api/routes/modules/assignments/tickets/
post.rs

1//! Ticket creation handler.
2//!
3//! Provides an endpoint to create a new ticket for an assignment.
4//!
5//! Only authenticated users can create tickets, and each ticket is linked
6//! to the assignment and the user who created it.
7
8use axum::{
9    Extension, Json,
10    extract::{Path, State},
11    http::StatusCode,
12    response::IntoResponse,
13};
14use db::models::tickets::Model as TicketModel;
15use serde::Deserialize;
16use util::state::AppState;
17
18use crate::{auth::AuthUser, response::ApiResponse, routes::modules::assignments::tickets::common::TicketResponse};
19
20/// Request payload for creating a ticket.
21#[derive(Debug, Deserialize)]
22pub struct TicketRequest {
23    /// Title of the ticket
24    pub title: String,
25    /// Detailed description of the issue or request
26    pub description: String,
27}
28
29/// Creates a new ticket.
30///
31/// **Endpoint:** `POST /modules/{module_id}/assignments/{assignment_id}/tickets`  
32/// **Permissions:** Authenticated users can create tickets for the assignment.
33///
34/// ### Path parameters
35/// - `module_id`       → ID of the module (unused in handler, kept for route consistency)
36/// - `assignment_id`   → ID of the assignment for which the ticket is created
37///
38/// ### Request body
39/// ```json
40/// {
41///   "title": "Issue with submission",
42///   "description": "I am unable to submit my assignment due to..."
43/// }
44/// ```
45///
46/// ### Responses
47/// - `200 OK` → Ticket created successfully
48/// ```json
49/// {
50///   "success": true,
51///   "data": {
52///       "id": 123,
53///       "title": "Issue with submission",
54///       "description": "I am unable to submit my assignment due to...",
55///       "status": "open",
56///       "user_id": 456
57///   },
58///   "message": "Ticket created successfully"
59/// }
60/// ```
61/// - `500 Internal Server Error` → Failed to create the ticket
62/// ```json
63/// {
64///   "success": false,
65///   "data": null,
66///   "message": "Failed to create ticket: <error message>"
67/// }
68/// ```
69pub async fn create_ticket(
70    State(app_state): State<AppState>,
71    Path((_, assignment_id)): Path<(i64, i64)>,
72    Extension(AuthUser(claims)): Extension<AuthUser>,
73    Json(req): Json<TicketRequest>,
74) -> impl IntoResponse {
75    let db = app_state.db();
76    let user_id = claims.sub;
77
78    match TicketModel::create(db, assignment_id, user_id, &req.title, &req.description).await {
79        Ok(ticket) => {
80            let response = TicketResponse::from(ticket);
81            (
82                StatusCode::OK,
83                Json(ApiResponse::success(
84                    response,
85                    "Ticket created successfully",
86                )),
87            )
88        }
89        Err(e) => (
90            StatusCode::INTERNAL_SERVER_ERROR,
91            Json(ApiResponse::<TicketResponse>::error(format!(
92                "Failed to create ticket: {}",
93                e
94            ))),
95        ),
96    }
97}