headless_lms_models/
email_templates.rs

1use crate::prelude::*;
2
3#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
4#[cfg_attr(feature = "ts_rs", derive(TS))]
5pub struct EmailTemplate {
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 content: Option<serde_json::Value>,
11    pub name: String,
12    pub subject: Option<String>,
13    pub exercise_completions_threshold: Option<i32>,
14    pub points_threshold: Option<i32>,
15    pub course_instance_id: Option<Uuid>,
16    pub language: Option<String>,
17}
18
19#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
20#[cfg_attr(feature = "ts_rs", derive(TS))]
21pub struct EmailTemplateNew {
22    pub name: String,
23    pub language: Option<String>,
24    pub content: Option<serde_json::Value>,
25}
26
27#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
28#[cfg_attr(feature = "ts_rs", derive(TS))]
29pub struct EmailTemplateUpdate {
30    pub name: String,
31    pub subject: String,
32    pub content: serde_json::Value,
33    pub exercise_completions_threshold: Option<i32>,
34    pub points_threshold: Option<i32>,
35}
36
37pub async fn get_email_templates(
38    conn: &mut PgConnection,
39    course_instance_id: Uuid,
40) -> ModelResult<Vec<EmailTemplate>> {
41    let res = sqlx::query_as!(
42        EmailTemplate,
43        "SELECT *
44FROM email_templates
45WHERE course_instance_id = $1
46  AND deleted_at IS NULL",
47        course_instance_id
48    )
49    .fetch_all(conn)
50    .await?;
51    Ok(res)
52}
53
54pub async fn get_generic_email_template_by_name_and_language(
55    conn: &mut PgConnection,
56    name: &str,
57    language: &str,
58) -> ModelResult<EmailTemplate> {
59    let res = sqlx::query_as!(
60        EmailTemplate,
61        r#"
62SELECT *
63FROM email_templates
64WHERE name = $1
65  AND course_instance_id IS NULL
66  AND deleted_at IS NULL
67  AND (language = $2 OR language = 'en' OR language IS NULL)
68ORDER BY CASE
69    WHEN language = $2 THEN 0
70    WHEN language = 'en' THEN 1
71    WHEN language IS NULL THEN 2
72    ELSE 3
73  END
74LIMIT 1
75        "#,
76        name,
77        language
78    )
79    .fetch_one(conn)
80    .await?;
81    Ok(res)
82}
83
84pub async fn insert_email_template(
85    conn: &mut PgConnection,
86    course_instance_id: Option<Uuid>,
87    email_template: EmailTemplateNew,
88    subject: Option<&'_ str>,
89) -> ModelResult<EmailTemplate> {
90    let res = sqlx::query_as!(
91        EmailTemplate,
92        "
93INSERT INTO email_templates (
94    name,
95    course_instance_id,
96    subject,
97    language,
98    content
99  )
100VALUES ($1, $2, $3, $4, $5) ON CONFLICT (name, language)
101WHERE course_instance_id IS NULL
102  AND deleted_at IS NULL DO
103UPDATE
104SET subject = COALESCE(EXCLUDED.subject, email_templates.subject),
105  content = COALESCE(EXCLUDED.content, email_templates.content),
106  updated_at = NOW()
107RETURNING *
108",
109        email_template.name,
110        course_instance_id,
111        subject,
112        email_template.language,
113        email_template.content,
114    )
115    .fetch_one(conn)
116    .await?;
117    Ok(res)
118}
119
120pub async fn get_email_template(
121    conn: &mut PgConnection,
122    email_template_id: Uuid,
123) -> ModelResult<EmailTemplate> {
124    let res = sqlx::query_as!(
125        EmailTemplate,
126        "SELECT *
127FROM email_templates
128WHERE id = $1
129  AND deleted_at IS NULL",
130        email_template_id
131    )
132    .fetch_one(conn)
133    .await?;
134    Ok(res)
135}
136
137pub async fn update_email_template(
138    conn: &mut PgConnection,
139    email_template_id: Uuid,
140    email_template_update: EmailTemplateUpdate,
141) -> ModelResult<EmailTemplate> {
142    let res = sqlx::query_as!(
143        EmailTemplate,
144        r#"
145UPDATE email_templates
146SET name = $1,
147  subject = $2,
148  content = $3,
149  exercise_completions_threshold = $4,
150  points_threshold = $5
151WHERE id = $6
152RETURNING *
153  "#,
154        email_template_update.name,
155        email_template_update.subject,
156        email_template_update.content,
157        email_template_update.exercise_completions_threshold,
158        email_template_update.points_threshold,
159        email_template_id
160    )
161    .fetch_one(conn)
162    .await?;
163    Ok(res)
164}
165
166pub async fn delete_email_template(
167    conn: &mut PgConnection,
168    email_template_id: Uuid,
169) -> ModelResult<EmailTemplate> {
170    let deleted = sqlx::query_as!(
171        EmailTemplate,
172        r#"
173UPDATE email_templates
174SET deleted_at = now()
175WHERE id = $1
176AND deleted_at IS NULL
177RETURNING *
178  "#,
179        email_template_id
180    )
181    .fetch_one(conn)
182    .await?;
183    Ok(deleted)
184}