Added functions for adding, deleting and showing tickets

As said, functions got implemented. Also minor changes to migration
layout and dependencies
This commit is contained in:
2026-04-22 20:40:28 +02:00
parent 1725d2538c
commit 8b34dac813
10 changed files with 134 additions and 9 deletions

4
backend/Cargo.lock generated
View File

@@ -1493,6 +1493,7 @@ checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
dependencies = [
"base64",
"bytes",
"chrono",
"crc",
"crossbeam-queue",
"either",
@@ -1569,6 +1570,7 @@ dependencies = [
"bitflags",
"byteorder",
"bytes",
"chrono",
"crc",
"digest",
"dotenvy",
@@ -1610,6 +1612,7 @@ dependencies = [
"base64",
"bitflags",
"byteorder",
"chrono",
"crc",
"dotenvy",
"etcetera",
@@ -1644,6 +1647,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
dependencies = [
"atoi",
"chrono",
"flume",
"futures-channel",
"futures-core",

View File

@@ -7,7 +7,7 @@ edition = "2024"
axum = "0.8.9"
serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149"
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio", "tls-native-tls"] }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio", "tls-native-tls", "chrono"] }
tokio = { version = "1.52.1", features = ["rt-multi-thread", "macros"] }
dotenv = "0.15.0"
chrono = { version = "0.4.44", features = ["serde"] }

View File

@@ -0,0 +1 @@
mod ticket;

View File

@@ -0,0 +1,103 @@
use std::sync::Arc;
use axum::{
Json,
extract::{Path, State},
http::StatusCode,
response::IntoResponse,
};
use serde_json::json;
use sqlx::query;
use crate::{
AppState,
models::{Ticket, TicketCreateScheme, TicketResponse},
};
pub async fn create_ticket(
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) VALUES ($1, $2, $3, $4)"#,
)
.bind(body.category.to_string())
.bind(body.description.to_string())
.bind(body.betreff.to_string())
.bind(body.room.to_string())
.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>)> {
let tickets =
sqlx::query_as(r#"SELECT * FROM tickets WHERE status <> 'Archived' ORDER BY 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))
})?;
let ticket_response = tickets
.iter()
.map(|ticket| filter_record(&ticket))
.collect::<Vec<TicketResponse>>();
let json_response = serde_json::json!(ticket_response);
Ok(Json(json_response))
}
fn filter_record(ticket: &Ticket) -> TicketResponse {
TicketResponse {
id: ticket.id.to_owned(),
category: ticket.category.to_owned(),
betreff: ticket.betreff.to_owned(),
description: ticket.description.to_owned(),
room: ticket.room.to_owned(),
status: ticket.status.to_owned(),
date: ticket.date.to_owned(),
user_id: ticket.user_id.to_owned(),
}
}

View File

@@ -1,8 +1,9 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize};
use sqlx::{Decode, prelude::Type};
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Decode, Type)]
pub enum Category {
WhiteboardBeamer,
Internet,
@@ -25,7 +26,7 @@ impl Display for Category {
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Decode, Type)]
pub enum Status {
ToDo,
InProgress,
@@ -56,6 +57,18 @@ pub struct Ticket {
pub user_id: i16,
}
#[derive(Deserialize, Serialize, Debug, PartialEq)]
pub struct TicketResponse {
pub id: i32,
pub category: Category,
pub betreff: String,
pub description: String,
pub room: i16,
pub status: Status,
pub date: chrono::NaiveDateTime,
pub user_id: i16,
}
#[derive(Deserialize, Serialize, PartialEq, Debug)]
pub struct User {
pub id: i16,