1
/*
2
 * This file is part of mailpot
3
 *
4
 * Copyright 2020 - Manos Pitsidianakis
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as
8
 * published by the Free Software Foundation, either version 3 of the
9
 * License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
 * GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public License
17
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18
 */
19

            
20
//! Named templates, for generated e-mail like confirmations, alerts etc.
21

            
22
use super::*;
23

            
24
impl Connection {
25
    /// Fetch all.
26
    pub fn fetch_templates(&self) -> Result<Vec<DbVal<Template>>> {
27
        let mut stmt = self.connection.prepare("SELECT * FROM templates;")?;
28
        let iter = stmt.query_map(rusqlite::params![], |row| {
29
            let pk = row.get("pk")?;
30
            Ok(DbVal(
31
                Template {
32
                    pk,
33
                    name: row.get("name")?,
34
                    list: row.get("list")?,
35
                    subject: row.get("subject")?,
36
                    headers_json: row.get("headers_json")?,
37
                    body: row.get("body")?,
38
                },
39
                pk,
40
            ))
41
        })?;
42

            
43
        let mut ret = vec![];
44
        for templ in iter {
45
            let templ = templ?;
46
            ret.push(templ);
47
        }
48
        Ok(ret)
49
    }
50

            
51
    /// Fetch a named template.
52
13
    pub fn fetch_template(
53
        &self,
54
        template: &str,
55
        list_pk: Option<i64>,
56
    ) -> Result<Option<DbVal<Template>>> {
57
13
        let mut stmt = self
58
            .connection
59
            .prepare("SELECT * FROM templates WHERE name = ? AND list IS ?;")?;
60
13
        let ret = stmt
61
13
            .query_row(rusqlite::params![&template, &list_pk], |row| {
62
                let pk = row.get("pk")?;
63
                Ok(DbVal(
64
                    Template {
65
                        pk,
66
                        name: row.get("name")?,
67
                        list: row.get("list")?,
68
                        subject: row.get("subject")?,
69
                        headers_json: row.get("headers_json")?,
70
                        body: row.get("body")?,
71
                    },
72
                    pk,
73
                ))
74
            })
75
            .optional()?;
76
13
        if ret.is_none() && list_pk.is_some() {
77
13
            let mut stmt = self
78
                .connection
79
                .prepare("SELECT * FROM templates WHERE name = ? AND list IS NULL;")?;
80
13
            Ok(stmt
81
14
                .query_row(rusqlite::params![&template], |row| {
82
1
                    let pk = row.get("pk")?;
83
1
                    Ok(DbVal(
84
1
                        Template {
85
                            pk,
86
1
                            name: row.get("name")?,
87
1
                            list: row.get("list")?,
88
1
                            subject: row.get("subject")?,
89
1
                            headers_json: row.get("headers_json")?,
90
1
                            body: row.get("body")?,
91
                        },
92
                        pk,
93
                    ))
94
1
                })
95
                .optional()?)
96
13
        } else {
97
            Ok(ret)
98
        }
99
13
    }
100

            
101
    /// Insert a named template.
102
1
    pub fn add_template(&self, template: Template) -> Result<DbVal<Template>> {
103
1
        let mut stmt = self.connection.prepare(
104
            "INSERT INTO templates(name, list, subject, headers_json, body) VALUES(?, ?, ?, ?, ?) \
105
             RETURNING *;",
106
        )?;
107
1
        let ret = stmt
108
            .query_row(
109
1
                rusqlite::params![
110
1
                    &template.name,
111
1
                    &template.list,
112
1
                    &template.subject,
113
1
                    &template.headers_json,
114
1
                    &template.body
115
                ],
116
1
                |row| {
117
1
                    let pk = row.get("pk")?;
118
1
                    Ok(DbVal(
119
1
                        Template {
120
                            pk,
121
1
                            name: row.get("name")?,
122
1
                            list: row.get("list")?,
123
1
                            subject: row.get("subject")?,
124
1
                            headers_json: row.get("headers_json")?,
125
1
                            body: row.get("body")?,
126
                        },
127
                        pk,
128
                    ))
129
1
                },
130
            )
131
            .map_err(|err| {
132
                if matches!(
133
                    err,
134
                    rusqlite::Error::SqliteFailure(
135
                        rusqlite::ffi::Error {
136
                            code: rusqlite::ffi::ErrorCode::ConstraintViolation,
137
                            extended_code: 787
138
                        },
139
                        _
140
                    )
141
                ) {
142
                    Error::from(err).chain_err(|| NotFound("Could not find a list with this pk."))
143
                } else {
144
                    err.into()
145
                }
146
            })?;
147

            
148
1
        trace!("add_template {:?}.", &ret);
149
1
        Ok(ret)
150
1
    }
151

            
152
    /// Remove a named template.
153
1
    pub fn remove_template(&self, template: &str, list_pk: Option<i64>) -> Result<Template> {
154
1
        let mut stmt = self
155
            .connection
156
            .prepare("DELETE FROM templates WHERE name = ? AND list IS ? RETURNING *;")?;
157
2
        let ret = stmt.query_row(rusqlite::params![&template, &list_pk], |row| {
158
1
            Ok(Template {
159
                pk: -1,
160
1
                name: row.get("name")?,
161
1
                list: row.get("list")?,
162
1
                subject: row.get("subject")?,
163
1
                headers_json: row.get("headers_json")?,
164
1
                body: row.get("body")?,
165
            })
166
1
        })?;
167

            
168
1
        trace!(
169
            "remove_template {} list_pk {:?} {:?}.",
170
            template,
171
1
            &list_pk,
172
1
            &ret
173
        );
174
1
        Ok(ret)
175
1
    }
176
}