headless_lms_server/controllers/exercise_services/
grading.rs

1use models::exercise_task_gradings::ExerciseTaskGradingResult;
2
3use crate::{domain::models_requests::GradingUpdateClaim, prelude::*};
4
5/**
6POST `/api/v0/exercise-services/grading/grading-update/:submission_id`
7
8Receives a grading update from an exercise service.
9*/
10#[instrument(skip(pool))]
11async fn grading_update(
12    submission_id: web::Path<Uuid>,
13    grading_result: web::Json<ExerciseTaskGradingResult>,
14    grading_update_claim: GradingUpdateClaim,
15    pool: web::Data<PgPool>,
16) -> ControllerResult<web::Json<()>> {
17    // accessed from exercise services, can't authenticate using login,
18    // the upload claim is used to verify requests instead
19    let token = skip_authorize();
20    let grading_result = grading_result.into_inner();
21
22    // Ensure that the claim is valid for this specific submission
23    if *submission_id != grading_update_claim.submission_id() {
24        return Err(ControllerError::new(
25            ControllerErrorType::BadRequest,
26            "Grading upload claim didn't match the submission id".to_string(),
27            None,
28        ));
29    }
30
31    let mut conn = pool.acquire().await?;
32
33    // Add new grading
34    let submission =
35        models::exercise_task_submissions::get_submission(&mut conn, *submission_id).await?;
36    let slide =
37        models::exercise_slides::get_exercise_slide(&mut conn, submission.exercise_slide_id)
38            .await?;
39    let grading = models::exercise_task_gradings::get_by_exercise_task_submission_id(
40        &mut conn,
41        *submission_id,
42    )
43    .await?
44    .ok_or_else(|| {
45        ControllerError::new(
46            ControllerErrorType::BadRequest,
47            "No existing grading for the submission found".to_string(),
48            None,
49        )
50    })?;
51    let exercise = models::exercises::get_by_id(&mut conn, slide.exercise_id).await?;
52    models::exercise_task_gradings::update_grading(&mut conn, &grading, &grading_result, &exercise)
53        .await?;
54
55    token.authorized_ok(web::Json(()))
56}
57
58/**
59Add a route for each controller in this module.
60
61The name starts with an underline in order to appear before other functions in the module documentation.
62
63We add the routes by calling the route method instead of using the route annotations because this method preserves the function signatures for documentation.
64*/
65#[doc(hidden)]
66pub fn _add_routes(cfg: &mut ServiceConfig) {
67    cfg.route(
68        "grading-update/{submission_id}",
69        web::post().to(grading_update),
70    );
71}