openauth-plugins 0.0.4

Official OpenAuth plugin modules.
Documentation
use ::http::{Method, StatusCode};
use openauth_core::api::{create_auth_endpoint, AsyncAuthEndpoint, AuthEndpointOptions};

use crate::organization::hooks::{AfterRemoveMember, BeforeRemoveMember};
use crate::organization::http;
use crate::organization::options::OrganizationOptions;
use crate::organization::store::OrganizationStore;

use super::validation::{is_last_owner, require_session};

pub(super) fn leave(options: OrganizationOptions) -> AsyncAuthEndpoint {
    create_auth_endpoint(
        "/organization/leave",
        Method::POST,
        AuthEndpointOptions::new().operation_id("organizationLeave"),
        move |context, request| {
            let options = options.clone();
            Box::pin(async move {
                let adapter = http::adapter(context)?;
                let store = OrganizationStore::new(adapter.as_ref());
                let session = require_session(context, &request, &store).await?;
                let Some(organization_id) = session.active_organization_id.clone() else {
                    return http::organization_error(
                        StatusCode::BAD_REQUEST,
                        "NO_ACTIVE_ORGANIZATION",
                    );
                };
                let Some(member) = store
                    .member_by_org_user(&organization_id, &session.user.id)
                    .await?
                else {
                    return http::organization_error(StatusCode::BAD_REQUEST, "MEMBER_NOT_FOUND");
                };
                if is_last_owner(&store, &organization_id, &member, &options).await? {
                    return http::organization_error(
                        StatusCode::BAD_REQUEST,
                        "YOU_CANNOT_LEAVE_THE_ORGANIZATION_AS_THE_ONLY_OWNER",
                    );
                }
                let Some(organization) = store.organization_by_id(&organization_id).await? else {
                    return http::organization_error(
                        StatusCode::BAD_REQUEST,
                        "ORGANIZATION_NOT_FOUND",
                    );
                };
                if let Some(hook) = &options.hooks.before_remove_member {
                    hook(&BeforeRemoveMember {
                        organization: organization.clone(),
                        member: member.clone(),
                        user: session.user.clone(),
                    })?;
                }
                if options.teams.enabled {
                    store
                        .delete_team_members_for_user(&organization_id, &session.user.id)
                        .await?;
                }
                store.delete_member(&member.id).await?;
                if let Some(hook) = &options.hooks.after_remove_member {
                    hook(&AfterRemoveMember {
                        organization,
                        member: member.clone(),
                        user: session.user.clone(),
                    })?;
                }
                store
                    .set_active_organization(&session.session.token, None)
                    .await?;
                if options.teams.enabled {
                    store.set_active_team(&session.session.token, None).await?;
                }
                http::json_with_cookies(
                    StatusCode::OK,
                    &serde_json::json!({ "member": member }),
                    http::refreshed_session_cookies(context, &session.session, &session.user)?,
                )
            })
        },
    )
}