koprogo_api/infrastructure/web/handlers/
building_handlers.rs1use crate::application::dto::{CreateBuildingDto, PageRequest, PageResponse, UpdateBuildingDto};
2use crate::infrastructure::audit::{AuditEventType, AuditLogEntry};
3use crate::infrastructure::web::{AppState, AuthenticatedUser};
4use actix_web::{delete, get, post, put, web, HttpResponse, Responder};
5use uuid::Uuid;
6use validator::Validate;
7
8#[post("/buildings")]
9pub async fn create_building(
10 state: web::Data<AppState>,
11 user: AuthenticatedUser, mut dto: web::Json<CreateBuildingDto>,
13) -> impl Responder {
14 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
34 .building_use_cases
35 .create_building(dto.into_inner())
36 .await
37 {
38 Ok(building) => {
39 AuditLogEntry::new(
41 AuditEventType::BuildingCreated,
42 Some(user.user_id),
43 Some(organization_id),
44 )
45 .with_resource("Building", Uuid::parse_str(&building.id).unwrap())
46 .log();
47
48 HttpResponse::Created().json(building)
49 }
50 Err(err) => {
51 AuditLogEntry::new(
53 AuditEventType::BuildingCreated,
54 Some(user.user_id),
55 Some(organization_id),
56 )
57 .with_error(err.clone())
58 .log();
59
60 HttpResponse::BadRequest().json(serde_json::json!({
61 "error": err
62 }))
63 }
64 }
65}
66
67#[get("/buildings")]
68pub async fn list_buildings(
69 state: web::Data<AppState>,
70 user: AuthenticatedUser,
71 page_request: web::Query<PageRequest>,
72) -> impl Responder {
73 let organization_id = user.organization_id;
75
76 match state
77 .building_use_cases
78 .list_buildings_paginated(&page_request, organization_id)
79 .await
80 {
81 Ok((buildings, total)) => {
82 let response =
83 PageResponse::new(buildings, page_request.page, page_request.per_page, total);
84 HttpResponse::Ok().json(response)
85 }
86 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
87 "error": err
88 })),
89 }
90}
91
92#[get("/buildings/{id}")]
93pub async fn get_building(state: web::Data<AppState>, id: web::Path<Uuid>) -> impl Responder {
94 match state.building_use_cases.get_building(*id).await {
95 Ok(Some(building)) => HttpResponse::Ok().json(building),
96 Ok(None) => HttpResponse::NotFound().json(serde_json::json!({
97 "error": "Building not found"
98 })),
99 Err(err) => HttpResponse::InternalServerError().json(serde_json::json!({
100 "error": err
101 })),
102 }
103}
104
105#[put("/buildings/{id}")]
106pub async fn update_building(
107 state: web::Data<AppState>,
108 user: AuthenticatedUser,
109 id: web::Path<Uuid>,
110 dto: web::Json<UpdateBuildingDto>,
111) -> impl Responder {
112 if let Err(errors) = dto.validate() {
113 return HttpResponse::BadRequest().json(serde_json::json!({
114 "error": "Validation failed",
115 "details": errors.to_string()
116 }));
117 }
118
119 match state
120 .building_use_cases
121 .update_building(*id, dto.into_inner())
122 .await
123 {
124 Ok(building) => {
125 AuditLogEntry::new(
127 AuditEventType::BuildingUpdated,
128 Some(user.user_id),
129 user.organization_id,
130 )
131 .with_resource("Building", *id)
132 .log();
133
134 HttpResponse::Ok().json(building)
135 }
136 Err(err) => {
137 AuditLogEntry::new(
139 AuditEventType::BuildingUpdated,
140 Some(user.user_id),
141 user.organization_id,
142 )
143 .with_resource("Building", *id)
144 .with_error(err.clone())
145 .log();
146
147 HttpResponse::BadRequest().json(serde_json::json!({
148 "error": err
149 }))
150 }
151 }
152}
153
154#[delete("/buildings/{id}")]
155pub async fn delete_building(
156 state: web::Data<AppState>,
157 user: AuthenticatedUser,
158 id: web::Path<Uuid>,
159) -> impl Responder {
160 match state.building_use_cases.delete_building(*id).await {
161 Ok(true) => {
162 AuditLogEntry::new(
164 AuditEventType::BuildingDeleted,
165 Some(user.user_id),
166 user.organization_id,
167 )
168 .with_resource("Building", *id)
169 .log();
170
171 HttpResponse::NoContent().finish()
172 }
173 Ok(false) => HttpResponse::NotFound().json(serde_json::json!({
174 "error": "Building not found"
175 })),
176 Err(err) => {
177 AuditLogEntry::new(
179 AuditEventType::BuildingDeleted,
180 Some(user.user_id),
181 user.organization_id,
182 )
183 .with_resource("Building", *id)
184 .with_error(err.clone())
185 .log();
186
187 HttpResponse::InternalServerError().json(serde_json::json!({
188 "error": err
189 }))
190 }
191 }
192}