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