ockam_api 0.93.0

Ockam's request-response API
use crate::orchestrator::email_address::EmailAddress;
use crate::orchestrator::share::{
    AcceptInvitation, AcceptedInvitation, CreateInvitation, CreateServiceInvitation,
    InvitationList, InvitationListKind, InvitationWithAccess, ListInvitations, RoleInShare,
    SentInvitation, ShareScope,
};
use crate::orchestrator::{ControllerClient, HasSecureClient};
use miette::IntoDiagnostic;
use ockam::identity::Identifier;
use ockam_core::api::Request;
use ockam_core::async_trait;
use ockam_node::Context;

const API_SERVICE: &str = "users";

#[async_trait]
pub trait Invitations {
    #[allow(clippy::too_many_arguments)]
    async fn create_invitation(
        &self,
        ctx: &Context,
        expires_at: Option<String>,
        grant_role: RoleInShare,
        recipient_email: EmailAddress,
        remaining_uses: Option<usize>,
        scope: ShareScope,
        target_id: String,
    ) -> miette::Result<SentInvitation>;

    #[allow(clippy::too_many_arguments)]
    async fn create_service_invitation(
        &self,
        ctx: &Context,
        expires_at: Option<String>,
        project_id: String,
        recipient_email: EmailAddress,
        project_identity: Identifier,
        project_route: String,
        project_authority_identity: Identifier,
        project_authority_route: String,
        shared_node_identity: Identifier,
        shared_node_route: String,
        enrollment_ticket: String,
    ) -> miette::Result<SentInvitation>;

    async fn accept_invitation(
        &self,
        ctx: &Context,
        invitation_id: String,
    ) -> miette::Result<AcceptedInvitation>;

    async fn show_invitation(
        &self,
        ctx: &Context,
        invitation_id: String,
    ) -> miette::Result<InvitationWithAccess>;

    async fn list_invitations(
        &self,
        ctx: &Context,
        kind: InvitationListKind,
    ) -> miette::Result<InvitationList>;

    async fn ignore_invitation(&self, ctx: &Context, invitation_id: String) -> miette::Result<()>;
}

#[async_trait]
impl Invitations for ControllerClient {
    async fn create_invitation(
        &self,
        ctx: &Context,
        expires_at: Option<String>,
        grant_role: RoleInShare,
        recipient_email: EmailAddress,
        remaining_uses: Option<usize>,
        scope: ShareScope,
        target_id: String,
    ) -> miette::Result<SentInvitation> {
        trace!(%scope, target_id = %target_id, "creating invitation");
        let req_body = CreateInvitation {
            expires_at,
            grant_role,
            recipient_email,
            remaining_uses,
            scope,
            target_id,
        };
        let req = Request::post("/v0/invites").body(req_body);
        self.get_secure_client()
            .ask(ctx, API_SERVICE, req)
            .await
            .into_diagnostic()?
            .miette_success("create invitation")
    }

    async fn create_service_invitation(
        &self,
        ctx: &Context,
        expires_at: Option<String>,
        project_id: String,
        recipient_email: EmailAddress,
        project_identity: Identifier,
        project_route: String,
        project_authority_identity: Identifier,
        project_authority_route: String,
        shared_node_identity: Identifier,
        shared_node_route: String,
        enrollment_ticket: String,
    ) -> miette::Result<SentInvitation> {
        trace!(project_id = %project_id, "creating service invitation");
        let req_body = CreateServiceInvitation {
            expires_at,
            project_id,
            recipient_email,
            project_identity,
            project_route,
            project_authority_identity,
            project_authority_route,
            shared_node_identity,
            shared_node_route,
            enrollment_ticket,
        };
        let req = Request::post("/v0/invites/service").body(req_body);
        self.get_secure_client()
            .ask(ctx, API_SERVICE, req)
            .await
            .into_diagnostic()?
            .miette_success("create service invitation")
    }

    async fn accept_invitation(
        &self,
        ctx: &Context,
        invitation_id: String,
    ) -> miette::Result<AcceptedInvitation> {
        let req = Request::post("/v0/redeem_invite").body(AcceptInvitation { id: invitation_id });
        self.get_secure_client()
            .ask(ctx, API_SERVICE, req)
            .await
            .into_diagnostic()?
            .miette_success("redeem invitation")
    }

    async fn show_invitation(
        &self,
        ctx: &Context,
        invitation_id: String,
    ) -> miette::Result<InvitationWithAccess> {
        trace!(?invitation_id, "showing invitation");
        let req = Request::get(format!("/v0/invites/{invitation_id}"));
        self.get_secure_client()
            .ask(ctx, API_SERVICE, req)
            .await
            .into_diagnostic()?
            .miette_success("get invitation")
    }

    async fn list_invitations(
        &self,
        ctx: &Context,
        kind: InvitationListKind,
    ) -> miette::Result<InvitationList> {
        debug!(?kind, "Sending request to list shares");
        let req = Request::get("/v0/invites").body(ListInvitations { kind });
        self.get_secure_client()
            .ask(ctx, API_SERVICE, req)
            .await
            .into_diagnostic()?
            .miette_success("list invitations")
    }

    async fn ignore_invitation(&self, ctx: &Context, invitation_id: String) -> miette::Result<()> {
        debug!(?invitation_id, "sending request to ignore invitation");
        let req = Request::post(format!("/v0/invites/{invitation_id}/ignore"));
        self.get_secure_client()
            .tell(ctx, API_SERVICE, req)
            .await
            .into_diagnostic()?
            .miette_success("ignore invitation")
    }
}