From e75a2bccb8a2a8d801bbedceb8e555c330642e4d Mon Sep 17 00:00:00 2001 From: "s0wlz (Matthias Puchstein)" Date: Tue, 28 Apr 2026 03:29:13 +0200 Subject: [PATCH] fix(attendance): correct course_id column in slot queries, add patch_json helper --- backend/src/routes/sessions.rs | 30 +++++++++++------------------- backend/src/test_helpers.rs | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/backend/src/routes/sessions.rs b/backend/src/routes/sessions.rs index f723834..951b032 100644 --- a/backend/src/routes/sessions.rs +++ b/backend/src/routes/sessions.rs @@ -4,6 +4,7 @@ use axum::{ routing::{delete, get, patch, post}, Json, Router, }; +use rand::Rng; use serde::Deserialize; use serde_json::{json, Value}; use sqlx::SqlitePool; @@ -16,7 +17,6 @@ use crate::{ fn generate_code() -> String { const CHARS: &[u8] = b"ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; - use rand::Rng; let mut rng = rand::rng(); (0..8) .map(|_| CHARS[rng.random_range(0..CHARS.len())] as char) @@ -132,7 +132,7 @@ async fn create_slot( .fetch_optional(&pool) .await?; if room.is_none() { - return Err(AppError::NotFound); + return Err(AppError::BadRequest("room_id does not exist".into())); } } @@ -174,7 +174,7 @@ async fn update_slot_status( // Fetch the slot + its session's course_id for access check let row: Option<(i64, Option)> = sqlx::query_as( - "SELECT s.id, sl.code + "SELECT s.course_id, sl.code FROM slots sl JOIN sessions s ON s.id = sl.session_id WHERE sl.id = ?", @@ -284,7 +284,7 @@ pub fn router() -> Router { #[cfg(test)] mod tests { use super::*; - use crate::test_helpers::{build_test_app, delete, get, post_json}; + use crate::test_helpers::{build_test_app, delete, get, patch_json, post_json}; use axum::http::StatusCode; use serde_json::{json, Value}; use std::collections::HashSet; @@ -413,21 +413,13 @@ mod tests { .unwrap(); // Open the slot - use axum::http::Request; - use http_body_util::BodyExt; - use tower::ServiceExt; - let req = Request::builder() - .method("PATCH") - .uri(format!("/api/admin/slots/{slot_id}/status")) - .header("Content-Type", "application/json") - .header("Authorization", &auth) - .body(axum::body::Body::from( - json!({"status": "open"}).to_string(), - )) - .unwrap(); - let res = app.clone().oneshot(req).await.unwrap(); - assert_eq!(res.status(), StatusCode::OK); - let body = res.into_body().collect().await.unwrap().to_bytes(); + let (status, body) = patch_json( + app.clone(), + &format!("/api/admin/slots/{slot_id}/status"), + &auth, + json!({"status": "open"}), + ).await; + assert_eq!(status, StatusCode::OK); let slot = serde_json::from_slice::(&body).unwrap(); assert_eq!(slot["status"], "open"); let code = slot["code"].as_str().unwrap(); diff --git a/backend/src/test_helpers.rs b/backend/src/test_helpers.rs index 83088d6..aeb267e 100644 --- a/backend/src/test_helpers.rs +++ b/backend/src/test_helpers.rs @@ -64,6 +64,29 @@ pub async fn put_json(app: Router, uri: &str, auth: &str, body: serde_json::Valu (status, body) } +/// PATCH JSON body to the app (one-shot), returns (StatusCode, response body bytes). +pub async fn patch_json( + app: Router, + uri: &str, + auth: &str, + body: serde_json::Value, +) -> (StatusCode, bytes::Bytes) { + let mut req = Request::builder() + .method("PATCH") + .uri(uri) + .header("Content-Type", "application/json"); + if !auth.is_empty() { + req = req.header("Authorization", auth); + } + let req = req + .body(axum::body::Body::from(body.to_string())) + .unwrap(); + let res = app.oneshot(req).await.unwrap(); + let status = res.status(); + let body = res.into_body().collect().await.unwrap().to_bytes(); + (status, body) +} + /// GET from the app (one-shot), returns (StatusCode, response body bytes). pub async fn get(app: Router, path: &str, auth: &str) -> (StatusCode, bytes::Bytes) { let mut builder = Request::builder()