api/routes/modules/assignments/
delete.rs

1//! Assignment deletion routes.
2//!
3//! Provides endpoints for deleting single or multiple assignments within a module.
4//!
5//! - `DELETE /api/modules/{module_id}/assignments/{assignment_id}`  
6//!   Deletes a single assignment along with its associated files and folder.
7//!
8//! - `DELETE /api/modules/{module_id}/assignments/bulk`  
9//!   Deletes multiple assignments in a module using a JSON array of assignment IDs.
10//!
11//! **Access Control:** Only lecturers or admins assigned to the module can perform deletions.
12//!
13//! **Responses:** JSON-wrapped `ApiResponse` indicating success, number of deletions, or detailed errors.
14
15use axum::{
16    extract::{State, Path},
17    http::StatusCode,
18    response::IntoResponse,
19    Json,
20};
21use sqlx::types::JsonValue;
22use serde_json::json;
23use db::models::assignment;
24use util::state::AppState;
25use crate::response::ApiResponse;
26use super::common::BulkDeleteRequest;
27
28/// DELETE /api/modules/:module_id/assignments/:assignment_id
29///
30/// Delete a specific assignment and its associated files and folder.
31/// Only accessible by lecturers or admins assigned to the module.
32///
33/// ### Path Parameters
34/// - `module_id` (i64): The ID of the module containing the assignment
35/// - `assignment_id` (i64): The ID of the assignment to delete
36///
37/// ### Responses
38///
39/// - `200 OK`  
40/// ```json
41/// {
42///   "success": true,
43///   "message": "Assignment 123 deleted successfully"
44/// }
45/// ```
46///
47/// - `404 Not Found`  
48/// ```json
49/// {
50///   "success": false,
51///   "message": "No assignment found with ID 123 in module 456"
52/// }
53/// ```
54///
55/// - `500 Internal Server Error`  
56/// ```json
57/// {
58///   "success": false,
59///   "message": "Database error details"
60/// }
61/// ```
62pub async fn delete_assignment(
63    State(app_state): State<AppState>,
64    Path((module_id, assignment_id)): Path<(i64, i64)>,
65) -> impl IntoResponse {
66    let db = app_state.db();
67
68    match assignment::Model::delete(db, assignment_id as i32, module_id as i32).await {
69        Ok(()) => (
70            StatusCode::OK,
71            Json(json!({
72                "success": true,
73                "message": format!("Assignment {} deleted successfully", assignment_id),
74            })),
75        ),
76        Err(e) => (
77            StatusCode::INTERNAL_SERVER_ERROR,
78            Json(json!({
79                "success": false,
80                "message": e.to_string(),
81            })),
82        ),
83    }
84}
85
86/// DELETE /api/modules/:module_id/assignments/bulk
87///
88/// Bulk delete multiple assignments by ID within a module.
89/// Only accessible by lecturers or admins assigned to the module.
90///
91/// ### Path Parameters
92/// - `module_id` (i64): The ID of the module containing the assignments
93///
94/// ### Request Body (JSON)
95/// ```json
96/// {
97///   "assignment_ids": [123, 124, 125]
98/// }
99/// ```
100///
101/// ### Success Response (200 OK)
102/// ```json
103/// {
104///   "success": true,
105///   "data": {
106///     "deleted": 2,
107///     "failed": [
108///       { "id": 125, "error": "Assignment 125 in module 1 not found" }
109///     ]
110///   },
111///   "message": "Deleted 2/3 assignments"
112/// }
113/// ```
114pub async fn bulk_delete_assignments(
115    State(app_state): State<AppState>,
116    Path(module_id): Path<i64>,
117    Json(req): Json<BulkDeleteRequest>,
118) -> impl IntoResponse {
119    let db = app_state.db();
120
121    if req.assignment_ids.is_empty() {
122        return (
123            StatusCode::BAD_REQUEST,
124            Json(ApiResponse::<JsonValue>::error("No assignment IDs provided")),
125        );
126    }
127
128    let mut deleted_count = 0;
129    let mut failed: Vec<JsonValue> = Vec::new();
130
131    for &id in &req.assignment_ids {
132        match assignment::Model::delete(db, id as i32, module_id as i32).await {
133            Ok(_) => deleted_count += 1,
134            Err(e) => {
135                failed.push(json!({
136                    "id": id,
137                    "error": e.to_string()
138                }));
139            }
140        }
141    }
142
143    let message = format!(
144        "Deleted {}/{} assignments",
145        deleted_count,
146        req.assignment_ids.len()
147    );
148
149    let data = json!({
150        "deleted": deleted_count,
151        "failed": failed
152    });
153
154    let response = ApiResponse::success(data, message);
155
156    (
157        StatusCode::OK,
158        Json(response),
159    )
160}