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