headless_lms_models/
credit_registration_account_linking_emails.rs1use utoipa::ToSchema;
6
7use crate::prelude::*;
8
9#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ToSchema)]
10pub struct CreditRegistrationAccountLinkingEmail {
11 pub id: Uuid,
12 pub created_at: DateTime<Utc>,
13 pub updated_at: DateTime<Utc>,
14 pub deleted_at: Option<DateTime<Utc>>,
15 pub student_number: String,
16 pub sisu_person_id: String,
17 pub course_id: Uuid,
18 pub emailed_to: String,
19 pub student_number_verification_token_id: Option<Uuid>,
20 pub email_delivery_id: Option<Uuid>,
21 pub sent_at: DateTime<Utc>,
22}
23
24#[derive(Debug, Clone, PartialEq)]
25pub struct NewAccountLinkingEmail {
26 pub student_number: String,
27 pub sisu_person_id: String,
28 pub course_id: Uuid,
29 pub emailed_to: String,
30 pub student_number_verification_token_id: Option<Uuid>,
31 pub email_delivery_id: Option<Uuid>,
32}
33
34pub async fn claim_send_slot(
39 conn: &mut PgConnection,
40 new: &NewAccountLinkingEmail,
41) -> ModelResult<Option<Uuid>> {
42 let res = sqlx::query!(
43 r#"
44INSERT INTO credit_registration_account_linking_emails (
45 student_number,
46 sisu_person_id,
47 course_id,
48 emailed_to,
49 student_number_verification_token_id,
50 email_delivery_id
51 )
52VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT DO NOTHING
53RETURNING id
54 "#,
55 new.student_number,
56 new.sisu_person_id,
57 new.course_id,
58 new.emailed_to,
59 new.student_number_verification_token_id,
60 new.email_delivery_id,
61 )
62 .fetch_optional(conn)
63 .await?;
64 Ok(res.map(|r| r.id))
65}
66
67pub async fn get_by_course_id(
68 conn: &mut PgConnection,
69 course_id: Uuid,
70) -> ModelResult<Vec<CreditRegistrationAccountLinkingEmail>> {
71 let res = sqlx::query_as!(
72 CreditRegistrationAccountLinkingEmail,
73 r#"
74SELECT *
75FROM credit_registration_account_linking_emails
76WHERE course_id = $1
77 AND deleted_at IS NULL
78ORDER BY sent_at DESC
79 "#,
80 course_id
81 )
82 .fetch_all(conn)
83 .await?;
84 Ok(res)
85}
86
87pub async fn get_by_sisu_person_id(
88 conn: &mut PgConnection,
89 sisu_person_id: &str,
90) -> ModelResult<Vec<CreditRegistrationAccountLinkingEmail>> {
91 let res = sqlx::query_as!(
92 CreditRegistrationAccountLinkingEmail,
93 r#"
94SELECT *
95FROM credit_registration_account_linking_emails
96WHERE sisu_person_id = $1
97 AND deleted_at IS NULL
98ORDER BY sent_at DESC
99 "#,
100 sisu_person_id
101 )
102 .fetch_all(conn)
103 .await?;
104 Ok(res)
105}
106
107pub async fn count_sent_since(
109 conn: &mut PgConnection,
110 sisu_person_id: &str,
111 since: DateTime<Utc>,
112) -> ModelResult<i64> {
113 let count = sqlx::query_scalar!(
114 r#"
115SELECT COUNT(*) AS "count!"
116FROM credit_registration_account_linking_emails
117WHERE sisu_person_id = $1
118 AND sent_at >= $2
119 AND deleted_at IS NULL
120 "#,
121 sisu_person_id,
122 since,
123 )
124 .fetch_one(conn)
125 .await?;
126 Ok(count)
127}
128
129pub async fn count_sent_for_person_and_course(
132 conn: &mut PgConnection,
133 sisu_person_id: &str,
134 course_id: Uuid,
135) -> ModelResult<i64> {
136 let count = sqlx::query_scalar!(
137 r#"
138SELECT COUNT(*) AS "count!"
139FROM credit_registration_account_linking_emails
140WHERE sisu_person_id = $1
141 AND course_id = $2
142 AND deleted_at IS NULL
143 "#,
144 sisu_person_id,
145 course_id,
146 )
147 .fetch_one(conn)
148 .await?;
149 Ok(count)
150}
151
152pub async fn soft_delete(conn: &mut PgConnection, id: Uuid) -> ModelResult<()> {
154 sqlx::query!(
155 r#"
156UPDATE credit_registration_account_linking_emails
157SET deleted_at = now()
158WHERE id = $1
159 AND deleted_at IS NULL
160 "#,
161 id
162 )
163 .execute(conn)
164 .await?;
165 Ok(())
166}