1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
use lettre::transport::smtp::Error;

use crate::prelude::*;

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct EmailDelivery {
    pub id: Uuid,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub deleted_at: Option<DateTime<Utc>>,
    pub email_template_id: Uuid,
    pub error: Option<String>,
    pub sent: bool,
    pub user_id: Uuid,
}

pub struct Email {
    pub id: Uuid,
    // TODO: change to user.email when field exists in the db.
    pub to: Uuid,
    pub subject: Option<String>,
    pub body: Option<serde_json::Value>,
}

pub async fn fetch_emails(conn: &mut PgConnection) -> ModelResult<Vec<Email>> {
    let emails = sqlx::query_as!(
        Email,
        "
SELECT ed.id AS id,
  u.id AS to,
  et.subject AS subject,
  et.content AS body
FROM email_deliveries ed
  JOIN email_templates et ON et.id = ed.email_template_id
  JOIN users u ON u.id = ed.user_id
WHERE ed.deleted_at IS NULL
  AND ed.sent = FALSE
  AND ed.error IS NULL
LIMIT 10000;
  ",
    )
    .fetch_all(conn)
    .await?;

    Ok(emails)
}

pub async fn mark_as_sent(email_id: Uuid, conn: &mut PgConnection) -> ModelResult<()> {
    sqlx::query!(
        "
update email_deliveries
set sent = TRUE
where id = $1;
    ",
        email_id
    )
    .execute(conn)
    .await?;

    Ok(())
}

pub async fn save_err_to_email(
    email_id: Uuid,
    err: Error,
    conn: &mut PgConnection,
) -> ModelResult<()> {
    sqlx::query!(
        "
update email_deliveries
set sent = FALSE,
  error = $1
where id = $2;
    ",
        err.to_string(),
        email_id
    )
    .execute(conn)
    .await?;

    Ok(())
}