twilight_model/channel/message/embed/
mod.rs

1//! Rich message content.
2
3#![allow(missing_docs)]
4mod author;
5mod field;
6mod footer;
7mod image;
8mod provider;
9mod thumbnail;
10mod video;
11
12pub use self::{
13    author::EmbedAuthor, field::EmbedField, footer::EmbedFooter, image::EmbedImage,
14    provider::EmbedProvider, thumbnail::EmbedThumbnail, video::EmbedVideo,
15};
16
17use crate::util::Timestamp;
18use serde::{Deserialize, Serialize};
19
20#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
21pub struct Embed {
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub author: Option<EmbedAuthor>,
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub color: Option<u32>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub description: Option<String>,
28    #[serde(default, skip_serializing_if = "Vec::is_empty")]
29    pub fields: Vec<EmbedField>,
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub footer: Option<EmbedFooter>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub image: Option<EmbedImage>,
34    #[serde(rename = "type")]
35    pub kind: String,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub provider: Option<EmbedProvider>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub thumbnail: Option<EmbedThumbnail>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub timestamp: Option<Timestamp>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    pub title: Option<String>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub url: Option<String>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub video: Option<EmbedVideo>,
48}
49
50#[cfg(test)]
51mod tests {
52    use super::{
53        Embed, EmbedAuthor, EmbedField, EmbedFooter, EmbedImage, EmbedProvider, EmbedThumbnail,
54        EmbedVideo,
55    };
56    use crate::util::datetime::{Timestamp, TimestampParseError};
57    use serde_test::Token;
58    use std::str::FromStr;
59
60    #[test]
61    fn embed() -> Result<(), TimestampParseError> {
62        let timestamp = Timestamp::from_str("2021-08-02T16:56:43.772000+00:00")?;
63
64        let value = Embed {
65            author: None,
66            color: Some(123),
67            description: Some("a description".to_owned()),
68            fields: Vec::new(),
69            footer: None,
70            image: None,
71            kind: "rich".to_owned(),
72            provider: None,
73            thumbnail: None,
74            timestamp: Some(timestamp),
75            title: Some("a title".to_owned()),
76            url: Some("https://example.com".to_owned()),
77            video: None,
78        };
79
80        serde_test::assert_tokens(
81            &value,
82            &[
83                Token::Struct {
84                    name: "Embed",
85                    len: 6,
86                },
87                Token::Str("color"),
88                Token::Some,
89                Token::U32(123),
90                Token::Str("description"),
91                Token::Some,
92                Token::Str("a description"),
93                Token::Str("type"),
94                Token::Str("rich"),
95                Token::Str("timestamp"),
96                Token::Some,
97                Token::Str("2021-08-02T16:56:43.772000+00:00"),
98                Token::Str("title"),
99                Token::Some,
100                Token::Str("a title"),
101                Token::Str("url"),
102                Token::Some,
103                Token::Str("https://example.com"),
104                Token::StructEnd,
105            ],
106        );
107
108        Ok(())
109    }
110
111    #[allow(clippy::too_many_lines)]
112    #[test]
113    fn embed_complete() -> Result<(), TimestampParseError> {
114        let timestamp = Timestamp::from_str("2021-08-02T16:56:43.772000+00:00")?;
115
116        let value = Embed {
117            author: Some(EmbedAuthor {
118                icon_url: Some("https://example.com/1.png".to_owned()),
119                name: "test".to_owned(),
120                proxy_icon_url: Some("https://example.com".to_owned()),
121                url: Some("https://example.com".to_owned()),
122            }),
123            color: Some(123),
124            description: Some("a description".to_owned()),
125            fields: vec![EmbedField {
126                inline: true,
127                name: "name".to_owned(),
128                value: "value".to_owned(),
129            }],
130            footer: Some(EmbedFooter {
131                icon_url: Some("https://example.com/1.png".to_owned()),
132                proxy_icon_url: Some("https://cdn.example.com/1-hash.png".to_owned()),
133                text: "a footer".to_owned(),
134            }),
135            image: Some(EmbedImage {
136                height: Some(1440),
137                proxy_url: Some("https://cdn.example.com/1-hash.png".to_owned()),
138                url: "https://example.com/1.png".to_owned(),
139                width: Some(2560),
140            }),
141            kind: "rich".to_owned(),
142            provider: Some(EmbedProvider {
143                name: Some("Example".to_owned()),
144                url: Some("https://example.com".to_owned()),
145            }),
146            thumbnail: Some(EmbedThumbnail {
147                height: Some(1440),
148                proxy_url: Some("https://cdn.example.com/1-hash.png".to_owned()),
149                url: "https://example.com/1.png".to_owned(),
150                width: Some(2560),
151            }),
152            timestamp: Some(timestamp),
153            title: Some("a title".to_owned()),
154            url: Some("https://example.com".to_owned()),
155            video: Some(EmbedVideo {
156                height: Some(1440),
157                proxy_url: Some("https://proxy.cdn.example.com/1-hash.mp4".to_owned()),
158                url: Some("https://cdn.example.com/1-hash.mp4".to_owned()),
159                width: Some(2560),
160            }),
161        };
162
163        serde_test::assert_tokens(
164            &value,
165            &[
166                Token::Struct {
167                    name: "Embed",
168                    len: 13,
169                },
170                Token::Str("author"),
171                Token::Some,
172                Token::Struct {
173                    name: "EmbedAuthor",
174                    len: 4,
175                },
176                Token::Str("icon_url"),
177                Token::Some,
178                Token::Str("https://example.com/1.png"),
179                Token::Str("name"),
180                Token::Str("test"),
181                Token::Str("proxy_icon_url"),
182                Token::Some,
183                Token::Str("https://example.com"),
184                Token::Str("url"),
185                Token::Some,
186                Token::Str("https://example.com"),
187                Token::StructEnd,
188                Token::Str("color"),
189                Token::Some,
190                Token::U32(123),
191                Token::Str("description"),
192                Token::Some,
193                Token::Str("a description"),
194                Token::Str("fields"),
195                Token::Seq { len: Some(1) },
196                Token::Struct {
197                    name: "EmbedField",
198                    len: 3,
199                },
200                Token::Str("inline"),
201                Token::Bool(true),
202                Token::Str("name"),
203                Token::Str("name"),
204                Token::Str("value"),
205                Token::Str("value"),
206                Token::StructEnd,
207                Token::SeqEnd,
208                Token::Str("footer"),
209                Token::Some,
210                Token::Struct {
211                    name: "EmbedFooter",
212                    len: 3,
213                },
214                Token::Str("icon_url"),
215                Token::Some,
216                Token::Str("https://example.com/1.png"),
217                Token::Str("proxy_icon_url"),
218                Token::Some,
219                Token::Str("https://cdn.example.com/1-hash.png"),
220                Token::Str("text"),
221                Token::Str("a footer"),
222                Token::StructEnd,
223                Token::Str("image"),
224                Token::Some,
225                Token::Struct {
226                    name: "EmbedImage",
227                    len: 4,
228                },
229                Token::Str("height"),
230                Token::Some,
231                Token::U64(1440),
232                Token::Str("proxy_url"),
233                Token::Some,
234                Token::Str("https://cdn.example.com/1-hash.png"),
235                Token::Str("url"),
236                Token::Str("https://example.com/1.png"),
237                Token::Str("width"),
238                Token::Some,
239                Token::U64(2560),
240                Token::StructEnd,
241                Token::Str("type"),
242                Token::Str("rich"),
243                Token::Str("provider"),
244                Token::Some,
245                Token::Struct {
246                    name: "EmbedProvider",
247                    len: 2,
248                },
249                Token::Str("name"),
250                Token::Some,
251                Token::Str("Example"),
252                Token::Str("url"),
253                Token::Some,
254                Token::Str("https://example.com"),
255                Token::StructEnd,
256                Token::Str("thumbnail"),
257                Token::Some,
258                Token::Struct {
259                    name: "EmbedThumbnail",
260                    len: 4,
261                },
262                Token::Str("height"),
263                Token::Some,
264                Token::U64(1440),
265                Token::Str("proxy_url"),
266                Token::Some,
267                Token::Str("https://cdn.example.com/1-hash.png"),
268                Token::Str("url"),
269                Token::Str("https://example.com/1.png"),
270                Token::Str("width"),
271                Token::Some,
272                Token::U64(2560),
273                Token::StructEnd,
274                Token::Str("timestamp"),
275                Token::Some,
276                Token::Str("2021-08-02T16:56:43.772000+00:00"),
277                Token::Str("title"),
278                Token::Some,
279                Token::Str("a title"),
280                Token::Str("url"),
281                Token::Some,
282                Token::Str("https://example.com"),
283                Token::Str("video"),
284                Token::Some,
285                Token::Struct {
286                    name: "EmbedVideo",
287                    len: 4,
288                },
289                Token::Str("height"),
290                Token::Some,
291                Token::U64(1440),
292                Token::Str("proxy_url"),
293                Token::Some,
294                Token::Str("https://proxy.cdn.example.com/1-hash.mp4"),
295                Token::Str("url"),
296                Token::Some,
297                Token::Str("https://cdn.example.com/1-hash.mp4"),
298                Token::Str("width"),
299                Token::Some,
300                Token::U64(2560),
301                Token::StructEnd,
302                Token::StructEnd,
303            ],
304        );
305
306        Ok(())
307    }
308}