tuitbot_server/routes/approval/
mod.rs1pub mod bulk_handlers;
10pub mod export;
11pub mod handlers;
12
13pub use bulk_handlers::{bulk_approve, bulk_reject};
14pub use export::{export_items, get_edit_history};
15pub use handlers::{approve_all, approve_item, edit_item, reject_item};
16
17use std::sync::Arc;
18
19use axum::extract::{Query, State};
20use axum::Json;
21use serde::Deserialize;
22use serde_json::{json, Value};
23use tuitbot_core::storage::approval_queue;
24
25use crate::account::AccountContext;
26use crate::error::ApiError;
27use crate::state::AppState;
28
29#[derive(Deserialize)]
31pub struct ApprovalQuery {
32 #[serde(default = "default_status")]
34 pub status: String,
35 #[serde(rename = "type")]
37 pub action_type: Option<String>,
38 pub reviewed_by: Option<String>,
40 pub since: Option<String>,
42 pub account_id: Option<String>,
45}
46
47fn default_status() -> String {
48 "pending".to_string()
49}
50
51pub async fn list_items(
57 State(state): State<Arc<AppState>>,
58 ctx: AccountContext,
59 Query(params): Query<ApprovalQuery>,
60) -> Result<Json<Value>, ApiError> {
61 let statuses: Vec<&str> = params.status.split(',').map(|s| s.trim()).collect();
62 let action_type = params.action_type.as_deref();
63 let reviewed_by = params.reviewed_by.as_deref();
64 let since = params.since.as_deref();
65
66 let effective_account_id = match params.account_id.as_deref() {
69 Some(qid) if qid == ctx.account_id => qid,
70 Some(_) => &ctx.account_id, None => &ctx.account_id,
72 };
73
74 let items = approval_queue::get_filtered_for(
75 &state.db,
76 effective_account_id,
77 &statuses,
78 action_type,
79 reviewed_by,
80 since,
81 )
82 .await?;
83 Ok(Json(json!(items)))
84}
85
86pub async fn stats(
88 State(state): State<Arc<AppState>>,
89 ctx: AccountContext,
90) -> Result<Json<Value>, ApiError> {
91 let stats = approval_queue::get_stats_for(&state.db, &ctx.account_id).await?;
92 Ok(Json(json!(stats)))
93}
94
95#[cfg(test)]
96mod tests;