Skip to main content

headless_lms_models/
certificate_configuration_to_requirements.rs

1use utoipa::ToSchema;
2
3use crate::prelude::*;
4
5#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
6
7pub struct CertificateConfigurationToRequirement {
8    pub id: Uuid,
9    pub created_at: DateTime<Utc>,
10    pub updated_at: DateTime<Utc>,
11    pub deleted_at: Option<DateTime<Utc>>,
12    pub certificate_configuration_id: Uuid,
13    pub course_module_id: Option<Uuid>,
14}
15
16#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
17
18pub struct CertificateAllRequirements {
19    pub certificate_configuration_id: Uuid,
20    pub course_module_ids: Vec<Uuid>,
21}
22
23impl CertificateAllRequirements {
24    /** A certificate configuration is a default configuration if the requirement is only for one course module. These types of configurations are regarded as the default because they are the most commonly used ones. */
25    pub fn is_default_certificate_configuration(&self) -> bool {
26        self.course_module_ids.len() == 1
27    }
28
29    /** Checks if the user has completed all requirements to be eligible for a certificate. */
30    pub async fn has_user_completed_all_requirements(
31        &self,
32        conn: &mut PgConnection,
33        user_id: Uuid,
34    ) -> ModelResult<bool> {
35        let all_users_completions =
36            crate::course_module_completions::get_all_by_user_id(conn, user_id).await?;
37
38        let all_completed_course_module_ids = all_users_completions
39            .iter()
40            .map(|o| o.course_module_id)
41            .collect::<Vec<_>>();
42        // Compare the vecs of completed stuff to the requirements
43        let all_required_course_modules_completed = self
44            .course_module_ids
45            .iter()
46            .all(|id| all_completed_course_module_ids.contains(id));
47        let result = all_required_course_modules_completed;
48        if !result {
49            let missing_course_module_ids = self
50                .course_module_ids
51                .iter()
52                .filter(|id| !all_completed_course_module_ids.contains(id))
53                .collect::<Vec<_>>();
54            warn!(
55                "User {} has not completed all requirements for certificate configuration {}. Missing course module ids: {:?}.",
56                user_id, self.certificate_configuration_id, missing_course_module_ids
57            )
58        }
59        Ok(result)
60    }
61}
62
63pub async fn get_all_requirements_for_certificate_configuration(
64    conn: &mut PgConnection,
65    certificate_configuration_id: Uuid,
66) -> ModelResult<CertificateAllRequirements> {
67    let requirements = sqlx::query_as!(
68        CertificateConfigurationToRequirement,
69        r#"
70SELECT *
71FROM certificate_configuration_to_requirements
72WHERE certificate_configuration_id = $1
73AND deleted_at IS NULL
74        "#,
75        certificate_configuration_id
76    )
77    .fetch_all(conn)
78    .await?;
79    let course_module_ids = requirements
80        .iter()
81        .filter_map(|r| r.course_module_id)
82        .collect();
83
84    Ok(CertificateAllRequirements {
85        certificate_configuration_id,
86        course_module_ids,
87    })
88}
89
90pub async fn insert(
91    conn: &mut PgConnection,
92    certificate_configuration_id: Uuid,
93    course_module_id: Option<Uuid>,
94) -> ModelResult<CertificateConfigurationToRequirement> {
95    let row = sqlx::query_as!(
96        CertificateConfigurationToRequirement,
97        r#"
98INSERT INTO certificate_configuration_to_requirements (
99    certificate_configuration_id,
100    course_module_id
101  )
102VALUES ($1, $2)
103RETURNING *
104        "#,
105        certificate_configuration_id,
106        course_module_id,
107    )
108    .fetch_one(conn)
109    .await?;
110    Ok(row)
111}
112
113pub async fn link_configuration_to_module_if_missing(
114    conn: &mut PgConnection,
115    certificate_configuration_id: Uuid,
116    course_module_id: Uuid,
117) -> ModelResult<()> {
118    sqlx::query!(
119        r#"
120        INSERT INTO certificate_configuration_to_requirements (
121            certificate_configuration_id,
122            course_module_id
123        )
124        SELECT $1, $2
125        WHERE NOT EXISTS (
126            SELECT 1
127            FROM certificate_configuration_to_requirements
128            WHERE certificate_configuration_id = $1
129              AND course_module_id = $2
130              AND deleted_at IS NULL
131        )
132        "#,
133        certificate_configuration_id,
134        course_module_id
135    )
136    .execute(conn)
137    .await?;
138
139    Ok(())
140}