slave 0.13.1

CLI for slave, a Laravel-inspired Rust framework for MCP-first apps: scaffold an MCP backend with auth, roles, teams and SurrealDB migrations, add server-rendered web apps, and route them by domain or path
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::modules::team::services::team_service::Member;
use crate::modules::team::{Access, Invitation, Team};

/// Arguments of `team_create`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct CreateTeamRequest {
    pub name: String,
    /// Lowercase letters, digits and `-`, e.g. `acme-design`.
    pub slug: String,
}

/// Arguments of `team_get` and `member_list`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct TeamRequest {
    pub team_id: i64,
}

/// Arguments of `invite_create`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct InviteRequest {
    pub team_id: i64,
    /// Who to invite; they join by accepting after signing in (or signing
    /// up) with this email.
    pub email: String,
    /// `owner`, `admin` or `staff`.
    pub role: String,
    /// For `staff`: the modules they may use (see `team_modules`).
    #[serde(default)]
    pub modules: Vec<String>,
}

/// Arguments of `invite_revoke`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct RevokeInviteRequest {
    pub team_id: i64,
    pub invitation_id: i64,
}

/// Arguments of `invite_accept` and `invite_decline`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct InvitationRequest {
    pub invitation_id: i64,
}

/// Arguments of `member_update`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct UpdateMemberRequest {
    pub team_id: i64,
    pub user_id: i64,
    /// `owner`, `admin` or `staff`.
    pub role: String,
    /// For `staff`: the modules they may use.
    #[serde(default)]
    pub modules: Vec<String>,
}

/// Arguments of `customer_join`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct CustomerJoinRequest {
    /// The store's team slug, e.g. the `{toko}` of `{toko}.example.com`.
    pub slug: String,
}

/// The store a customer joined.
#[derive(Debug, Serialize, JsonSchema)]
pub struct StoreResponse {
    pub id: i64,
    pub name: String,
    pub slug: String,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct CustomerResponse {
    pub user_id: i64,
    pub name: String,
    pub email: Option<String>,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct CustomerListResponse {
    pub customers: Vec<CustomerResponse>,
}

/// Arguments of `member_remove`.
#[derive(Debug, Deserialize, JsonSchema)]
pub struct RemoveMemberRequest {
    pub team_id: i64,
    pub user_id: i64,
}

/// A team and what the caller may do there.
#[derive(Debug, Serialize, JsonSchema)]
pub struct TeamResponse {
    pub id: i64,
    pub name: String,
    pub slug: String,
    /// The caller's role: `owner`, `admin`, `staff` or `super_admin`.
    pub role: String,
    /// Modules the caller may use.
    pub modules: Vec<String>,
    /// Whether the caller may add, change and remove members.
    pub manages_members: bool,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct TeamListResponse {
    pub teams: Vec<TeamResponse>,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct MemberResponse {
    pub user_id: i64,
    pub name: String,
    pub email: Option<String>,
    pub role: String,
    /// For `staff`: their modules; empty for owners and admins (all modules).
    pub modules: Vec<String>,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct MemberListResponse {
    pub members: Vec<MemberResponse>,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct InvitationResponse {
    pub id: i64,
    pub team_id: i64,
    /// Set in `invite_mine`.
    pub team_name: Option<String>,
    pub email: String,
    pub role: String,
    pub modules: Vec<String>,
}

#[derive(Debug, Serialize, JsonSchema)]
pub struct InvitationListResponse {
    pub invitations: Vec<InvitationResponse>,
}

impl InvitationResponse {
    pub fn new(invitation: Invitation, team_name: Option<String>) -> Self {
        Self {
            id: invitation.id,
            team_id: invitation.team_id,
            team_name,
            modules: crate::modules::team::services::access::split_modules(&invitation.modules),
            email: invitation.email,
            role: invitation.role,
        }
    }
}

impl From<Vec<Invitation>> for InvitationListResponse {
    fn from(invitations: Vec<Invitation>) -> Self {
        Self {
            invitations: invitations
                .into_iter()
                .map(|invitation| InvitationResponse::new(invitation, None))
                .collect(),
        }
    }
}

/// The modules staff can be given.
#[derive(Debug, Serialize, JsonSchema)]
pub struct ModulesResponse {
    pub roles: Vec<String>,
    pub modules: Vec<String>,
}

impl From<(Team, Access)> for TeamResponse {
    fn from((team, access): (Team, Access)) -> Self {
        Self {
            id: team.id,
            name: team.name,
            slug: team.slug,
            manages_members: access.manages_members(),
            role: access.role,
            modules: access.modules,
        }
    }
}

impl From<Vec<Member>> for MemberListResponse {
    fn from(members: Vec<Member>) -> Self {
        Self {
            members: members
                .into_iter()
                .map(|member| MemberResponse {
                    user_id: member.membership.user_id,
                    name: member.name,
                    email: member.email,
                    modules: crate::modules::team::services::access::split_modules(
                        &member.membership.modules,
                    ),
                    role: member.membership.role,
                })
                .collect(),
        }
    }
}