Files
ticketsystem/backend/src/handlers/ticket.rs
2026-05-02 10:23:25 +02:00

220 lines
7.0 KiB
Rust

use std::sync::Arc;
use axum::{
Extension, Json,
extract::{Path, State},
http::StatusCode,
response::IntoResponse,
};
use serde_json::json;
use sqlx::{Row, query};
use crate::{
AppState,
models::{FilteredUser, TicketCreateScheme, TicketResponse, TicketUpdateScheme},
};
pub async fn create_ticket(
Extension(user): Extension<FilteredUser>,
State(data): State<Arc<AppState>>,
Json(body): Json<TicketCreateScheme>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let query = query(
r#"INSERT INTO tickets (category, description, betreff, room, user_id) VALUES ($1, $2, $3, $4, $5)"#,
)
.bind(body.category.to_string())
.bind(body.description.to_string())
.bind(body.betreff.to_string())
.bind(body.room)
.bind(user.id)
.execute(&data.db)
.await;
if let Err(err) = query {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", err),})),
));
}
let response_status = serde_json::json!({"status": "success"});
Ok(Json(response_status))
}
pub async fn delete_ticket(
Path(id): Path<i32>,
State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let query = sqlx::query(r#"DELETE FROM tickets WHERE id = $1"#)
.bind(id)
.execute(&data.db)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
)
})?;
if query.rows_affected() == 0 {
let error_response = serde_json::json!({
"status": "error",
"message": format!("Ticket with ID {} not found", id)
});
return Err((StatusCode::NOT_FOUND, Json(error_response)));
}
Ok(StatusCode::NO_CONTENT)
}
pub async fn get_tickets(
State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
println!("get_tickets called");
let tickets = sqlx::query(
r#"SELECT t.id, t.category, t.betreff, t.description, t.room, t.status, t.date, t.user_id, u.first_name, u.last_name
FROM tickets t
LEFT JOIN users u ON t.user_id = u.id
WHERE t.status <> 'Archived' ORDER BY t.date DESC"#,
)
.fetch_all(&data.db)
.await
.map_err(|e| {
let error_response = serde_json::json!({
"status": "error",
"message": format!("Database error: {}", e),
});
(StatusCode::INTERNAL_SERVER_ERROR, Json(error_response))
})?;
println!("Tickets fetched");
let ticket_response: Vec<TicketResponse> = tickets
.iter()
.map(|row| TicketResponse {
id: row.get("id"),
category: row.get("category"),
betreff: row.get("betreff"),
description: row.get("description"),
room: row.get("room"),
status: row.get("status"),
date: row.get("date"),
user_id: row.get("user_id"),
user_first_name: row.get("first_name"),
user_last_name: row.get("last_name"),
})
.collect();
let json_response = serde_json::json!(ticket_response);
println!("Json contructed");
Ok(Json(json_response))
}
pub async fn get_ticket_by_id(
Path(id): Path<i32>,
State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let query = sqlx::query(
r#"SELECT t.id, t.category, t.betreff, t.description, t.room, t.status, t.date, t.user_id, u.first_name, u.last_name
FROM tickets t
LEFT JOIN users u ON t.user_id = u.id
WHERE t.id = $1"#,
)
.bind(id)
.fetch_one(&data.db)
.await;
match query {
Ok(row) => {
let ticket_response = TicketResponse {
id: row.get("id"),
category: row.get("category"),
betreff: row.get("betreff"),
description: row.get("description"),
room: row.get("room"),
status: row.get("status"),
date: row.get("date"),
user_id: row.get("user_id"),
user_first_name: row.get("first_name"),
user_last_name: row.get("last_name"),
};
let response = serde_json::json!(ticket_response);
return Ok(Json(response));
}
Err(sqlx::Error::RowNotFound) => {
let error_response = serde_json::json!({
"status": "fail",
"message": format!("Ticket with ID {} not found", id)
});
return Err((StatusCode::NOT_FOUND, Json(error_response)));
}
Err(e) => {
return Err((
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
));
}
};
}
pub async fn edit_ticket(
Path(id): Path<i32>,
State(data): State<Arc<AppState>>,
Json(body): Json<TicketUpdateScheme>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let update_result = sqlx::query(r#"UPDATE tickets SET status = $1 WHERE id = $2"#)
.bind(body.status.to_owned())
.bind(id)
.execute(&data.db)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
)
})?;
if update_result.rows_affected() == 0 {
let error_response = serde_json::json!({
"status": "error",
"message": format!("Ticket with ID {} not found", id)
});
return Err((StatusCode::INTERNAL_SERVER_ERROR, Json(error_response)));
}
let updated_ticket = sqlx::query(
r#"SELECT t.id, t.category, t.betreff, t.description, t.room, t.status, t.date, t.user_id, u.first_name, u.last_name
FROM tickets t
LEFT JOIN users u ON t.user_id = u.id
WHERE t.id = $1"#,
)
.bind(id)
.fetch_one(&data.db)
.await
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"status": "error", "message": format!("{:?}", e)})),
)
})?;
let ticket_response = TicketResponse {
id: updated_ticket.get("id"),
category: updated_ticket.get("category"),
betreff: updated_ticket.get("betreff"),
description: updated_ticket.get("description"),
room: updated_ticket.get("room"),
status: updated_ticket.get("status"),
date: updated_ticket.get("date"),
user_id: updated_ticket.get("user_id"),
user_first_name: updated_ticket.get("first_name"),
user_last_name: updated_ticket.get("last_name"),
};
let response = serde_json::json!({
"ticket": ticket_response,
"status": "success"
});
Ok(Json(response))
}