Skip to main content

max / makenotwork

1.8 KB · 60 lines History Blame Raw
1 //! Invite code generation for creators.
2
3 use axum::{extract::State, response::IntoResponse};
4
5 use sqlx::PgPool;
6
7 use crate::{
8 auth::AuthUser,
9 constants, db,
10 error::{AppError, Result},
11 templates::AlertTemplate,
12 };
13
14 /// Generate a new invite code for the authenticated creator.
15 #[tracing::instrument(skip_all, name = "api::create_invite")]
16 pub(in crate::routes::api) async fn create_invite(
17 State(db): State<PgPool>,
18 AuthUser(user): AuthUser,
19 ) -> Result<impl IntoResponse> {
20 user.check_not_sandbox()?;
21 if !constants::INVITES_ENABLED {
22 return Ok(AlertTemplate::new("error", "Invites are currently disabled.").into_response());
23 }
24
25 // Only creators can generate invites
26 let db_user = db::users::get_user_by_id(&db, user.id)
27 .await?
28 .ok_or(AppError::NotFound)?;
29
30 if !db_user.can_create_projects {
31 return Ok(AlertTemplate::new(
32 "error",
33 "You need creator access to generate invite codes.",
34 )
35 .into_response());
36 }
37
38 // Check limit
39 let active_count = db::invites::count_active_invites(&db, user.id).await?;
40 if active_count >= constants::INVITE_LIMIT_PER_CREATOR {
41 return Ok(AlertTemplate::new(
42 "error",
43 &format!(
44 "You have reached the limit of {} active invite codes.",
45 constants::INVITE_LIMIT_PER_CREATOR
46 ),
47 )
48 .into_response());
49 }
50
51 // Generate and store
52 let code = db::invites::generate_invite_code();
53 db::invites::create_invite_code(&db, user.id, &code).await?;
54
55 let formatted = db::invites::format_invite_code(&code);
56 let link = format!("makenot.work/join?invite={formatted}");
57
58 Ok(AlertTemplate::new("success", &format!("Invite code: {formatted} {link}")).into_response())
59 }
60