cloudillo_admin/
invite.rs1use axum::{extract::State, http::StatusCode, Json};
4use serde::{Deserialize, Serialize};
5use serde_with::skip_serializing_none;
6
7use crate::prelude::*;
8use cloudillo_core::extract::Auth;
9use cloudillo_core::CreateActionFn;
10use cloudillo_ref::service::{create_ref_internal, CreateRefInternalParams};
11use cloudillo_types::action_types::CreateAction;
12use cloudillo_types::types::{ApiResponse, Timestamp};
13
14#[derive(Debug, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct InviteCommunityRequest {
18 pub target_id_tag: String,
20 pub expires_in_days: Option<u32>,
22 pub message: Option<String>,
24}
25
26#[skip_serializing_none]
28#[derive(Debug, Serialize)]
29#[serde(rename_all = "camelCase")]
30pub struct InviteCommunityResponse {
31 pub ref_id: String,
32 pub invite_url: String,
33 pub target_id_tag: String,
34 pub expires_at: Option<i64>,
35}
36
37pub async fn post_invite_community(
39 State(app): State<App>,
40 Auth(auth): Auth,
41 Json(req): Json<InviteCommunityRequest>,
42) -> ClResult<(StatusCode, Json<ApiResponse<InviteCommunityResponse>>)> {
43 let admin_tn_id = auth.tn_id;
44 let admin_id_tag = &auth.id_tag;
45 let expires_in_days = req.expires_in_days.unwrap_or(30);
46
47 info!(
48 admin = %admin_id_tag,
49 target = %req.target_id_tag,
50 "Creating community invite"
51 );
52
53 let admin_tenant = app.meta_adapter.read_tenant(admin_tn_id).await?;
55 let node_id_tag = admin_tenant.id_tag.to_string();
56
57 let expires_at = Some(Timestamp::now().add_seconds(expires_in_days as i64 * 86400));
59
60 let (ref_id, invite_url) = create_ref_internal(
62 &app,
63 admin_tn_id,
64 CreateRefInternalParams {
65 id_tag: &node_id_tag,
66 typ: "profile.invite",
67 description: Some("Community profile invite"),
68 expires_at,
69 path_prefix: "/profile/new?invite=",
70 resource_id: None,
71 count: None, },
73 )
74 .await?;
75
76 let prinvt_content = serde_json::json!({
78 "refId": ref_id,
79 "nodeName": admin_tenant.name.as_ref(),
80 "message": req.message,
81 });
82
83 let create_action_fn = app.ext::<CreateActionFn>()?;
84 if let Err(e) = create_action_fn(
85 &app,
86 admin_tn_id,
87 admin_id_tag,
88 CreateAction {
89 typ: "PRINVT".into(),
90 audience_tag: Some(req.target_id_tag.clone().into()),
91 content: Some(prinvt_content),
92 expires_at,
93 ..Default::default()
94 },
95 )
96 .await
97 {
98 warn!(
99 error = %e,
100 target = %req.target_id_tag,
101 "Failed to send PRINVT action, invite ref was still created"
102 );
103 }
104
105 let response = InviteCommunityResponse {
106 ref_id,
107 invite_url,
108 target_id_tag: req.target_id_tag,
109 expires_at: expires_at.map(|ts| ts.0),
110 };
111
112 Ok((StatusCode::CREATED, Json(ApiResponse::new(response))))
113}
114
115