195 lines
6.4 KiB
Rust
195 lines
6.4 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
/// API response for a ticket with user information.
|
|
///
|
|
/// Returned by ticket endpoints. Includes denormalized user data for easier frontend rendering.
|
|
/// Created via [`TicketCreateScheme`].
|
|
///
|
|
/// # Fields
|
|
/// - `id`: Unique ticket identifier
|
|
/// - `category`: Ticket category/type
|
|
/// - `betreff`: Ticket subject line
|
|
/// - `description`: Detailed ticket description
|
|
/// - `room`: Room number associated with the issue
|
|
/// - `status`: Current ticket status (e.g., "open", "in_progress", "resolved")
|
|
/// - `date`: When the ticket was created (UTC timestamp)
|
|
/// - `user_id`: ID of the user who created the ticket (references [`User`])
|
|
/// - `user_first_name`, `user_last_name`: User's name (denormalized for convenience)
|
|
///
|
|
/// # Example
|
|
/// ```json
|
|
/// {
|
|
/// "id": 1,
|
|
/// "category": "maintenance",
|
|
/// "betreff": "Broken light in room 101",
|
|
/// "description": "The ceiling light is not working",
|
|
/// "room": 101,
|
|
/// "status": "open",
|
|
/// "date": "2024-01-15T10:30:00Z",
|
|
/// "user_id": 5,
|
|
/// "user_first_name": "John",
|
|
/// "user_last_name": "Doe"
|
|
/// }
|
|
/// ```
|
|
#[derive(Deserialize, Serialize, Debug, PartialEq)]
|
|
pub struct TicketResponse {
|
|
pub id: i32,
|
|
pub category: String,
|
|
pub betreff: String,
|
|
pub description: String,
|
|
pub room: i16,
|
|
pub status: String,
|
|
pub date: chrono::DateTime<chrono::Utc>,
|
|
pub user_id: i16,
|
|
pub user_first_name: String,
|
|
pub user_last_name: String,
|
|
}
|
|
|
|
/// Complete user record from the database.
|
|
///
|
|
/// Contains all user information including the password hash.
|
|
/// This should NEVER be sent directly to clients - always use [`FilteredUser`] instead.
|
|
///
|
|
/// # Fields
|
|
/// - `id`: Unique user identifier
|
|
/// - `first_name`, `last_name`: User's full name
|
|
/// - `username`: Login username (must be unique)
|
|
/// - `is_admin`: Whether user has admin privileges
|
|
/// - `pwd`: Argon2 password hash (NEVER expose to clients)
|
|
///
|
|
/// # Security Note
|
|
/// The `pwd` field contains the password hash and should never be included in API responses.
|
|
/// Use [`filter_user()`](`crate::handlers::auth::filter_user`) to convert to [`FilteredUser`] for responses.
|
|
#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, sqlx::FromRow)]
|
|
pub struct User {
|
|
pub id: i16,
|
|
pub last_name: String,
|
|
pub first_name: String,
|
|
pub username: String,
|
|
pub is_admin: bool,
|
|
pub pwd: String,
|
|
}
|
|
|
|
/// Payload for creating a new ticket.
|
|
///
|
|
/// Sent to `/api/tickets/create`. The backend automatically associates it with the
|
|
/// authenticated user and sets the creation timestamp. Converted to [`TicketResponse`] for the response.
|
|
///
|
|
/// # Fields
|
|
/// - `category`: Ticket category/type
|
|
/// - `betreff`: Subject line for the ticket
|
|
/// - `description`: Detailed problem description
|
|
/// - `room`: Room number where the issue is located
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct TicketCreateScheme {
|
|
pub category: String,
|
|
pub betreff: String,
|
|
pub description: String,
|
|
pub room: i16,
|
|
}
|
|
|
|
/// Payload for updating a ticket.
|
|
///
|
|
/// Sent to `PATCH /api/tickets/{id}`. Allows updating the ticket [`TicketResponse::status`].
|
|
/// Only admins can update tickets.
|
|
///
|
|
/// # Fields
|
|
/// - `status`: New ticket status (e.g., "open", "in_progress", "resolved")
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct TicketUpdateScheme {
|
|
pub status: String,
|
|
}
|
|
|
|
/// Payload for updating user information.
|
|
///
|
|
/// Sent to `PATCH /api/users/{id}`. Allows updating profile and admin status.
|
|
/// Only admins can update [`User`] records. Empty password field means no password change.
|
|
///
|
|
/// # Fields
|
|
/// - `id`: [`User`] ID to update
|
|
/// - `first_name`, `last_name`: Updated user name
|
|
/// - `username`: Updated login username
|
|
/// - `make_admin`: New admin privilege status
|
|
/// - `new_pwd`: New password (empty string = keep existing password)
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct UserUpdateScheme {
|
|
pub id: i16,
|
|
pub first_name: String,
|
|
pub last_name: String,
|
|
pub username: String,
|
|
pub make_admin: bool,
|
|
pub new_pwd: String,
|
|
}
|
|
|
|
/// Payload for creating a new user account.
|
|
///
|
|
/// Used in both admin registration (`/api/register`) and initial setup (`/api/setup-admin`).
|
|
/// The password is hashed server-side before storage using Argon2. Converted to [`User`] for storage.
|
|
///
|
|
/// # Fields
|
|
/// - `first_name`: User's first name
|
|
/// - `last_name`: User's last name
|
|
/// - `username`: Unique username for login
|
|
/// - `is_admin`: Whether to grant admin privileges (setup endpoint always sets this to true)
|
|
/// - `pwd`: Plain text password (hashed on server)
|
|
#[derive(Deserialize, Serialize, Debug, sqlx::FromRow)]
|
|
pub struct UserCreateScheme {
|
|
pub first_name: String,
|
|
pub last_name: String,
|
|
pub username: String,
|
|
pub is_admin: bool,
|
|
pub pwd: String,
|
|
}
|
|
|
|
/// Payload for user login.
|
|
///
|
|
/// Sent to `/api/login` endpoint with credentials. The backend verifies the password
|
|
/// against the stored Argon2 hash.
|
|
///
|
|
/// # Security
|
|
/// The password is never stored in plain text - only the Argon2 hash is persisted.
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
pub struct LoginScheme {
|
|
pub username: String,
|
|
pub pwd: String,
|
|
}
|
|
|
|
/// User information sent to clients, excluding password hashes.
|
|
///
|
|
/// This is the safe version of [`User`] data that gets returned in API responses.
|
|
/// It never includes the password hash or JWT claims. Always use this for responses
|
|
/// to prevent leaking sensitive data.
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub struct FilteredUser {
|
|
pub id: i16,
|
|
pub first_name: String,
|
|
pub last_name: String,
|
|
pub username: String,
|
|
pub is_admin: bool,
|
|
}
|
|
|
|
/// JWT token claims embedded in the session token.
|
|
///
|
|
/// Contains user identification and token validity information.
|
|
/// Generated during login via `encode_token` and verified via `decode_token`.
|
|
///
|
|
/// # Fields
|
|
/// - `sub`: Subject - the user ID as a string (references [`User`])
|
|
/// - `issued`: Unix timestamp when token was created
|
|
/// - `expires`: Unix timestamp when token expires (currently 1 hour from creation)
|
|
///
|
|
/// # Token Lifetime
|
|
/// Tokens are valid for 1 hour. After expiration, user must log in again.
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
pub struct Claims {
|
|
/// Subject - typically the user ID
|
|
#[serde(alias = "subject")]
|
|
pub sub: String,
|
|
/// Issued at time (Unix timestamp)
|
|
#[serde(rename = "iat", alias = "issued", default)]
|
|
pub issued: usize,
|
|
/// Expiration time (Unix timestamp)
|
|
#[serde(rename = "exp", alias = "expires", default)]
|
|
pub expires: usize,
|
|
}
|