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 ).await {
78 Ok((uri, commit_cid)) => {
79 info!(did = %did, uri = %uri, "Created profile for user");
80 (
81 StatusCode::OK,
82 Json(CreateProfileOutput {
83 uri,
84 cid: commit_cid.to_string(),
85 }),
86 )
87 .into_response()
88 }
89 Err(e) => {
90 error!("Failed to create profile for {}: {}", did, e);
91 (
92 StatusCode::INTERNAL_SERVER_ERROR,
93 Json(json!({"error": "InternalError", "message": e})),
94 )
95 .into_response()
96 }
97 }
98}
99
100pub async fn create_record_admin(
101 State(state): State<AppState>,
102 headers: axum::http::HeaderMap,
103 Json(input): Json<CreateRecordAdminInput>,
104) -> Response {
105 let auth_header = headers.get("Authorization");
106 if auth_header.is_none() {
107 return (
108 StatusCode::UNAUTHORIZED,
109 Json(json!({"error": "AuthenticationRequired"})),
110 )
111 .into_response();
112 }
113
114 let did = input.did.trim();
115 if did.is_empty() {
116 return (
117 StatusCode::BAD_REQUEST,
118 Json(json!({"error": "InvalidRequest", "message": "did is required"})),
119 )
120 .into_response();
121 }
122
123 let rkey = input.rkey.unwrap_or_else(|| {
124 chrono::Utc::now().format("%Y%m%d%H%M%S%f").to_string()
125 });
126
127 match create_record_internal(
128 &state,
129 did,
130 &input.collection,
131 &rkey,
132 &input.record,
133 ).await {
134 Ok((uri, commit_cid)) => {
135 info!(did = %did, uri = %uri, "Admin created record");
136 (
137 StatusCode::OK,
138 Json(CreateProfileOutput {
139 uri,
140 cid: commit_cid.to_string(),
141 }),
142 )
143 .into_response()
144 }
145 Err(e) => {
146 error!("Failed to create record for {}: {}", did, e);
147 (
148 StatusCode::INTERNAL_SERVER_ERROR,
149 Json(json!({"error": "InternalError", "message": e})),
150 )
151 .into_response()
152 }
153 }
154}