koprogo_api/infrastructure/web/handlers/
owner_handlers.rs

1use crate::application::dto::{CreateOwnerDto, PageRequest, PageResponse};
2use crate::infrastructure::audit::{AuditEventType, AuditLogEntry};
3use crate::infrastructure::web::{AppState, AuthenticatedUser};
4use actix_web::{get, post, web, HttpResponse, Responder};
5use uuid::Uuid;
6use validator::Validate;
7
8#[post("/owners")]
9pub async fn create_owner(
10    state: web::Data<AppState>,
11    user: AuthenticatedUser, // JWT-extracted user info (SECURE!)
12    mut dto: web::Json<CreateOwnerDto>,
13) -> impl Responder {
14    // Override the organization_id from DTO with the one from JWT token
15    // This prevents users from creating owners in other organizations
16    let organization_id = match user.require_organization() {
17        Ok(org_id) => org_id,
18        Err(e) => {
19            return HttpResponse::Unauthorized().json(serde_json::json!({
20                "error": e.to_string()
21            }))
22        }
23    };
24    dto.organization_id = organization_id.to_string();
25
26    if let Err(errors) = dto.validate() {
27        return HttpResponse::BadRequest().json(serde_json::json!({
28            "error": "Validation failed",
29            "details": errors.to_string()
30        }));
31    }
32
33    match state.owner_use_cases.create_owner(dto.into_inner()).await {
34        Ok(owner) => {
35            // Audit log: successful owner creation
36            AuditLogEntry::new(
37                AuditEventType::OwnerCreated,
38                Some(user.user_id),
39                Some(organization_id),
40            )
41            .with_resource("Owner", Uuid::parse_str(&owner.id).unwrap())
42            .log();
43
44            HttpResponse::Created().json(owner)
45        }
46        Err(err) => {
47            // Audit log: failed owner creation
48            AuditLogEntry::new(
49                AuditEventType::OwnerCreated,
50                Some(user.user_id),
51                Some(organization_id),
52            )
53            .with_error(err.clone())
54            .log();
55
56            HttpResponse::BadRequest().json(serde_json::json!({
57                "error": err
58            }))
59        }
60    }
61}
62
63#[get("/owners")]
64pub async fn list_owners(
65    state: web::Data<AppState>,
66    user: AuthenticatedUser,
67    page_request: web::Query<PageRequest>,
68) -> impl Responder {
69    let organization_id = user.organization_id;
70
71    match state
72        .owner_use_cases
73        .list_owners_paginated(&page_request, organization_id)
74        .await
75    {
76        Ok((owners, total)) => {
77            let response =
78                PageResponse::new(owners, page_request.page, page_request.per_page, total);
79            HttpResponse::Ok().json(response)
80        }
81        Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
82            "error": err
83        })),
84    }
85}
86
87#[get("/owners/{id}")]
88pub async fn get_owner(state: web::Data<AppState>, id: web::Path<Uuid>) -> impl Responder {
89    match state.owner_use_cases.get_owner(*id).await {
90        Ok(Some(owner)) => HttpResponse::Ok().json(owner),
91        Ok(None) => HttpResponse::NotFound().json(serde_json::json!({
92            "error": "Owner not found"
93        })),
94        Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
95            "error": err
96        })),
97    }
98}