1use utoipa::ToSchema;
2
3use crate::prelude::*;
4
5#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone, Copy, Type, ToSchema)]
7#[sqlx(
8 type_name = "student_number_verification_method",
9 rename_all = "snake_case"
10)]
11#[serde(rename_all = "snake_case")]
12pub enum StudentNumberVerificationMethod {
13 EmailedLink,
14 EmailMatchFastTrack,
15 AdminManual,
16}
17
18#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
19pub struct VerifiedStudentNumber {
20 pub id: Uuid,
21 pub created_at: DateTime<Utc>,
22 pub updated_at: DateTime<Utc>,
23 pub deleted_at: Option<DateTime<Utc>>,
24 pub user_id: Uuid,
25 pub student_number: String,
26 pub sisu_person_id: String,
27 pub first_names: Option<String>,
28 pub last_name: Option<String>,
29 pub verified_at: DateTime<Utc>,
30 pub verified_via: StudentNumberVerificationMethod,
31 pub verified_via_email: Option<String>,
32 pub verified_via_email_match_field: Option<String>,
33 pub account_email_verified_at: Option<DateTime<Utc>>,
34 pub linked_by_user_id: Option<Uuid>,
35 pub link_reason: Option<String>,
36 pub verified_from_course_id: Option<Uuid>,
37}
38
39#[derive(Debug, Clone, PartialEq)]
40pub struct NewVerifiedStudentNumber {
41 pub user_id: Uuid,
42 pub student_number: String,
43 pub sisu_person_id: String,
44 pub first_names: Option<String>,
45 pub last_name: Option<String>,
46 pub verified_via: StudentNumberVerificationMethod,
47 pub verified_via_email: Option<String>,
49 pub verified_via_email_match_field: Option<String>,
50 pub account_email_verified_at: Option<DateTime<Utc>>,
51 pub linked_by_user_id: Option<Uuid>,
52 pub link_reason: Option<String>,
53 pub verified_from_course_id: Option<Uuid>,
54}
55
56pub async fn insert(
57 conn: &mut PgConnection,
58 pkey_policy: PKeyPolicy<Uuid>,
59 new: &NewVerifiedStudentNumber,
60) -> ModelResult<Uuid> {
61 let res = sqlx::query!(
62 r#"
63INSERT INTO verified_student_numbers (
64 id,
65 user_id,
66 student_number,
67 sisu_person_id,
68 first_names,
69 last_name,
70 verified_via,
71 verified_via_email,
72 verified_via_email_match_field,
73 account_email_verified_at,
74 linked_by_user_id,
75 link_reason,
76 verified_from_course_id
77 )
78VALUES (
79 $1,
80 $2,
81 $3,
82 $4,
83 $5,
84 $6,
85 $7,
86 $8,
87 $9,
88 $10,
89 $11,
90 $12,
91 $13
92 )
93RETURNING id
94 "#,
95 pkey_policy.into_uuid(),
96 new.user_id,
97 new.student_number,
98 new.sisu_person_id,
99 new.first_names,
100 new.last_name,
101 new.verified_via as StudentNumberVerificationMethod,
102 new.verified_via_email,
103 new.verified_via_email_match_field,
104 new.account_email_verified_at,
105 new.linked_by_user_id,
106 new.link_reason,
107 new.verified_from_course_id,
108 )
109 .fetch_one(conn)
110 .await?;
111 Ok(res.id)
112}
113
114pub async fn get_by_id(conn: &mut PgConnection, id: Uuid) -> ModelResult<VerifiedStudentNumber> {
115 let res = sqlx::query_as!(
116 VerifiedStudentNumber,
117 r#"
118SELECT *
119FROM verified_student_numbers
120WHERE id = $1
121 AND deleted_at IS NULL
122 "#,
123 id
124 )
125 .fetch_one(conn)
126 .await?;
127 Ok(res)
128}
129
130pub async fn get_by_user_id(
132 conn: &mut PgConnection,
133 user_id: Uuid,
134) -> ModelResult<Option<VerifiedStudentNumber>> {
135 let res = sqlx::query_as!(
136 VerifiedStudentNumber,
137 r#"
138SELECT *
139FROM verified_student_numbers
140WHERE user_id = $1
141 AND deleted_at IS NULL
142 "#,
143 user_id
144 )
145 .fetch_optional(conn)
146 .await?;
147 Ok(res)
148}
149
150pub async fn get_by_student_number(
151 conn: &mut PgConnection,
152 student_number: &str,
153) -> ModelResult<Option<VerifiedStudentNumber>> {
154 let res = sqlx::query_as!(
155 VerifiedStudentNumber,
156 r#"
157SELECT *
158FROM verified_student_numbers
159WHERE student_number = $1
160 AND deleted_at IS NULL
161 "#,
162 student_number
163 )
164 .fetch_optional(conn)
165 .await?;
166 Ok(res)
167}
168
169pub async fn get_by_user_ids(
170 conn: &mut PgConnection,
171 user_ids: &[Uuid],
172) -> ModelResult<Vec<VerifiedStudentNumber>> {
173 let res = sqlx::query_as!(
174 VerifiedStudentNumber,
175 r#"
176SELECT *
177FROM verified_student_numbers
178WHERE user_id = ANY($1::uuid [])
179 AND deleted_at IS NULL
180 "#,
181 user_ids
182 )
183 .fetch_all(conn)
184 .await?;
185 Ok(res)
186}
187
188pub async fn get_by_student_numbers(
189 conn: &mut PgConnection,
190 student_numbers: &[String],
191) -> ModelResult<Vec<VerifiedStudentNumber>> {
192 let res = sqlx::query_as!(
193 VerifiedStudentNumber,
194 r#"
195SELECT *
196FROM verified_student_numbers
197WHERE student_number = ANY($1::varchar [])
198 AND deleted_at IS NULL
199 "#,
200 student_numbers
201 )
202 .fetch_all(conn)
203 .await?;
204 Ok(res)
205}
206
207pub async fn soft_delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
209 sqlx::query!(
210 r#"
211UPDATE verified_student_numbers
212SET deleted_at = now()
213WHERE id = $1
214 AND deleted_at IS NULL
215 "#,
216 id
217 )
218 .execute(conn)
219 .await?;
220 Ok(())
221}