omni_orchestrator/schemas/v1/api/cost/
budgets.rs

1use super::super::super::super::auth::User;
2use super::super::super::db::queries as db;
3use super::types::{CreateCostBudgetRequest, UpdateCostBudgetRequest};
4use rocket::http::Status;
5use rocket::serde::json::{json, Json, Value};
6use rocket::{delete, get, post, put, State};
7use std::sync::Arc;
8use crate::DatabaseManager;
9
10use libomni::types::db::v1 as types;
11use types::cost::CostBudget;
12
13/// List all cost budgets with pagination support.
14#[get("/platform/<platform_id>/cost_budgets?<page>&<per_page>")]
15pub async fn list_cost_budgets(
16    platform_id: i64,
17    page: Option<i64>,
18    per_page: Option<i64>,
19    db_manager: &State<Arc<DatabaseManager>>,
20) -> Result<Json<Value>, (Status, Json<Value>)> {
21    // Get platform information
22    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
23        Ok(platform) => platform,
24        Err(_) => {
25            return Err((
26                Status::NotFound,
27                Json(json!({
28                    "error": "Platform not found",
29                    "message": format!("Platform with ID {} does not exist", platform_id)
30                }))
31            ));
32        }
33    };
34
35    // Get platform-specific database pool
36    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
37        Ok(pool) => pool,
38        Err(_) => {
39            return Err((
40                Status::InternalServerError,
41                Json(json!({
42                    "error": "Database error",
43                    "message": "Failed to connect to platform database"
44                }))
45            ));
46        }
47    };
48
49    match (page, per_page) {
50        (Some(p), Some(pp)) => {
51            let cost_budgets = match db::cost::list_cost_budgets(&pool, p, pp).await {
52                Ok(budgets) => budgets,
53                Err(_) => {
54                    return Err((
55                        Status::InternalServerError,
56                        Json(json!({
57                            "error": "Database error",
58                            "message": "Failed to retrieve cost budgets"
59                        }))
60                    ));
61                }
62            };
63            
64            let total_count = match db::cost::count_cost_budgets(&pool).await {
65                Ok(count) => count,
66                Err(_) => {
67                    return Err((
68                        Status::InternalServerError,
69                        Json(json!({
70                            "error": "Database error",
71                            "message": "Failed to count cost budgets"
72                        }))
73                    ));
74                }
75            };
76            
77            let total_pages = (total_count as f64 / pp as f64).ceil() as i64;
78
79            let response = json!({
80                "cost_budgets": cost_budgets,
81                "pagination": {
82                    "page": p,
83                    "per_page": pp,
84                    "total_count": total_count,
85                    "total_pages": total_pages
86                }
87            });
88
89            Ok(Json(response))
90        }
91        _ => Err((
92            Status::BadRequest,
93            Json(json!({
94                "error": "Missing pagination parameters",
95                "message": "Please provide both 'page' and 'per_page' parameters"
96            }))
97        ))
98    }
99}
100
101/// Get a specific cost budget by ID.
102#[get("/platform/<platform_id>/cost_budgets/<id>")]
103pub async fn get_cost_budget(
104    platform_id: i64,
105    id: i64,
106    db_manager: &State<Arc<DatabaseManager>>,
107) -> Result<Json<CostBudget>, (Status, Json<Value>)> {
108    // Get platform information
109    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
110        Ok(platform) => platform,
111        Err(_) => {
112            return Err((
113                Status::NotFound,
114                Json(json!({
115                    "error": "Platform not found",
116                    "message": format!("Platform with ID {} does not exist", platform_id)
117                }))
118            ));
119        }
120    };
121
122    // Get platform-specific database pool
123    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
124        Ok(pool) => pool,
125        Err(_) => {
126            return Err((
127                Status::InternalServerError,
128                Json(json!({
129                    "error": "Database error",
130                    "message": "Failed to connect to platform database"
131                }))
132            ));
133        }
134    };
135
136    match db::cost::get_cost_budget_by_id(&pool, id).await {
137        Ok(budget) => Ok(Json(budget)),
138        Err(_) => Err((
139            Status::NotFound,
140            Json(json!({
141                "error": "Cost budget not found",
142                "message": format!("Cost budget with ID {} could not be found", id)
143            }))
144        )),
145    }
146}
147
148/// Create a new cost budget.
149#[post("/platform/<platform_id>/cost_budgets", format = "json", data = "<request>")]
150pub async fn create_cost_budget(
151    platform_id: i64,
152    request: Json<CreateCostBudgetRequest>,
153    db_manager: &State<Arc<DatabaseManager>>,
154    user: User,
155) -> Result<Json<CostBudget>, (Status, Json<Value>)> {
156    // Get platform information
157    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
158        Ok(platform) => platform,
159        Err(_) => {
160            return Err((
161                Status::NotFound,
162                Json(json!({
163                    "error": "Platform not found",
164                    "message": format!("Platform with ID {} does not exist", platform_id)
165                }))
166            ));
167        }
168    };
169
170    // Get platform-specific database pool
171    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
172        Ok(pool) => pool,
173        Err(_) => {
174            return Err((
175                Status::InternalServerError,
176                Json(json!({
177                    "error": "Database error",
178                    "message": "Failed to connect to platform database"
179                }))
180            ));
181        }
182    };
183
184    let user_id = user.id;
185
186    //TODO: Validate user permissions here later
187
188    match db::cost::create_cost_budget(
189        &pool,
190        request.org_id,
191        request.app_id,
192        &request.budget_name,
193        request.budget_amount,
194        &request.currency,
195        &request.budget_period,
196        request.period_start,
197        request.period_end,
198        request.alert_threshold_percentage,
199        &request.alert_contacts,
200        user_id,
201    ).await {
202        Ok(budget) => Ok(Json(budget)),
203        Err(e) => Err((
204            Status::InternalServerError,
205            Json(json!({
206                "error": "Failed to create cost budget",
207                "message": format!("{}", e)
208            }))
209        )),
210    }
211}
212
213/// Update an existing cost budget.
214#[put("/platform/<platform_id>/cost_budgets/<id>", format = "json", data = "<request>")]
215pub async fn update_cost_budget(
216    platform_id: i64,
217    id: i64,
218    request: Json<UpdateCostBudgetRequest>,
219    db_manager: &State<Arc<DatabaseManager>>,
220) -> Result<Json<CostBudget>, (Status, Json<Value>)> {
221    // Get platform information
222    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
223        Ok(platform) => platform,
224        Err(_) => {
225            return Err((
226                Status::NotFound,
227                Json(json!({
228                    "error": "Platform not found",
229                    "message": format!("Platform with ID {} does not exist", platform_id)
230                }))
231            ));
232        }
233    };
234
235    // Get platform-specific database pool
236    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
237        Ok(pool) => pool,
238        Err(_) => {
239            return Err((
240                Status::InternalServerError,
241                Json(json!({
242                    "error": "Database error",
243                    "message": "Failed to connect to platform database"
244                }))
245            ));
246        }
247    };
248
249    match db::cost::update_cost_budget(
250        &pool,
251        id,
252        request.budget_name.as_deref(),
253        request.budget_amount,
254        request.alert_threshold_percentage,
255        request.alert_contacts.as_deref(),
256        request.is_active,
257    ).await {
258        Ok(budget) => Ok(Json(budget)),
259        Err(e) => Err((
260            Status::InternalServerError,
261            Json(json!({
262                "error": "Failed to update cost budget",
263                "message": format!("{}", e)
264            }))
265        )),
266    }
267}
268
269/// Delete a cost budget.
270#[delete("/platform/<platform_id>/cost_budgets/<id>")]
271pub async fn delete_cost_budget(
272    platform_id: i64,
273    id: i64,
274    db_manager: &State<Arc<DatabaseManager>>,
275) -> Result<Json<Value>, (Status, Json<Value>)> {
276    // Get platform information
277    let platform = match db::platforms::get_platform_by_id(db_manager.get_main_pool(), platform_id).await {
278        Ok(platform) => platform,
279        Err(_) => {
280            return Err((
281                Status::NotFound,
282                Json(json!({
283                    "error": "Platform not found",
284                    "message": format!("Platform with ID {} does not exist", platform_id)
285                }))
286            ));
287        }
288    };
289
290    // Get platform-specific database pool
291    let pool = match db_manager.get_platform_pool(&platform.name, platform_id).await {
292        Ok(pool) => pool,
293        Err(_) => {
294            return Err((
295                Status::InternalServerError,
296                Json(json!({
297                    "error": "Database error",
298                    "message": "Failed to connect to platform database"
299                }))
300            ));
301        }
302    };
303
304    match db::cost::delete_cost_budget(&pool, id).await {
305        Ok(_) => Ok(Json(json!({ "status": "deleted" }))),
306        Err(e) => Err((
307            Status::InternalServerError,
308            Json(json!({
309                "error": "Failed to delete cost budget",
310                "message": format!("{}", e)
311            }))
312        )),
313    }
314}