2 Commits
Author SHA1 Message Date
schn33fuchs 535d940857 Removed unneeded imports 2026-05-10 10:26:16 +02:00
schn33fuchs 33df619c8d Cargo doc fixes
It's good now
2026-05-10 10:18:45 +02:00
9 changed files with 50 additions and 44 deletions
Generated
+4
View File
@@ -2777,6 +2777,10 @@ dependencies = [
"syn 2.0.117", "syn 2.0.117",
] ]
[[package]]
name = "ticketsystem"
version = "0.1.0"
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.47" version = "0.3.47"
+8
View File
@@ -1,3 +1,11 @@
[package]
name = "ticketsystem"
version = "0.1.0"
edition = "2021"
readme = "README.md"
description = "A ticket system with backend and frontend components"
publish = false
[workspace] [workspace]
members = ["backend", "frontend"] members = ["backend", "frontend"]
resolver = "2" resolver = "2"
+6
View File
@@ -1,2 +1,8 @@
# Ticketsystem # Ticketsystem
A ticket system with backend and frontend components.
## Components
- **[Backend](../backend/index.html)** - The server-side API and business logic
- **[Frontend](../frontend/index.html)** - The client-side user interface
+2 -2
View File
@@ -1,5 +1,5 @@
use axum::{Json, http::StatusCode}; use axum::{Json, http::StatusCode};
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, decode, encode}; use jsonwebtoken::{DecodingKey, EncodingKey, Header, decode, encode};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::models::Claims; use crate::models::Claims;
@@ -65,7 +65,7 @@ pub fn decode_token(token: String, key: &DecodingKey) -> Result<Claims, (StatusC
validation.validate_exp = false; validation.validate_exp = false;
validation.validate_nbf = false; validation.validate_nbf = false;
validation.leeway = 0; validation.leeway = 0;
let claims = decode::<Claims>(&token, key, &validation) let claims = decode::<Claims>(&token, key, &validation)
.map_err(|err| { .map_err(|err| {
let message = format!("Invalid Token: {}", err); let message = format!("Invalid Token: {}", err);
+1 -6
View File
@@ -12,12 +12,7 @@ use axum_extra::extract::CookieJar;
use jsonwebtoken::DecodingKey; use jsonwebtoken::DecodingKey;
use serde_json::json; use serde_json::json;
use crate::{ use crate::{AppState, cookie::jwt::decode_token, handlers::auth::filter_user, models::User};
AppState,
cookie::jwt::decode_token,
handlers::auth::filter_user,
models::{LoginScheme, User},
};
/// Axum middleware to validate a JWT token present in cookies or Authorization header. /// Axum middleware to validate a JWT token present in cookies or Authorization header.
/// ///
+24 -21
View File
@@ -1,4 +1,4 @@
use std::{sync::Arc, usize}; use std::sync::Arc;
use argon2::{ use argon2::{
Argon2, PasswordHash, PasswordHasher, PasswordVerifier, Argon2, PasswordHash, PasswordHasher, PasswordVerifier,
@@ -11,7 +11,6 @@ use axum::{
response::IntoResponse, response::IntoResponse,
}; };
use axum_extra::extract::cookie::{Cookie, SameSite}; use axum_extra::extract::cookie::{Cookie, SameSite};
use chrono::format;
use jsonwebtoken::{EncodingKey, Header}; use jsonwebtoken::{EncodingKey, Header};
use serde_json::json; use serde_json::json;
@@ -485,15 +484,16 @@ pub async fn update_user(
pub async fn check_admin_exists( pub async fn check_admin_exists(
State(data): State<Arc<AppState>>, State(data): State<Arc<AppState>>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> { ) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
let admin_count = sqlx::query_scalar::<_, i64>(r#"SELECT COUNT(*) FROM users WHERE is_admin = true"#) let admin_count =
.fetch_one(&data.db) sqlx::query_scalar::<_, i64>(r#"SELECT COUNT(*) FROM users WHERE is_admin = true"#)
.await .fetch_one(&data.db)
.map_err(|e| { .await
( .map_err(|e| {
StatusCode::INTERNAL_SERVER_ERROR, (
Json(json!({"status": "error", "message": format!("{:?}", e)})), StatusCode::INTERNAL_SERVER_ERROR,
) Json(json!({"status": "error", "message": format!("{:?}", e)})),
})?; )
})?;
let has_admin = admin_count > 0; let has_admin = admin_count > 0;
Ok(Json(json!({"has_admin": has_admin}))) Ok(Json(json!({"has_admin": has_admin})))
@@ -528,15 +528,16 @@ pub async fn setup_initial_admin(
Json(request): Json<UserCreateScheme>, Json(request): Json<UserCreateScheme>,
) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> { ) -> Result<impl IntoResponse, (StatusCode, Json<serde_json::Value>)> {
// Check if any admin already exists // Check if any admin already exists
let admin_count = sqlx::query_scalar::<_, i64>(r#"SELECT COUNT(*) FROM users WHERE is_admin = true"#) let admin_count =
.fetch_one(&data.db) sqlx::query_scalar::<_, i64>(r#"SELECT COUNT(*) FROM users WHERE is_admin = true"#)
.await .fetch_one(&data.db)
.map_err(|e| { .await
( .map_err(|e| {
StatusCode::INTERNAL_SERVER_ERROR, (
Json(json!({"status": "error", "message": format!("{:?}", e)})), StatusCode::INTERNAL_SERVER_ERROR,
) Json(json!({"status": "error", "message": format!("{:?}", e)})),
})?; )
})?;
if admin_count > 0 { if admin_count > 0 {
return Err(( return Err((
@@ -580,7 +581,9 @@ pub async fn setup_initial_admin(
Json(json!({"status": "error", "message": "Error creating admin user"})), Json(json!({"status": "error", "message": "Error creating admin user"})),
)); ));
} else { } else {
Ok(Json(json!({"status": "success", "result": "Admin user created"}))) Ok(Json(
json!({"status": "success", "result": "Admin user created"}),
))
} }
} }
+4 -12
View File
@@ -1,5 +1,3 @@
#![allow(unused_imports)]
/// Cookie and JWT authentication utilities /// Cookie and JWT authentication utilities
mod cookie; mod cookie;
/// Environment configuration loading /// Environment configuration loading
@@ -13,18 +11,12 @@ mod router;
use std::sync::Arc; use std::sync::Arc;
use axum::{ use axum::http::{
Router, HeaderValue, Method,
http::{ header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE},
HeaderValue, Method,
header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE},
},
routing,
}; };
use dotenv::dotenv; use dotenv::dotenv;
use models::*;
use router::create_router; use router::create_router;
use serde::{Deserialize, Serialize};
use sqlx::{PgPool, postgres::PgPoolOptions}; use sqlx::{PgPool, postgres::PgPoolOptions};
use tower_http::cors::CorsLayer; use tower_http::cors::CorsLayer;
@@ -65,7 +57,7 @@ async fn main() {
dotenv().ok(); dotenv().ok();
let env = Env::load(); let env = Env::load();
let database_url = &env.db_url; let database_url = &env.db_url;
// Establish connection pool to PostgreSQL // Establish connection pool to PostgreSQL
let pool = match PgPoolOptions::new().connect(&database_url).await { let pool = match PgPoolOptions::new().connect(&database_url).await {
Ok(pool) => { Ok(pool) => {
-3
View File
@@ -1,7 +1,4 @@
use std::fmt::Display;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sqlx::{Decode, prelude::Type};
/// API response for a ticket with user information. /// API response for a ticket with user information.
/// ///
+1
View File
@@ -0,0 +1 @@
#![doc = include_str!("../README.md")]