headless_lms_models/
certificate_configuration_to_requirements.rs

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