headless_lms_server/controllers/main_frontend/
teacher_grading_decisions.rs

1use crate::prelude::*;
2use headless_lms_models::{
3    exercises::get_exercise_by_id,
4    library::user_exercise_state_updater,
5    teacher_grading_decisions::{NewTeacherGradingDecision, TeacherDecisionType},
6    user_exercise_states::UserExerciseState,
7};
8
9/**
10POST `/api/v0/main-frontend/teacher-grading-decisions` - Creates a new teacher grading decision, overriding the points a user has received from an exercise.
11*/
12#[instrument(skip(pool))]
13async fn create_teacher_grading_decision(
14    payload: web::Json<NewTeacherGradingDecision>,
15    pool: web::Data<PgPool>,
16    user: AuthUser,
17) -> ControllerResult<web::Json<Option<UserExerciseState>>> {
18    let action = &payload.action;
19    let exercise_id = payload.exercise_id;
20    let user_exercise_state_id = payload.user_exercise_state_id;
21    let manual_points = payload.manual_points;
22    let justification = &payload.justification;
23    let hidden = payload.hidden;
24    let mut conn = pool.acquire().await?;
25    let token = authorize(
26        &mut conn,
27        Act::Edit,
28        Some(user.id),
29        Res::Exercise(exercise_id),
30    )
31    .await?;
32    let points_given;
33    if *action == TeacherDecisionType::FullPoints {
34        let exercise = get_exercise_by_id(&mut conn, exercise_id).await?;
35        points_given = exercise.score_maximum as f32;
36    } else if *action == TeacherDecisionType::ZeroPoints {
37        points_given = 0.0;
38    } else if *action == TeacherDecisionType::CustomPoints {
39        points_given = manual_points.unwrap_or(0.0);
40    } else if *action == TeacherDecisionType::SuspectedPlagiarism {
41        points_given = 0.0;
42    } else if *action == TeacherDecisionType::RejectAndReset {
43        points_given = 0.0;
44
45        let mut tx = conn.begin().await?;
46
47        let _res = models::teacher_grading_decisions::add_teacher_grading_decision(
48            &mut tx,
49            user_exercise_state_id,
50            *action,
51            points_given,
52            Some(user.id),
53            justification.clone(),
54            hidden,
55        )
56        .await?;
57
58        let student_state =
59            models::user_exercise_states::get_by_id(&mut tx, user_exercise_state_id).await?;
60        let users_and_exercises = vec![(student_state.user_id, vec![exercise_id])];
61
62        let course_id = student_state.course_id.ok_or_else(|| {
63            ControllerError::new(
64                ControllerErrorType::BadRequest,
65                "RejectAndReset requires course_id".to_string(),
66                None,
67            )
68        })?;
69
70        let _reset = models::exercises::reset_exercises_for_selected_users(
71            &mut tx,
72            &users_and_exercises,
73            user.id,
74            course_id,
75        )
76        .await?;
77
78        tx.commit().await?;
79        info!("Teacher took the following action: RejectAndReset.",);
80
81        return token.authorized_ok(web::Json(None));
82    } else {
83        return Err(ControllerError::new(
84            ControllerErrorType::BadRequest,
85            "Invalid query".to_string(),
86            None,
87        ));
88    }
89
90    info!(
91        "Teacher took the following action: {:?}. Points given: {:?}.",
92        &action, points_given
93    );
94
95    let mut tx = conn.begin().await?;
96
97    let _res = models::teacher_grading_decisions::add_teacher_grading_decision(
98        &mut tx,
99        user_exercise_state_id,
100        *action,
101        points_given,
102        Some(user.id),
103        justification.clone(),
104        hidden,
105    )
106    .await?;
107
108    let new_user_exercise_state =
109        user_exercise_state_updater::update_user_exercise_state(&mut tx, user_exercise_state_id)
110            .await?;
111
112    if let Some(course_id) = new_user_exercise_state.course_id {
113        // Since the teacher just reviewed the submission we should mark possible peer review queue entries so that they won't be given to others to review. Receiving peer reviews for this answer now would not make much sense.
114        models::peer_review_queue_entries::remove_queue_entries_for_unusual_reason(
115            &mut tx,
116            new_user_exercise_state.user_id,
117            new_user_exercise_state.exercise_id,
118            course_id,
119        )
120        .await?;
121    }
122
123    tx.commit().await?;
124
125    token.authorized_ok(web::Json(Some(new_user_exercise_state)))
126}
127
128pub fn _add_routes(cfg: &mut ServiceConfig) {
129    cfg.route("", web::post().to(create_teacher_grading_decision));
130}