Skip to main content

headless_lms_server/domain/credit_registration/
linking_mail_resend.rs

1//! What the teacher- and admin-facing linking mail resend endpoints share: the gate before either
2//! may try, and the wire shape both answer with.
3
4use headless_lms_credit_registration::account_linking;
5use utoipa::ToSchema;
6
7use crate::prelude::*;
8
9/// Refuses a resend while account linking is switched off, or for a course with no credit
10/// registration module configured.
11pub async fn ensure_resend_possible(
12    conn: &mut PgConnection,
13    app_conf: &ApplicationConfiguration,
14    course_id: Uuid,
15) -> Result<(), ControllerError> {
16    if !app_conf.suotar_configuration.account_linking_enabled {
17        return Err(controller_err!(
18            BadRequest,
19            "Account linking is switched off.".to_string()
20        ));
21    }
22    let enabled_module_ids =
23        models::course_modules::get_credit_registration_enabled_ids_for_course(conn, course_id)
24            .await?;
25    if enabled_module_ids.is_empty() {
26        return Err(controller_err!(
27            BadRequest,
28            "This course has no credit registration module configured.".to_string()
29        ));
30    }
31    Ok(())
32}
33
34/// What a resend endpoint tells its caller. Shared wire shape for the teacher- and admin-facing
35/// resend endpoints; `NoStudentNumberKnown` is only ever emitted by the teacher endpoint, whose
36/// target may be an account that has never held a number.
37#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, ToSchema)]
38#[serde(rename_all = "snake_case")]
39pub enum ResendOutcome {
40    /// A mail is owed and will be handed to the sender on the next run.
41    Queued,
42    AlreadyMailedToEveryKnownAddress,
43    /// A cap refused it.
44    RefusedByRateCap,
45    NoAddressInStudyRegistry,
46    NotOnTheCourseRoster,
47    /// The number is already linked to an account, so no linking mail is owed.
48    AlreadyLinked,
49    StudyRegistryUnavailable,
50    /// This account has never had a student number, so there is nothing to look up.
51    NoStudentNumberKnown,
52}
53
54impl From<account_linking::ResendOutcome> for ResendOutcome {
55    fn from(outcome: account_linking::ResendOutcome) -> Self {
56        use account_linking::ResendOutcome as Attempted;
57        match outcome {
58            Attempted::Queued => Self::Queued,
59            Attempted::AlreadyMailedToEveryKnownAddress => Self::AlreadyMailedToEveryKnownAddress,
60            Attempted::RefusedByRateCap => Self::RefusedByRateCap,
61            Attempted::NoAddressInStudyRegistry => Self::NoAddressInStudyRegistry,
62            Attempted::NotOnTheCourseRoster => Self::NotOnTheCourseRoster,
63            Attempted::AlreadyLinked => Self::AlreadyLinked,
64            Attempted::StudyRegistryUnavailable => Self::StudyRegistryUnavailable,
65        }
66    }
67}