headless_lms_models/
generated_certificates.rs1use crate::prelude::*;
2use headless_lms_utils as utils;
3
4#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
5#[cfg_attr(feature = "ts_rs", derive(TS))]
6pub struct GeneratedCertificate {
7 pub id: Uuid,
8 pub created_at: DateTime<Utc>,
9 pub updated_at: DateTime<Utc>,
10 pub deleted_at: Option<DateTime<Utc>>,
11 pub user_id: Uuid,
12 pub name_on_certificate: String,
13 pub verification_id: String,
14 pub certificate_configuration_id: Uuid,
15}
16
17pub async fn get_certificate_for_user(
18 conn: &mut PgConnection,
19 user_id: Uuid,
20 certificate_configuration_id: Uuid,
21) -> ModelResult<GeneratedCertificate> {
22 let res = sqlx::query_as!(
23 GeneratedCertificate,
24 "
25SELECT *
26FROM generated_certificates
27WHERE user_id = $1
28 AND certificate_configuration_id = $2
29 AND deleted_at IS NULL
30",
31 user_id,
32 certificate_configuration_id
33 )
34 .fetch_one(conn)
35 .await?;
36 Ok(res)
37}
38pub async fn generate_and_insert(
40 conn: &mut PgConnection,
41 user_id: Uuid,
42 name_on_certificate: &str,
43 certificate_configuration_id: Uuid,
44) -> ModelResult<GeneratedCertificate> {
45 let requirements = crate::certificate_configuration_to_requirements::get_all_requirements_for_certificate_configuration(conn, certificate_configuration_id).await?;
46 if !requirements
48 .has_user_completed_all_requirements(conn, user_id)
49 .await?
50 {
51 return Err(ModelError::new(
52 ModelErrorType::PreconditionFailed,
53 "User has not completed all the requirements to be eligible for this certificate."
54 .to_string(),
55 None,
56 ));
57 }
58
59 if sqlx::query!(
61 "
62SELECT id
63FROM generated_certificates
64WHERE user_id = $1
65 AND certificate_configuration_id = $2
66 AND deleted_at IS NULL
67",
68 user_id,
69 certificate_configuration_id,
70 )
71 .fetch_optional(&mut *conn)
72 .await?
73 .is_some()
74 {
75 return Err(ModelError::new(
77 ModelErrorType::PreconditionFailed,
78 "User already has a certificate for the given module and course instance".to_string(),
79 None,
80 ));
81 }
82
83 let verification_id = generate_verification_id();
84 let res = sqlx::query_as!(
85 GeneratedCertificate,
86 "
87INSERT INTO generated_certificates (
88 user_id,
89 certificate_configuration_id,
90 name_on_certificate,
91 verification_id
92 )
93VALUES ($1, $2, $3, $4)
94RETURNING *
95",
96 user_id,
97 certificate_configuration_id,
98 name_on_certificate,
99 verification_id,
100 )
101 .fetch_one(conn)
102 .await?;
103 Ok(res)
104}
105
106pub async fn get_certificate_by_verification_id(
107 conn: &mut PgConnection,
108 certificate_verification_id: &str,
109) -> ModelResult<GeneratedCertificate> {
110 let res = sqlx::query_as!(
111 GeneratedCertificate,
112 "
113SELECT *
114FROM generated_certificates
115WHERE verification_id = $1
116 AND deleted_at IS NULL
117",
118 certificate_verification_id
119 )
120 .fetch_one(conn)
121 .await?;
122 Ok(res)
123}
124
125fn generate_verification_id() -> String {
126 utils::strings::generate_easily_writable_random_string(15)
127}