|
| 1 | +//! Admin API handlers for maintenance operations |
| 2 | +
|
| 3 | +use actix_web::{web, HttpResponse, Result as ActixResult}; |
| 4 | +use serde::Serialize; |
| 5 | +use std::sync::Arc; |
| 6 | +use tracing::{error, info}; |
| 7 | + |
| 8 | +use crate::server::app_state::AppState; |
| 9 | +use crate::storage::CleanupStats; |
| 10 | + |
| 11 | +/// Default retention period for soft-deleted items (in days) |
| 12 | +const DEFAULT_RETENTION_DAYS: i32 = 30; |
| 13 | + |
| 14 | +/// Response for cleanup operation |
| 15 | +#[derive(Debug, Serialize)] |
| 16 | +pub struct CleanupResponse { |
| 17 | + pub success: bool, |
| 18 | + pub message: String, |
| 19 | + pub retention_days: i32, |
| 20 | + pub stats: CleanupStats, |
| 21 | +} |
| 22 | + |
| 23 | +/// Run cleanup job to permanently delete soft-deleted records older than retention period |
| 24 | +/// |
| 25 | +/// This endpoint permanently deletes: |
| 26 | +/// - Files (including S3 objects) |
| 27 | +/// - Watchers |
| 28 | +/// - Watcher groups |
| 29 | +/// |
| 30 | +/// that have been soft-deleted for longer than the retention period (default 30 days). |
| 31 | +/// |
| 32 | +/// # Request |
| 33 | +/// POST /admin/cleanup |
| 34 | +/// |
| 35 | +/// # Response |
| 36 | +/// ```json |
| 37 | +/// { |
| 38 | +/// "success": true, |
| 39 | +/// "message": "Cleanup completed successfully", |
| 40 | +/// "retention_days": 30, |
| 41 | +/// "stats": { |
| 42 | +/// "files_deleted": 10, |
| 43 | +/// "watchers_deleted": 5, |
| 44 | +/// "groups_deleted": 2, |
| 45 | +/// "s3_objects_deleted": 10, |
| 46 | +/// "errors": [] |
| 47 | +/// } |
| 48 | +/// } |
| 49 | +/// ``` |
| 50 | +pub async fn run_cleanup(app_state: web::Data<Arc<AppState>>) -> ActixResult<HttpResponse> { |
| 51 | + info!("Admin cleanup job started"); |
| 52 | + |
| 53 | + match app_state |
| 54 | + .storage |
| 55 | + .cleanup_soft_deleted(DEFAULT_RETENTION_DAYS) |
| 56 | + .await |
| 57 | + { |
| 58 | + Ok(stats) => { |
| 59 | + info!( |
| 60 | + "Cleanup completed: {} files, {} watchers, {} groups deleted", |
| 61 | + stats.files_deleted, stats.watchers_deleted, stats.groups_deleted |
| 62 | + ); |
| 63 | + |
| 64 | + Ok(HttpResponse::Ok().json(CleanupResponse { |
| 65 | + success: true, |
| 66 | + message: "Cleanup completed successfully".to_string(), |
| 67 | + retention_days: DEFAULT_RETENTION_DAYS, |
| 68 | + stats, |
| 69 | + })) |
| 70 | + } |
| 71 | + Err(e) => { |
| 72 | + error!("Cleanup failed: {}", e); |
| 73 | + |
| 74 | + Ok(HttpResponse::InternalServerError().json(CleanupResponse { |
| 75 | + success: false, |
| 76 | + message: format!("Cleanup failed: {}", e), |
| 77 | + retention_days: DEFAULT_RETENTION_DAYS, |
| 78 | + stats: CleanupStats::default(), |
| 79 | + })) |
| 80 | + } |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +/// Get cleanup status and statistics (read-only, no actual cleanup) |
| 85 | +/// |
| 86 | +/// # Request |
| 87 | +/// GET /admin/cleanup/status |
| 88 | +/// |
| 89 | +/// # Response |
| 90 | +/// Returns information about pending cleanup items |
| 91 | +pub async fn cleanup_status(app_state: web::Data<Arc<AppState>>) -> ActixResult<HttpResponse> { |
| 92 | + // For now, just return the retention configuration |
| 93 | + // In the future, could query counts of items pending cleanup |
| 94 | + let _ = app_state; // Will be used when we add pending count queries |
| 95 | + |
| 96 | + Ok(HttpResponse::Ok().json(serde_json::json!({ |
| 97 | + "retention_days": DEFAULT_RETENTION_DAYS, |
| 98 | + "description": "Items soft-deleted more than 30 days ago will be permanently deleted on cleanup", |
| 99 | + "trigger_endpoint": "POST /admin/cleanup" |
| 100 | + }))) |
| 101 | +} |
0 commit comments