headless_lms_models/
code_giveaways.rs1use crate::prelude::*;
2
3#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
4#[cfg_attr(feature = "ts_rs", derive(TS))]
5pub struct CodeGiveaway {
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 course_id: Uuid,
11 pub course_module_id: Option<Uuid>,
12 pub require_course_specific_consent_form_question_id: Option<Uuid>,
13 pub enabled: bool,
14 pub name: String,
15}
16
17#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
18#[cfg_attr(feature = "ts_rs", derive(TS))]
19pub struct NewCodeGiveaway {
20 pub course_id: Uuid,
21 pub name: String,
22 pub course_module_id: Option<Uuid>,
23 pub require_course_specific_consent_form_question_id: Option<Uuid>,
24}
25
26#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
27#[cfg_attr(feature = "ts_rs", derive(TS))]
28#[serde(tag = "tag")]
29pub enum CodeGiveawayStatus {
30 Disabled,
31 NotEligible,
32 Eligible { codes_left: bool },
33 AlreadyGottenCode { given_code: String },
34}
35
36pub async fn insert(conn: &mut PgConnection, input: &NewCodeGiveaway) -> ModelResult<CodeGiveaway> {
37 let res = sqlx::query_as!(
38 CodeGiveaway,
39 r#"
40INSERT INTO code_giveaways (course_id, name, course_module_id, require_course_specific_consent_form_question_id)
41VALUES ($1, $2, $3, $4)
42RETURNING *
43 "#,
44 input.course_id,
45 input.name,
46 input.course_module_id,
47 input.require_course_specific_consent_form_question_id
48 )
49 .fetch_one(&mut *conn)
50 .await?;
51
52 Ok(res)
53}
54
55pub async fn get_all_for_course(
56 conn: &mut PgConnection,
57 course_id: Uuid,
58) -> ModelResult<Vec<CodeGiveaway>> {
59 let res = sqlx::query_as!(
60 CodeGiveaway,
61 r#"
62SELECT *
63FROM code_giveaways
64WHERE course_id = $1
65 AND deleted_at IS NULL
66"#,
67 course_id
68 )
69 .fetch_all(&mut *conn)
70 .await?;
71
72 Ok(res)
73}
74
75pub async fn get_by_id(conn: &mut PgConnection, id: Uuid) -> ModelResult<CodeGiveaway> {
76 let res = sqlx::query_as!(
77 CodeGiveaway,
78 r#"
79SELECT *
80FROM code_giveaways
81WHERE id = $1
82"#,
83 id
84 )
85 .fetch_one(&mut *conn)
86 .await?;
87
88 Ok(res)
89}
90
91pub async fn set_enabled(
92 conn: &mut PgConnection,
93 id: Uuid,
94 enabled: bool,
95) -> ModelResult<CodeGiveaway> {
96 let res = sqlx::query_as!(
97 CodeGiveaway,
98 r#"
99UPDATE code_giveaways
100SET enabled = $2
101WHERE id = $1
102RETURNING *
103"#,
104 id,
105 enabled
106 )
107 .fetch_one(&mut *conn)
108 .await?;
109
110 Ok(res)
111}
112
113pub async fn get_code_giveaway_status(
114 conn: &mut PgConnection,
115 code_giveaway_id: Uuid,
116 user_id: Uuid,
117) -> ModelResult<CodeGiveawayStatus> {
118 let code_giveaway = get_by_id(conn, code_giveaway_id).await?;
119 if !code_giveaway.enabled {
120 return Ok(CodeGiveawayStatus::Disabled);
121 }
122
123 if let Some(course_module_id) = code_giveaway.course_module_id {
124 let course_module_completions =
125 crate::course_module_completions::get_all_by_user_id_and_course_module_id(
126 conn,
127 user_id,
128 course_module_id,
129 )
130 .await?;
131
132 if !course_module_completions.iter().any(|c| c.passed) {
133 return Ok(CodeGiveawayStatus::NotEligible);
134 }
135 } else {
136 warn!(
137 "Code giveaway {} does not have a course module requirement",
138 code_giveaway_id
139 );
140 return Ok(CodeGiveawayStatus::Disabled);
141 }
142 if let Some(question_id) = code_giveaway.require_course_specific_consent_form_question_id {
143 let research_form_answers =
144 crate::research_forms::get_all_research_form_answers_with_user_course_and_question_id(
145 conn,
146 user_id,
147 code_giveaway.course_id,
148 question_id,
149 )
150 .await?;
151
152 if !research_form_answers.iter().any(|a| a.research_consent) {
153 return Ok(CodeGiveawayStatus::NotEligible);
154 }
155 }
156 let already_given_code =
157 crate::code_giveaway_codes::get_code_given_to_user(conn, code_giveaway_id, user_id).await?;
158
159 if let Some(code) = already_given_code {
160 return Ok(CodeGiveawayStatus::AlreadyGottenCode {
161 given_code: code.code,
162 });
163 }
164
165 let codes_left = crate::code_giveaway_codes::are_any_codes_left(conn, code_giveaway_id).await?;
166
167 Ok(CodeGiveawayStatus::Eligible { codes_left })
168}