//! Invite code generation for creators. use axum::{ extract::State, response::IntoResponse, }; use crate::{ auth::AuthUser, constants, db, error::{AppError, Result}, templates::AlertTemplate, AppState, }; /// Generate a new invite code for the authenticated creator. #[tracing::instrument(skip_all, name = "api::create_invite")] pub(in crate::routes::api) async fn create_invite( State(state): State, AuthUser(user): AuthUser, ) -> Result { user.check_not_sandbox()?; if !constants::INVITES_ENABLED { return Ok(AlertTemplate::new("error", "Invites are currently disabled.").into_response()); } // Only creators can generate invites let db_user = db::users::get_user_by_id(&state.db, user.id) .await? .ok_or(AppError::NotFound)?; if !db_user.can_create_projects { return Ok(AlertTemplate::new("error", "You need creator access to generate invite codes.").into_response()); } // Check limit let active_count = db::invites::count_active_invites(&state.db, user.id).await?; if active_count >= constants::INVITE_LIMIT_PER_CREATOR { return Ok(AlertTemplate::new( "error", &format!("You have reached the limit of {} active invite codes.", constants::INVITE_LIMIT_PER_CREATOR), ).into_response()); } // Generate and store let code = db::invites::generate_invite_code(); db::invites::create_invite_code(&state.db, user.id, &code).await?; let formatted = db::invites::format_invite_code(&code); let link = format!("makenot.work/join?invite={}", formatted); Ok(AlertTemplate::new("success", &format!("Invite code: {} -- {}", formatted, link)).into_response()) }