koprogo_api/infrastructure/web/handlers/
stats_handlers.rs

1use crate::infrastructure::web::{AppState, AuthenticatedUser};
2use actix_web::{get, web, HttpResponse, Responder};
3
4/// GET /api/v1/stats/dashboard
5/// Get dashboard statistics (SuperAdmin only)
6#[get("/stats/dashboard")]
7pub async fn get_dashboard_stats(
8    state: web::Data<AppState>,
9    user: AuthenticatedUser,
10) -> impl Responder {
11    if user.role != "superadmin" {
12        return HttpResponse::Forbidden().json(serde_json::json!({
13            "error": "Only SuperAdmin can access dashboard statistics"
14        }));
15    }
16
17    match state.stats_use_cases.get_admin_dashboard_stats().await {
18        Ok(stats) => HttpResponse::Ok().json(stats),
19        Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
20            "error": format!("Failed to fetch dashboard statistics: {}", e)
21        })),
22    }
23}
24
25/// GET /api/v1/stats/owner
26/// Get owner dashboard statistics (Owner role)
27#[get("/stats/owner")]
28pub async fn get_owner_stats(
29    state: web::Data<AppState>,
30    user: AuthenticatedUser,
31) -> impl Responder {
32    if user.role != "owner" && user.role != "superadmin" {
33        return HttpResponse::Forbidden().json(serde_json::json!({
34            "error": "Only Owner can access these statistics"
35        }));
36    }
37
38    match state
39        .stats_use_cases
40        .get_owner_stats_by_user_id(user.user_id)
41        .await
42    {
43        Ok(stats) => HttpResponse::Ok().json(stats),
44        Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
45            "error": format!("Failed to fetch owner dashboard statistics: {}", e)
46        })),
47    }
48}
49
50/// GET /api/v1/stats/syndic
51/// Get Syndic dashboard statistics (Syndic and Accountant roles)
52#[get("/stats/syndic")]
53pub async fn get_syndic_stats(
54    state: web::Data<AppState>,
55    user: AuthenticatedUser,
56) -> impl Responder {
57    if user.role != "syndic" && user.role != "accountant" && user.role != "superadmin" {
58        return HttpResponse::Forbidden().json(serde_json::json!({
59            "error": "Only Syndic and Accountant can access these statistics"
60        }));
61    }
62
63    let Some(org_id) = user.organization_id else {
64        return HttpResponse::BadRequest().json(serde_json::json!({
65            "error": "User has no organization"
66        }));
67    };
68
69    match state.stats_use_cases.get_syndic_stats(org_id).await {
70        Ok(stats) => HttpResponse::Ok().json(stats),
71        Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
72            "error": format!("Failed to fetch syndic dashboard statistics: {}", e)
73        })),
74    }
75}
76
77/// GET /api/v1/stats/syndic/urgent-tasks
78/// Get urgent tasks for Syndic dashboard (Syndic and Accountant roles)
79#[get("/stats/syndic/urgent-tasks")]
80pub async fn get_syndic_urgent_tasks(
81    state: web::Data<AppState>,
82    user: AuthenticatedUser,
83) -> impl Responder {
84    if user.role != "syndic" && user.role != "accountant" && user.role != "superadmin" {
85        return HttpResponse::Forbidden().json(serde_json::json!({
86            "error": "Only Syndic and Accountant can access these tasks"
87        }));
88    }
89
90    let Some(org_id) = user.organization_id else {
91        return HttpResponse::BadRequest().json(serde_json::json!({
92            "error": "User has no organization"
93        }));
94    };
95
96    match state.stats_use_cases.get_syndic_urgent_tasks(org_id).await {
97        Ok(tasks) => HttpResponse::Ok().json(tasks),
98        Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
99            "error": format!("Failed to fetch urgent tasks: {}", e)
100        })),
101    }
102}
103
104/// GET /api/v1/stats/seed-data
105/// Get seed data statistics (SuperAdmin only)
106#[get("/stats/seed-data")]
107pub async fn get_seed_data_stats(
108    state: web::Data<AppState>,
109    user: AuthenticatedUser,
110) -> impl Responder {
111    if user.role != "superadmin" {
112        return HttpResponse::Forbidden().json(serde_json::json!({
113            "error": "Only SuperAdmin can access seed data statistics"
114        }));
115    }
116
117    match state.stats_use_cases.get_seed_data_stats().await {
118        Ok(stats) => HttpResponse::Ok().json(stats),
119        Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({
120            "error": format!("Failed to fetch seed data statistics: {}", e)
121        })),
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    #[test]
128    fn test_role_check_superadmin_passes() {
129        let allowed_roles = ["superadmin"];
130        assert!(allowed_roles.contains(&"superadmin"));
131        assert!(!allowed_roles.contains(&"owner"));
132    }
133
134    #[test]
135    fn test_role_check_syndic_and_accountant() {
136        let allowed_roles = ["syndic", "accountant", "superadmin"];
137        assert!(allowed_roles.contains(&"syndic"));
138        assert!(allowed_roles.contains(&"accountant"));
139        assert!(!allowed_roles.contains(&"owner"));
140    }
141
142    #[test]
143    fn test_role_check_owner() {
144        let allowed_roles = ["owner", "superadmin"];
145        assert!(allowed_roles.contains(&"owner"));
146        assert!(!allowed_roles.contains(&"syndic"));
147    }
148}