headless_lms_server/controllers/main_frontend/course_credit_registrations/
enrolment_recheck.rs1use headless_lms_models::credit_registration_admin_actions::{
4 COURSE_TEACHER_ROLE, CreditRegistrationAdminAction, CreditRegistrationAdminActionTarget,
5 NewCreditRegistrationAdminAction,
6};
7use headless_lms_models::credit_registration_events::CreditRegistrationEventKind;
8use headless_lms_models::credit_registrations::CreditRegistrationState;
9
10use headless_lms_models::library::credit_registration::enrolment_check_schedule::EnrolmentCheckSource;
11use headless_lms_models::library::credit_registration::enrolment_checks::CheckRequestOutcome;
12
13use crate::controllers::main_frontend::credit_registrations::RequestCreditRegistrationEnrolmentRecheckResult;
14use crate::domain::credit_registration::enrolment_recheck::{
15 RecheckTarget, start_enrolment_recheck,
16};
17use crate::domain::error::missing_controller_error;
18use crate::prelude::*;
19
20#[instrument(skip(pool))]
30#[utoipa::path(
31 post,
32 path = "/registrations/{credit_registration_id}/recheck-enrolment",
33 operation_id = "recheckCreditRegistrationEnrolment",
34 tag = "course-credit-registrations",
35 params(("credit_registration_id" = Uuid, Path, description = "Credit registration id")),
36 responses(
37 (status = 200, description = "Whether a recheck was started", body = RequestCreditRegistrationEnrolmentRecheckResult),
38 (status = 400, description = "The registration is not waiting for an enrolment"),
39 (status = 404, description = "No such registration")
40 )
41)]
42pub async fn recheck_credit_registration_enrolment(
43 user: AuthUser,
44 pool: web::Data<PgPool>,
45 credit_registration_id: web::Path<Uuid>,
46) -> ControllerResult<web::Json<RequestCreditRegistrationEnrolmentRecheckResult>> {
47 let mut conn = pool.acquire().await?;
48 let id = *credit_registration_id;
49 let row = models::credit_registrations::get_teacher_facing_by_id(&mut conn, id)
50 .await?
51 .ok_or_else(missing_controller_error(
52 ControllerErrorType::NotFound,
53 "Not found.".to_string(),
54 ))?;
55 let token =
56 super::authorize_credit_registration_teacher(&mut conn, user.id, row.course_id).await?;
57
58 if row.state != CreditRegistrationState::NoUsableEnrolment {
59 return Err(controller_err!(
60 BadRequest,
61 "This registration is not waiting for an enrolment.".to_string()
62 ));
63 }
64 let mut tx = conn.begin().await?;
65 let outcome = start_enrolment_recheck(
66 &mut tx,
67 user.id,
68 RecheckTarget {
69 registration_id: id,
70 course_module_completion_id: row.course_module_completion_id,
71 },
72 EnrolmentCheckSource::TeacherRequest,
73 CreditRegistrationEventKind::AdminAction,
74 "A teacher of the course asked us to check for an enrolment again.",
75 )
76 .await?;
77 if matches!(
78 outcome,
79 CheckRequestOutcome::TooSoon | CheckRequestOutcome::NotWaiting
80 ) {
81 tx.commit().await?;
82 return token.authorized_ok(web::Json(RequestCreditRegistrationEnrolmentRecheckResult {
83 recheck_started: false,
84 }));
85 }
86 models::credit_registration_admin_actions::record(
87 &mut tx,
88 &NewCreditRegistrationAdminAction {
89 target_id: Some(id),
90 actor_course_id: Some(row.course_id),
91 before_state: Some(row.state),
92 affected_row_count: Some(1),
93 ..NewCreditRegistrationAdminAction::new(
94 CreditRegistrationAdminAction::ForceRecheck,
95 CreditRegistrationAdminActionTarget::CreditRegistration,
96 user.id,
97 COURSE_TEACHER_ROLE,
98 )
99 },
100 )
101 .await?;
102 tx.commit().await?;
103
104 token.authorized_ok(web::Json(RequestCreditRegistrationEnrolmentRecheckResult {
105 recheck_started: outcome.started_check(),
106 }))
107}
108
109pub fn _add_routes(cfg: &mut ServiceConfig) {
110 cfg.route(
111 "/registrations/{credit_registration_id}/recheck-enrolment",
112 web::post().to(recheck_credit_registration_enrolment),
113 );
114}