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
use super::*;
21

            
22
#[derive(Debug, PartialEq, Eq, Clone, serde::Deserialize, serde::Serialize)]
23
pub struct Crumb {
24
    pub label: Cow<'static, str>,
25
    #[serde(serialize_with = "to_safe_string")]
26
    pub url: Cow<'static, str>,
27
}
28

            
29
#[derive(Debug, Default, Hash, Copy, Clone, serde::Deserialize, serde::Serialize)]
30
pub enum Level {
31
    Success,
32
    #[default]
33
    Info,
34
    Warning,
35
    Error,
36
}
37

            
38
#[derive(Debug, Hash, Clone, serde::Deserialize, serde::Serialize)]
39
pub struct Message {
40
    pub message: Cow<'static, str>,
41
    #[serde(default)]
42
    pub level: Level,
43
}
44

            
45
impl Message {
46
    const MESSAGE_KEY: &str = "session-message";
47
}
48

            
49
pub trait SessionMessages {
50
    fn drain_messages(&mut self) -> Vec<Message>;
51
    fn add_message(&mut self, _: Message) -> Result<(), ResponseError>;
52
}
53

            
54
impl SessionMessages for WritableSession {
55
    fn drain_messages(&mut self) -> Vec<Message> {
56
        let ret = self.get(Message::MESSAGE_KEY).unwrap_or_default();
57
        self.remove(Message::MESSAGE_KEY);
58
        ret
59
    }
60

            
61
    #[allow(clippy::significant_drop_tightening)]
62
    fn add_message(&mut self, message: Message) -> Result<(), ResponseError> {
63
        let mut messages: Vec<Message> = self.get(Message::MESSAGE_KEY).unwrap_or_default();
64
        messages.push(message);
65
        self.insert(Message::MESSAGE_KEY, messages)?;
66
        Ok(())
67
    }
68
}
69

            
70
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Hash)]
71
#[repr(transparent)]
72
pub struct IntPOST(pub i64);
73

            
74
impl serde::Serialize for IntPOST {
75
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76
    where
77
        S: serde::Serializer,
78
    {
79
        serializer.serialize_i64(self.0)
80
    }
81
}
82

            
83
impl<'de> serde::Deserialize<'de> for IntPOST {
84
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
85
    where
86
        D: serde::Deserializer<'de>,
87
    {
88
        struct IntVisitor;
89

            
90
        impl<'de> serde::de::Visitor<'de> for IntVisitor {
91
            type Value = IntPOST;
92

            
93
            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
94
                f.write_str("Int as a number or string")
95
            }
96

            
97
            fn visit_i64<E>(self, int: i64) -> Result<Self::Value, E>
98
            where
99
                E: serde::de::Error,
100
            {
101
                Ok(IntPOST(int))
102
            }
103

            
104
            fn visit_str<E>(self, int: &str) -> Result<Self::Value, E>
105
            where
106
                E: serde::de::Error,
107
            {
108
                int.parse().map(IntPOST).map_err(serde::de::Error::custom)
109
            }
110
        }
111

            
112
        deserializer.deserialize_any(IntVisitor)
113
    }
114
}
115

            
116
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Hash)]
117
#[repr(transparent)]
118
pub struct BoolPOST(pub bool);
119

            
120
impl serde::Serialize for BoolPOST {
121
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
122
    where
123
        S: serde::Serializer,
124
    {
125
        serializer.serialize_bool(self.0)
126
    }
127
}
128

            
129
impl<'de> serde::Deserialize<'de> for BoolPOST {
130
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
131
    where
132
        D: serde::Deserializer<'de>,
133
    {
134
        struct BoolVisitor;
135

            
136
        impl<'de> serde::de::Visitor<'de> for BoolVisitor {
137
            type Value = BoolPOST;
138

            
139
            fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
140
                f.write_str("Bool as a boolean or \"true\" \"false\"")
141
            }
142

            
143
            fn visit_bool<E>(self, val: bool) -> Result<Self::Value, E>
144
            where
145
                E: serde::de::Error,
146
            {
147
                Ok(BoolPOST(val))
148
            }
149

            
150
            fn visit_str<E>(self, val: &str) -> Result<Self::Value, E>
151
            where
152
                E: serde::de::Error,
153
            {
154
                val.parse().map(BoolPOST).map_err(serde::de::Error::custom)
155
            }
156
        }
157

            
158
        deserializer.deserialize_any(BoolVisitor)
159
    }
160
}
161

            
162
#[derive(Debug, Clone, serde::Deserialize)]
163
pub struct Next {
164
    #[serde(default, deserialize_with = "empty_string_as_none")]
165
    pub next: Option<String>,
166
}
167

            
168
impl Next {
169
    #[inline]
170
    pub fn or_else(self, cl: impl FnOnce() -> String) -> Redirect {
171
        self.next
172
            .map_or_else(|| Redirect::to(&cl()), |next| Redirect::to(&next))
173
    }
174
}
175

            
176
/// Serde deserialization decorator to map empty Strings to None,
177
fn empty_string_as_none<'de, D, T>(de: D) -> Result<Option<T>, D::Error>
178
where
179
    D: serde::Deserializer<'de>,
180
    T: std::str::FromStr,
181
    T::Err: std::fmt::Display,
182
{
183
    use serde::Deserialize;
184
    let opt = Option::<String>::deserialize(de)?;
185
    match opt.as_deref() {
186
        None | Some("") => Ok(None),
187
        Some(s) => std::str::FromStr::from_str(s)
188
            .map_err(serde::de::Error::custom)
189
            .map(Some),
190
    }
191
}
192

            
193
/// Serialize string to [`minijinja::value::Value`] with
194
/// [`minijinja::value::Value::from_safe_string`].
195
pub fn to_safe_string<S>(s: impl AsRef<str>, ser: S) -> Result<S::Ok, S::Error>
196
where
197
    S: serde::Serializer,
198
{
199
    use serde::Serialize;
200
    let s = s.as_ref();
201
    Value::from_safe_string(s.to_string()).serialize(ser)
202
}
203

            
204
/// Serialize an optional string to [`minijinja::value::Value`] with
205
/// [`minijinja::value::Value::from_safe_string`].
206
pub fn to_safe_string_opt<S>(s: &Option<String>, ser: S) -> Result<S::Ok, S::Error>
207
where
208
    S: serde::Serializer,
209
{
210
    use serde::Serialize;
211
    s.as_ref()
212
        .map(|s| Value::from_safe_string(s.to_string()))
213
        .serialize(ser)
214
}