2 Commits
Author SHA1 Message Date
schn33fuchs 5e643503aa Added ticket edit functionality
As said, also minor change to database for testing purposes
2026-04-23 20:13:09 +02:00
schn33fuchs b905ffc9b1 Changed enums to string
String is easyer to decode and the sendable data in the frontend will be
limited.
2026-04-23 16:51:21 +02:00
6 changed files with 64 additions and 59 deletions
+47 -3
View File
@@ -11,7 +11,7 @@ use sqlx::query;
use crate::{
AppState,
models::{Ticket, TicketCreateScheme, TicketResponse},
models::{Ticket, TicketCreateScheme, TicketResponse, TicketUpdateScheme},
};
pub async fn create_ticket(
@@ -24,7 +24,7 @@ pub async fn create_ticket(
.bind(body.category.to_string())
.bind(body.description.to_string())
.bind(body.betreff.to_string())
.bind(body.room.to_string())
.bind(body.room)
.execute(&data.db)
.await;
@@ -93,7 +93,7 @@ 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_as(r#"SELECT * FROM tickets WHERE id = $1"#)
let query = sqlx::query_as::<_, Ticket>(r#"SELECT * FROM tickets WHERE id = $1"#)
.bind(id)
.fetch_one(&data.db)
.await;
@@ -119,6 +119,50 @@ pub async fn get_ticket_by_id(
};
}
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_as(r#"SELECT * FROM tickets WHERE 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 = serde_json::json!({
"ticket": filter_record(&updated_ticket),
"status": "success"
});
Ok(Json(ticket_response))
}
fn filter_record(ticket: &Ticket) -> TicketResponse {
TicketResponse {
id: ticket.id.to_owned(),
+10 -47
View File
@@ -3,56 +3,14 @@ use std::fmt::Display;
use serde::{Deserialize, Serialize};
use sqlx::{Decode, prelude::Type};
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Type)]
pub enum Category {
WhiteboardBeamer,
Internet,
IPadKoffer,
AppleTV,
DocuCam,
Sonstiges,
}
impl Display for Category {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::WhiteboardBeamer => write!(f, "Whiteboard Beamer"),
Self::Internet => write!(f, "Internet"),
Self::IPadKoffer => write!(f, "IPad Koffer"),
Self::AppleTV => write!(f, "Apple TV"),
Self::DocuCam => write!(f, "Docu Cam"),
Self::Sonstiges => write!(f, "Sonstiges"),
}
}
}
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Type)]
pub enum Status {
ToDo,
InProgress,
Done,
Archived,
}
impl Display for Status {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ToDo => write!(f, "ToDo"),
Self::InProgress => write!(f, "InProgress"),
Self::Done => write!(f, "Done"),
Self::Archived => write!(f, "Archived"),
}
}
}
#[derive(Deserialize, Serialize, PartialEq, Debug, sqlx::FromRow)]
pub struct Ticket {
pub id: i32,
pub category: Category,
pub category: String,
pub betreff: String,
pub description: String,
pub room: i16,
pub status: Status,
pub status: String,
pub date: chrono::NaiveDateTime,
pub user_id: i16,
}
@@ -60,11 +18,11 @@ pub struct Ticket {
#[derive(Deserialize, Serialize, Debug, PartialEq)]
pub struct TicketResponse {
pub id: i32,
pub category: Category,
pub category: String,
pub betreff: String,
pub description: String,
pub room: i16,
pub status: Status,
pub status: String,
pub date: chrono::NaiveDateTime,
pub user_id: i16,
}
@@ -79,8 +37,13 @@ pub struct User {
#[derive(Deserialize, Serialize, Debug)]
pub struct TicketCreateScheme {
pub category: Category,
pub category: String,
pub betreff: String,
pub description: String,
pub room: i16,
}
#[derive(Deserialize, Serialize, Debug)]
pub struct TicketUpdateScheme {
pub status: String,
}
+4 -2
View File
@@ -7,7 +7,7 @@ use axum::{
use crate::{
AppState,
handlers::ticket::{create_ticket, delete_ticket, get_ticket_by_id, get_tickets},
handlers::ticket::{create_ticket, delete_ticket, edit_ticket, get_ticket_by_id, get_tickets},
};
pub fn create_router(state: Arc<AppState>) -> Router {
@@ -16,7 +16,9 @@ pub fn create_router(state: Arc<AppState>) -> Router {
.route("/api/tickets/create", post(create_ticket))
.route(
"/api/tickets/{id}",
get(get_ticket_by_id).delete(delete_ticket),
get(get_ticket_by_id)
.delete(delete_ticket)
.patch(edit_ticket),
)
.with_state(state)
}
-2
View File
@@ -1,2 +0,0 @@
DROP TYPE category;
DROP TYPE status;
-2
View File
@@ -1,2 +0,0 @@
CREATE TYPE category AS ENUM('Whiteboard Beamer', 'Internet', 'iPad Koffer', 'Apple TV', 'Docu Cam', 'Sonstiges');
CREATE TYPE status AS ENUM('ToDo', 'InProgress', 'Done', 'Archived');
+3 -3
View File
@@ -1,10 +1,10 @@
CREATE TABLE IF NOT EXISTS tickets (
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
category category NOT NULL DEFAULT 'Sonstiges',
category VARCHAR(20) NOT NULL DEFAULT 'Sonstiges',
betreff VARCHAR(100),
description TEXT,
room SMALLINT,
status status NOT NULL DEFAULT 'ToDo',
status VARCHAR(15) NOT NULL DEFAULT 'ToDo',
date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
user_id SMALLINT
user_id SMALLINT DEFAULT 1
);