Files
hotel_api/src/rooms/handler.rs

164 lines
4.9 KiB
Rust

use axum::{Json, extract::Path, extract::State };
use axum::response::IntoResponse;
use axum::http::StatusCode;
use axum::extract::ws::Message;
use serde::Serialize;
use serde_json::json;
use crate::rooms::extractor::UpdateRoomPayload;
//use crate::utils::db_pool::*;
use crate::utils::auth::AuthClaims;
use crate::utils::db_pool::{HotelPool,AppState};
use std::sync::Arc;
use r2d2::{Pool};
use r2d2_sqlite::SqliteConnectionManager;
use dashmap::DashMap;
use rusqlite::params;
pub async fn hello_rooms() -> String {
"hello from rooms".to_string()
}
pub async fn fake_db_update(
State(state): State<AppState>,
AuthClaims { user_id, hotel_id }: AuthClaims,
Path(room_id): Path<i32>,
UpdateRoomPayload(payload): UpdateRoomPayload,
) -> impl IntoResponse {
let pool = state.hotel_pools.get_pool(hotel_id);
let conn = match pool.get() {
Ok(conn) => conn,
Err(err) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Pool error: {err}")),
};
let result = conn.execute(
"UPDATE rooms SET status = ?1 WHERE number = ?2",
params![&payload.status, &room_id],
);
match result {
Ok(rows) if rows > 0 => (StatusCode::OK, format!("Updated room {room_id} in hotel {}", hotel_id)),
Ok(_) => (StatusCode::NOT_FOUND, "No room found".to_string()),
Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("DB error: {err}")),
}
}
pub async fn clean_db_update(
State(state): State<AppState>,
Path(room_id): Path<i32>,
AuthClaims { user_id, hotel_id }: AuthClaims,
UpdateRoomPayload(payload): UpdateRoomPayload,
) -> impl IntoResponse {
//TODO: make better error handling :
// if wrong param collumn targeted,
// if missing path param
let pool = state.hotel_pools.get_pool(hotel_id);
let conn = match pool.get(){
Ok(conn) => conn,
Err(err) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Pool error: {err}")),
};
let result: Result<String, rusqlite::Error> = conn.query_row(
"UPDATE rooms SET status = ?1 WHERE id = ?2 RETURNING number",
params![&payload.status, &room_id],
|row| row.get(0),
);
match result {
Ok(room_number) => {
// --- broadcast to all WS clients in the hotel ---
if let Err(err) = conn.execute(
"INSERT INTO room_history (room_id, room_number, status) VALUES (?1, ?2, ?3)",
params![&room_id, &room_number, &payload.status],
) {
return (StatusCode::INTERNAL_SERVER_ERROR, format!("Failed to insert history: {err}"));
}
if let Some(hotel_users) = state.ws_map.get(&hotel_id) {
let update_msg = json!({
"room_id": room_id,
"status": payload.status,
"updated_by": user_id,
})
.to_string();
for entry in hotel_users.iter() {
let sender = entry.value();
// ignore errors (client disconnected)
let _ = sender.send(Message::Text(update_msg.clone().into()));
}
}
(StatusCode::OK, format!("updated room {room_id} in hotel {hotel_id}, with status: {}", payload.status))
}
Ok(_) => (StatusCode::NOT_FOUND, "No room found".to_string()),
Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, format!("Error from DB: {err}")),
}
}
#[derive(Serialize)]
struct Room {
id: i32,
number: String,
status: String,
}
pub async fn get_all_rooms(
State(state): State<AppState>,
AuthClaims { hotel_id, .. }: AuthClaims,
) -> impl IntoResponse {
let pool = state.hotel_pools.get_pool(hotel_id);
let conn = match pool.get(){
Ok(conn) => conn,
Err(err) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Pool error: {err}")),
};
let mut stmt = match conn.prepare(
"SELECT id, number, status FROM rooms ",
) {
Ok(s) => s,
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Prepare failed: {}", e)),
};
let room_iter = match stmt.query_map( params![],|row| {
Ok(Room {
id: row.get(0)?,
number: row.get(1)?,
status: row.get(2)?,
})
}) {
Ok(iter) => iter,
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Query failed: {}", e)),
};
let rooms: Vec<Room> = match room_iter.collect::<Result<Vec<_>, _>>() {
Ok(u) => u,
Err(e) => return (StatusCode::INTERNAL_SERVER_ERROR, format!("Collect failed: {}", e)),
};
match serde_json::to_string(&rooms) {
Ok(json) => (StatusCode::OK, json),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, format!("Serialization failed: {}", e)),
}
}
struct RoomRequest {
item_id: i32,
item_amount: i32,
token: String,
}