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:
4
backend/Cargo.lock
generated
4
backend/Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
1
backend/src/handlers/mod.rs
Normal file
1
backend/src/handlers/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
mod ticket;
|
||||
103
backend/src/handlers/ticket.rs
Normal file
103
backend/src/handlers/ticket.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
2
migrations/20260422094704_types.down.sql
Normal file
2
migrations/20260422094704_types.down.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
DROP TYPE category;
|
||||
DROP TYPE status;
|
||||
2
migrations/20260422094704_types.up.sql
Normal file
2
migrations/20260422094704_types.up.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
CREATE TYPE category AS ENUM('Whiteboard Beamer', 'Internet', 'iPad Koffer', 'Apple TV', 'Docu Cam', 'Sonstiges');
|
||||
CREATE TYPE status AS ENUM('ToDo', 'InProgress', 'Done', 'Archived');
|
||||
2
migrations/20260422094706_ticket_table.down.sql
Normal file
2
migrations/20260422094706_ticket_table.down.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
DROP TABLE tickets;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
CREATE TYPE category AS ENUM('Whiteboard Beamer', 'Internet', 'iPad Koffer', 'Apple TV', 'Docu Cam', 'Sonstiges')
|
||||
CREAYE TYPE status AS ENUM('ToDo', 'InProgress', 'Done', 'Archived')
|
||||
CREATE TABLE IF NOT EXISTS tickets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
category category NOT NULL DEFAULT 'Sonstiges',
|
||||
betreff VARCHAR(100),
|
||||
description VARCHAR,
|
||||
description TEXT,
|
||||
room SMALLINT,
|
||||
status status NOT NULL DEFAULT 'ToDo',
|
||||
date TIMESTAMP,
|
||||
date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id SMALLINT
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
CREATE TABLE users (
|
||||
id SMALLINT PRIMARY KEY AUTOINCREMENT,
|
||||
id SMALLINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
name VARCHAR(30),
|
||||
firstname VARCHAR(30),
|
||||
is_admin BOOLEAN NOT NULL DEFAULT false
|
||||
|
||||
Reference in New Issue
Block a user