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