this repo has no description
1use crate::state::AppState; 2use axum::{ 3 Json, 4 extract::State, 5 http::StatusCode, 6 response::{IntoResponse, Response}, 7}; 8use serde::{Deserialize, Serialize}; 9use serde_json::{Value, json}; 10use tracing::error; 11 12#[derive(Deserialize)] 13#[serde(rename_all = "camelCase")] 14pub struct CreateReportInput { 15 pub reason_type: String, 16 pub reason: Option<String>, 17 pub subject: Value, 18} 19 20#[derive(Serialize)] 21#[serde(rename_all = "camelCase")] 22pub struct CreateReportOutput { 23 pub id: i64, 24 pub reason_type: String, 25 pub reason: Option<String>, 26 pub subject: Value, 27 pub reported_by: String, 28 pub created_at: String, 29} 30 31pub async fn create_report( 32 State(state): State<AppState>, 33 headers: axum::http::HeaderMap, 34 Json(input): Json<CreateReportInput>, 35) -> Response { 36 let token = match crate::auth::extract_bearer_token_from_header( 37 headers.get("Authorization").and_then(|h| h.to_str().ok()) 38 ) { 39 Some(t) => t, 40 None => { 41 return ( 42 StatusCode::UNAUTHORIZED, 43 Json(json!({"error": "AuthenticationRequired"})), 44 ) 45 .into_response(); 46 } 47 }; 48 49 let auth_result = crate::auth::validate_bearer_token(&state.db, &token).await; 50 let did = match auth_result { 51 Ok(user) => user.did, 52 Err(e) => { 53 return ( 54 StatusCode::UNAUTHORIZED, 55 Json(json!({"error": e})), 56 ) 57 .into_response(); 58 } 59 }; 60 61 let valid_reason_types = [ 62 "com.atproto.moderation.defs#reasonSpam", 63 "com.atproto.moderation.defs#reasonViolation", 64 "com.atproto.moderation.defs#reasonMisleading", 65 "com.atproto.moderation.defs#reasonSexual", 66 "com.atproto.moderation.defs#reasonRude", 67 "com.atproto.moderation.defs#reasonOther", 68 "com.atproto.moderation.defs#reasonAppeal", 69 ]; 70 71 if !valid_reason_types.contains(&input.reason_type.as_str()) { 72 return ( 73 StatusCode::BAD_REQUEST, 74 Json(json!({"error": "InvalidRequest", "message": "Invalid reasonType"})), 75 ) 76 .into_response(); 77 } 78 79 let created_at = chrono::Utc::now(); 80 let report_id = created_at.timestamp_millis(); 81 82 let subject_json = json!(input.subject); 83 let insert = sqlx::query!( 84 "INSERT INTO reports (id, reason_type, reason, subject_json, reported_by_did, created_at) VALUES ($1, $2, $3, $4, $5, $6)", 85 report_id, 86 input.reason_type, 87 input.reason, 88 subject_json, 89 did, 90 created_at 91 ) 92 .execute(&state.db) 93 .await; 94 95 if let Err(e) = insert { 96 error!("Failed to insert report: {:?}", e); 97 return ( 98 StatusCode::INTERNAL_SERVER_ERROR, 99 Json(json!({"error": "InternalError"})), 100 ) 101 .into_response(); 102 } 103 104 ( 105 StatusCode::OK, 106 Json(CreateReportOutput { 107 id: report_id, 108 reason_type: input.reason_type, 109 reason: input.reason, 110 subject: input.subject, 111 reported_by: did, 112 created_at: created_at.to_rfc3339(), 113 }), 114 ) 115 .into_response() 116}