headless_lms_server/controllers/main_frontend/
exercise_slide_submissions.rs1use crate::{domain::models_requests, prelude::*};
2use headless_lms_models::exercise_slide_submissions::ExerciseSlideSubmissionInfo;
3use models::{
4 exercises::get_exercise_by_id,
5 teacher_grading_decisions::{
6 NewTeacherGradingDecision, TeacherDecisionType, TeacherGradingDecision,
7 },
8 user_exercise_states::UserExerciseState,
9};
10
11#[instrument(skip(pool))]
15async fn get_submission_info(
16 submission_id: web::Path<Uuid>,
17 pool: web::Data<PgPool>,
18 user: AuthUser,
19) -> ControllerResult<web::Json<ExerciseSlideSubmissionInfo>> {
20 let mut conn = pool.acquire().await?;
21 let token = authorize(
22 &mut conn,
23 Act::Teach,
24 Some(user.id),
25 Res::ExerciseSlideSubmission(*submission_id),
26 )
27 .await?;
28
29 let submission_id_uuid = submission_id.into_inner();
30
31 let submission =
33 models::exercise_slide_submissions::get_by_id(&mut conn, submission_id_uuid).await?;
34
35 let res = models::exercise_slide_submissions::get_exercise_slide_submission_info(
36 &mut conn,
37 submission_id_uuid,
38 submission.user_id,
39 models_requests::fetch_service_info,
40 true,
41 )
42 .await?;
43
44 token.authorized_ok(web::Json(res))
45}
46
47#[derive(Debug, Deserialize)]
48#[cfg_attr(feature = "ts_rs", derive(TS))]
49pub struct ExerciseStateIds {
50 exercise_id: Uuid,
51 user_id: Uuid,
52}
53#[instrument(skip(pool))]
57async fn get_user_exercise_state_info(
58 exam_id: web::Path<Uuid>,
59 pool: web::Data<PgPool>,
60 query_ids: web::Query<ExerciseStateIds>,
61 user: AuthUser,
62) -> ControllerResult<web::Json<UserExerciseState>> {
63 let mut conn = pool.acquire().await?;
64 let token = authorize(&mut conn, Act::Teach, Some(user.id), Res::Exam(*exam_id)).await?;
65
66 let res = models::user_exercise_states::get_or_create_user_exercise_state(
67 &mut conn,
68 query_ids.user_id,
69 query_ids.exercise_id,
70 None,
71 Some(*exam_id),
72 )
73 .await?;
74 token.authorized_ok(web::Json(res))
75}
76
77#[instrument(skip(pool))]
81async fn add_teacher_grading(
82 payload: web::Json<NewTeacherGradingDecision>,
83 pool: web::Data<PgPool>,
84 user: AuthUser,
85) -> ControllerResult<web::Json<TeacherGradingDecision>> {
86 let action = &payload.action;
87 let exercise_id = payload.exercise_id;
88 let user_exercise_state_id = payload.user_exercise_state_id;
89 let manual_points = payload.manual_points;
90 let justification = &payload.justification;
91 let mut conn = pool.acquire().await?;
92 let token = authorize(
93 &mut conn,
94 Act::Edit,
95 Some(user.id),
96 Res::Exercise(exercise_id),
97 )
98 .await?;
99
100 let points_given;
101 if *action == TeacherDecisionType::CustomPoints {
102 let exercise = get_exercise_by_id(&mut conn, exercise_id).await?;
103 let max_points = exercise.score_maximum as f32;
104
105 points_given = manual_points.unwrap_or(0.0);
106
107 if max_points < points_given {
108 return Err(ControllerError::new(
109 ControllerErrorType::BadRequest,
110 "Cannot give more points than maximum score".to_string(),
111 None,
112 ));
113 }
114 } else {
115 return Err(ControllerError::new(
116 ControllerErrorType::BadRequest,
117 "Invalid query".to_string(),
118 None,
119 ));
120 }
121
122 info!(
123 "Teacher took the following action: {:?}. Points given: {:?}.",
124 &action, points_given
125 );
126
127 let mut tx = conn.begin().await?;
128
129 let _res = models::teacher_grading_decisions::add_teacher_grading_decision(
130 &mut tx,
131 user_exercise_state_id,
132 *action,
133 points_given,
134 Some(user.id),
135 justification.clone(),
136 true,
137 )
138 .await?;
139
140 tx.commit().await?;
141
142 token.authorized_ok(web::Json(_res))
143}
144
145pub fn _add_routes(cfg: &mut ServiceConfig) {
146 cfg.route("/{submission_id}/info", web::get().to(get_submission_info))
147 .route(
148 "/{exam_id}/user-exercise-state-info",
149 web::get().to(get_user_exercise_state_info),
150 )
151 .route(
152 "/add-teacher-grading-for-exam-submission",
153 web::put().to(add_teacher_grading),
154 );
155}