this repo has no description
1use crate::api::repo::record::create_record_internal;
2use crate::auth::BearerAuthAdmin;
3use crate::state::AppState;
4use axum::{
5 Json,
6 extract::State,
7 http::StatusCode,
8 response::{IntoResponse, Response},
9};
10use serde::{Deserialize, Serialize};
11use serde_json::json;
12use tracing::{error, info};
13
14#[derive(Deserialize)]
15#[serde(rename_all = "camelCase")]
16pub struct CreateProfileInput {
17 pub did: String,
18 pub display_name: Option<String>,
19 pub description: Option<String>,
20}
21
22#[derive(Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct CreateRecordAdminInput {
25 pub did: String,
26 pub collection: String,
27 pub rkey: Option<String>,
28 pub record: serde_json::Value,
29}
30
31#[derive(Serialize)]
32#[serde(rename_all = "camelCase")]
33pub struct CreateProfileOutput {
34 pub uri: String,
35 pub cid: String,
36}
37
38pub async fn create_profile(
39 State(state): State<AppState>,
40 _auth: BearerAuthAdmin,
41 Json(input): Json<CreateProfileInput>,
42) -> Response {
43 let did = input.did.trim();
44 if did.is_empty() {
45 return (
46 StatusCode::BAD_REQUEST,
47 Json(json!({"error": "InvalidRequest", "message": "did is required"})),
48 )
49 .into_response();
50 }
51
52 let mut profile_record = json!({
53 "$type": "app.bsky.actor.profile"
54 });
55
56 if let Some(display_name) = &input.display_name {
57 profile_record["displayName"] = json!(display_name);
58 }
59 if let Some(description) = &input.description {
60 profile_record["description"] = json!(description);
61 }
62
63 match create_record_internal(
64 &state,
65 did,
66 "app.bsky.actor.profile",
67 "self",
68 &profile_record,
69 )
70 .await
71 {
72 Ok((uri, commit_cid)) => {
73 info!(did = %did, uri = %uri, "Created profile for user");
74 (
75 StatusCode::OK,
76 Json(CreateProfileOutput {
77 uri,
78 cid: commit_cid.to_string(),
79 }),
80 )
81 .into_response()
82 }
83 Err(e) => {
84 error!("Failed to create profile for {}: {}", did, e);
85 (
86 StatusCode::INTERNAL_SERVER_ERROR,
87 Json(json!({"error": "InternalError", "message": e})),
88 )
89 .into_response()
90 }
91 }
92}
93
94pub async fn create_record_admin(
95 State(state): State<AppState>,
96 _auth: BearerAuthAdmin,
97 Json(input): Json<CreateRecordAdminInput>,
98) -> Response {
99 let did = input.did.trim();
100 if did.is_empty() {
101 return (
102 StatusCode::BAD_REQUEST,
103 Json(json!({"error": "InvalidRequest", "message": "did is required"})),
104 )
105 .into_response();
106 }
107
108 let rkey = input
109 .rkey
110 .unwrap_or_else(|| chrono::Utc::now().format("%Y%m%d%H%M%S%f").to_string());
111
112 match create_record_internal(&state, did, &input.collection, &rkey, &input.record).await {
113 Ok((uri, commit_cid)) => {
114 info!(did = %did, uri = %uri, "Admin created record");
115 (
116 StatusCode::OK,
117 Json(CreateProfileOutput {
118 uri,
119 cid: commit_cid.to_string(),
120 }),
121 )
122 .into_response()
123 }
124 Err(e) => {
125 error!("Failed to create record for {}: {}", did, e);
126 (
127 StatusCode::INTERNAL_SERVER_ERROR,
128 Json(json!({"error": "InternalError", "message": e})),
129 )
130 .into_response()
131 }
132 }
133}