headless_lms_server/controllers/main_frontend/
teacher_grading_decisions.rs1use 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#[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 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}