Skip to main content

mxr_store/
draft.rs

1use mxr_core::id::*;
2use mxr_core::types::*;
3
4impl super::Store {
5    pub async fn insert_draft(&self, draft: &Draft) -> Result<(), sqlx::Error> {
6        let id = draft.id.as_str();
7        let account_id = draft.account_id.as_str();
8        let to_addrs = serde_json::to_string(&draft.to).unwrap();
9        let cc_addrs = serde_json::to_string(&draft.cc).unwrap();
10        let bcc_addrs = serde_json::to_string(&draft.bcc).unwrap();
11        let attachments = serde_json::to_string(&draft.attachments).unwrap();
12        let in_reply_to = draft
13            .reply_headers
14            .as_ref()
15            .map(|headers| serde_json::to_string(headers).unwrap());
16        let created_at = draft.created_at.timestamp();
17        let updated_at = draft.updated_at.timestamp();
18
19        sqlx::query!(
20            "INSERT INTO drafts (id, account_id, in_reply_to, to_addrs, cc_addrs, bcc_addrs, subject, body_markdown, attachments, created_at, updated_at)
21             VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
22            id,
23            account_id,
24            in_reply_to,
25            to_addrs,
26            cc_addrs,
27            bcc_addrs,
28            draft.subject,
29            draft.body_markdown,
30            attachments,
31            created_at,
32            updated_at,
33        )
34        .execute(self.writer())
35        .await?;
36
37        Ok(())
38    }
39
40    pub async fn get_draft(&self, id: &DraftId) -> Result<Option<Draft>, sqlx::Error> {
41        let id_str = id.as_str();
42        let row = sqlx::query!(
43            r#"SELECT id as "id!", account_id as "account_id!", in_reply_to,
44                      to_addrs as "to_addrs!", cc_addrs as "cc_addrs!", bcc_addrs as "bcc_addrs!",
45                      subject as "subject!", body_markdown as "body_markdown!",
46                      attachments as "attachments!", created_at as "created_at!", updated_at as "updated_at!"
47               FROM drafts WHERE id = ?"#,
48            id_str,
49        )
50        .fetch_optional(self.reader())
51        .await?;
52
53        Ok(row.map(|r| Draft {
54            id: DraftId::from_uuid(uuid::Uuid::parse_str(&r.id).unwrap()),
55            account_id: AccountId::from_uuid(uuid::Uuid::parse_str(&r.account_id).unwrap()),
56            reply_headers: parse_reply_headers(r.in_reply_to),
57            to: serde_json::from_str(&r.to_addrs).unwrap_or_default(),
58            cc: serde_json::from_str(&r.cc_addrs).unwrap_or_default(),
59            bcc: serde_json::from_str(&r.bcc_addrs).unwrap_or_default(),
60            subject: r.subject,
61            body_markdown: r.body_markdown,
62            attachments: serde_json::from_str(&r.attachments).unwrap_or_default(),
63            created_at: chrono::DateTime::from_timestamp(r.created_at, 0).unwrap_or_default(),
64            updated_at: chrono::DateTime::from_timestamp(r.updated_at, 0).unwrap_or_default(),
65        }))
66    }
67
68    pub async fn list_drafts(&self, account_id: &AccountId) -> Result<Vec<Draft>, sqlx::Error> {
69        let aid = account_id.as_str();
70        let rows = sqlx::query!(
71            r#"SELECT id as "id!", account_id as "account_id!", in_reply_to,
72                      to_addrs as "to_addrs!", cc_addrs as "cc_addrs!", bcc_addrs as "bcc_addrs!",
73                      subject as "subject!", body_markdown as "body_markdown!",
74                      attachments as "attachments!", created_at as "created_at!", updated_at as "updated_at!"
75               FROM drafts WHERE account_id = ? ORDER BY updated_at DESC"#,
76            aid,
77        )
78        .fetch_all(self.reader())
79        .await?;
80
81        Ok(rows
82            .into_iter()
83            .map(|r| Draft {
84                id: DraftId::from_uuid(uuid::Uuid::parse_str(&r.id).unwrap()),
85                account_id: AccountId::from_uuid(uuid::Uuid::parse_str(&r.account_id).unwrap()),
86                reply_headers: parse_reply_headers(r.in_reply_to),
87                to: serde_json::from_str(&r.to_addrs).unwrap_or_default(),
88                cc: serde_json::from_str(&r.cc_addrs).unwrap_or_default(),
89                bcc: serde_json::from_str(&r.bcc_addrs).unwrap_or_default(),
90                subject: r.subject,
91                body_markdown: r.body_markdown,
92                attachments: serde_json::from_str(&r.attachments).unwrap_or_default(),
93                created_at: chrono::DateTime::from_timestamp(r.created_at, 0).unwrap_or_default(),
94                updated_at: chrono::DateTime::from_timestamp(r.updated_at, 0).unwrap_or_default(),
95            })
96            .collect())
97    }
98
99    pub async fn delete_draft(&self, id: &DraftId) -> Result<(), sqlx::Error> {
100        let id_str = id.as_str();
101        sqlx::query!("DELETE FROM drafts WHERE id = ?", id_str)
102            .execute(self.writer())
103            .await?;
104        Ok(())
105    }
106}
107
108fn parse_reply_headers(raw: Option<String>) -> Option<ReplyHeaders> {
109    let raw = raw?;
110    serde_json::from_str(&raw).ok().or_else(|| {
111        if raw.trim().is_empty() {
112            None
113        } else {
114            Some(ReplyHeaders {
115                in_reply_to: raw,
116                references: Vec::new(),
117            })
118        }
119    })
120}