Skip to main content

twilight_model/channel/message/
snapshot.rs

1use crate::{
2    channel::Attachment,
3    id::{Id, marker::GuildMarker},
4    util::Timestamp,
5};
6
7use super::{Component, Embed, Mention, MessageFlags, MessageSticker, MessageType};
8
9use crate::id::marker::RoleMarker;
10use serde::{Deserialize, Serialize};
11
12/// The snap-shot of a message.
13#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
14pub struct MessageSnapshot {
15    /// Subset of fields in the message object.
16    pub message: MessageSnapshotFields,
17    /// ID of the origin message's guild.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub guild_id: Option<Id<GuildMarker>>,
20}
21
22/// A subset of the fields for a message that has been snap-shotted.
23#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
24pub struct MessageSnapshotFields {
25    /// List of attachments from the message snapshot.
26    pub attachments: Vec<Attachment>,
27    /// Components in the message snapshot.
28    #[serde(default, skip_serializing_if = "Vec::is_empty")]
29    pub components: Vec<Component>,
30    /// Content of the message snapshot.
31    pub content: String,
32    /// When the message was last edited.
33    pub edited_timestamp: Option<Timestamp>,
34    /// List of embeds from the message snapshot.
35    pub embeds: Vec<Embed>,
36    /// Flags of the message.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub flags: Option<MessageFlags>,
39    /// Type of message.
40    #[serde(rename = "type")]
41    pub kind: MessageType,
42    /// Users mentioned in the message snapshot.
43    #[serde(default, skip_serializing_if = "Vec::is_empty")]
44    pub mentions: Vec<Mention>,
45    /// Roles mentioned in the message snapshot.
46    #[serde(default, skip_serializing_if = "Vec::is_empty")]
47    pub mention_roles: Vec<Id<RoleMarker>>,
48    /// Stickers within the message snapshot.
49    #[serde(default, skip_serializing_if = "Vec::is_empty")]
50    pub sticker_items: Vec<MessageSticker>,
51    /// Timestamp of when the message was created.
52    pub timestamp: Timestamp,
53}
54
55#[cfg(test)]
56mod tests {
57    use super::{MessageSnapshot, MessageSnapshotFields};
58    use crate::channel::message::component::{ActionRow, Button, ButtonStyle, ComponentType};
59    use crate::channel::message::sticker::StickerFormatType;
60    use crate::channel::message::{Component, MessageSticker, MessageType};
61    use crate::{channel::Attachment, id::Id, util::Timestamp};
62    use serde_test::Token;
63
64    #[test]
65    fn test_message_snapshot() {
66        let value = MessageSnapshot {
67            message: MessageSnapshotFields {
68                attachments: vec![Attachment {
69                    content_type: None,
70                    description: None,
71                    duration_secs: None,
72                    ephemeral: false,
73                    filename: "file.jpg".to_owned(),
74                    flags: None,
75                    height: Some(100),
76                    id: Id::new(1),
77                    // Thumbhash of the twilight project logo.
78                    placeholder: Some("zSeKDQIoCLiHeIKeiLyfrsBqCIaYaHJ2Vg".to_owned()),
79                    placeholder_version: Some(1),
80                    proxy_url: "https://example.com".to_owned(),
81                    size: 1000,
82                    title: None,
83                    url: "https://example.com".to_owned(),
84                    waveform: None,
85                    width: Some(100),
86                }],
87                components: vec![],
88                content: "test".to_owned(),
89                edited_timestamp: Some(Timestamp::from_secs(1_571_573_184).unwrap()),
90                embeds: Vec::new(),
91                kind: MessageType::Regular,
92                flags: None,
93                mentions: Vec::new(),
94                mention_roles: Vec::new(),
95                sticker_items: Vec::new(),
96                timestamp: Timestamp::from_secs(1_571_573_184).unwrap(),
97            },
98            guild_id: Some(Id::new(1)),
99        };
100
101        serde_test::assert_tokens(
102            &value,
103            &[
104                Token::Struct {
105                    name: "MessageSnapshot",
106                    len: 2,
107                },
108                Token::Str("message"),
109                Token::Struct {
110                    name: "MessageSnapshotFields",
111                    len: 6,
112                },
113                Token::Str("attachments"),
114                Token::Seq { len: Some(1) },
115                Token::Struct {
116                    name: "Attachment",
117                    len: 10,
118                },
119                Token::Str("content_type"),
120                Token::None,
121                Token::Str("filename"),
122                Token::Str("file.jpg"),
123                Token::Str("height"),
124                Token::Some,
125                Token::U64(100),
126                Token::Str("id"),
127                Token::NewtypeStruct { name: "Id" },
128                Token::Str("1"),
129                Token::Str("placeholder"),
130                Token::Some,
131                Token::Str("zSeKDQIoCLiHeIKeiLyfrsBqCIaYaHJ2Vg"),
132                Token::Str("placeholder_version"),
133                Token::Some,
134                Token::U64(1),
135                Token::Str("proxy_url"),
136                Token::Str("https://example.com"),
137                Token::Str("size"),
138                Token::U64(1000),
139                Token::Str("url"),
140                Token::Str("https://example.com"),
141                Token::Str("width"),
142                Token::Some,
143                Token::U64(100),
144                Token::StructEnd,
145                Token::SeqEnd,
146                Token::Str("content"),
147                Token::Str("test"),
148                Token::Str("edited_timestamp"),
149                Token::Some,
150                Token::Str("2019-10-20T12:06:24.000000+00:00"),
151                Token::Str("embeds"),
152                Token::Seq { len: Some(0) },
153                Token::SeqEnd,
154                Token::Str("type"),
155                Token::U8(0),
156                Token::Str("timestamp"),
157                Token::Str("2019-10-20T12:06:24.000000+00:00"),
158                Token::StructEnd,
159                Token::Str("guild_id"),
160                Token::Some,
161                Token::NewtypeStruct { name: "Id" },
162                Token::Str("1"),
163                Token::StructEnd,
164            ],
165        );
166    }
167
168    #[allow(clippy::too_many_lines)]
169    #[test]
170    fn test_message_snapshot_with_sticker_and_components() {
171        let value = MessageSnapshot {
172            message: MessageSnapshotFields {
173                attachments: vec![Attachment {
174                    content_type: None,
175                    description: None,
176                    duration_secs: None,
177                    ephemeral: false,
178                    filename: "file.jpg".to_owned(),
179                    flags: None,
180                    height: Some(100),
181                    id: Id::new(1),
182                    // Thumbhash of the twilight project logo.
183                    placeholder: Some("zSeKDQIoCLiHeIKeiLyfrsBqCIaYaHJ2Vg".to_owned()),
184                    placeholder_version: Some(1),
185                    proxy_url: "https://example.com".to_owned(),
186                    size: 1000,
187                    title: None,
188                    url: "https://example.com".to_owned(),
189                    waveform: None,
190                    width: Some(100),
191                }],
192                components: vec![Component::ActionRow(ActionRow {
193                    id: None,
194                    components: Vec::from([Component::Button(Button {
195                        id: None,
196                        custom_id: Some("button-1".to_owned()),
197                        disabled: false,
198                        emoji: None,
199                        style: ButtonStyle::Primary,
200                        label: Some("Button".to_owned()),
201                        url: None,
202                        sku_id: None,
203                    })]),
204                })],
205                content: "test".to_owned(),
206                edited_timestamp: Some(Timestamp::from_secs(1_571_573_184).unwrap()),
207                embeds: Vec::new(),
208                kind: MessageType::Regular,
209                flags: None,
210                mentions: Vec::new(),
211                mention_roles: Vec::new(),
212                sticker_items: vec![MessageSticker {
213                    format_type: StickerFormatType::Png,
214                    id: Id::new(1),
215                    name: "sticker name".to_owned(),
216                }],
217                timestamp: Timestamp::from_secs(1_571_573_184).unwrap(),
218            },
219            guild_id: Some(Id::new(1)),
220        };
221
222        serde_test::assert_tokens(
223            &value,
224            &[
225                Token::Struct {
226                    name: "MessageSnapshot",
227                    len: 2,
228                },
229                Token::Str("message"),
230                Token::Struct {
231                    name: "MessageSnapshotFields",
232                    len: 8,
233                },
234                Token::Str("attachments"),
235                Token::Seq { len: Some(1) },
236                Token::Struct {
237                    name: "Attachment",
238                    len: 10,
239                },
240                Token::Str("content_type"),
241                Token::None,
242                Token::Str("filename"),
243                Token::Str("file.jpg"),
244                Token::Str("height"),
245                Token::Some,
246                Token::U64(100),
247                Token::Str("id"),
248                Token::NewtypeStruct { name: "Id" },
249                Token::Str("1"),
250                Token::Str("placeholder"),
251                Token::Some,
252                Token::Str("zSeKDQIoCLiHeIKeiLyfrsBqCIaYaHJ2Vg"),
253                Token::Str("placeholder_version"),
254                Token::Some,
255                Token::U64(1),
256                Token::Str("proxy_url"),
257                Token::Str("https://example.com"),
258                Token::Str("size"),
259                Token::U64(1000),
260                Token::Str("url"),
261                Token::Str("https://example.com"),
262                Token::Str("width"),
263                Token::Some,
264                Token::U64(100),
265                Token::StructEnd,
266                Token::SeqEnd,
267                Token::String("components"),
268                Token::Seq { len: Some(1) },
269                Token::Struct {
270                    name: "Component",
271                    len: 2,
272                },
273                Token::String("type"),
274                Token::U8(ComponentType::ActionRow.into()),
275                Token::String("components"),
276                Token::Seq { len: Some(1) },
277                Token::Struct {
278                    name: "Component",
279                    len: 4,
280                },
281                Token::String("type"),
282                Token::U8(2),
283                Token::String("custom_id"),
284                Token::Some,
285                Token::String("button-1"),
286                Token::String("label"),
287                Token::Some,
288                Token::String("Button"),
289                Token::String("style"),
290                Token::U8(1),
291                Token::StructEnd,
292                Token::SeqEnd,
293                Token::StructEnd,
294                Token::SeqEnd,
295                Token::Str("content"),
296                Token::Str("test"),
297                Token::Str("edited_timestamp"),
298                Token::Some,
299                Token::Str("2019-10-20T12:06:24.000000+00:00"),
300                Token::Str("embeds"),
301                Token::Seq { len: Some(0) },
302                Token::SeqEnd,
303                Token::Str("type"),
304                Token::U8(0),
305                Token::Str("sticker_items"),
306                Token::Seq { len: Some(1) },
307                Token::Struct {
308                    name: "MessageSticker",
309                    len: 3,
310                },
311                Token::Str("format_type"),
312                Token::U8(1),
313                Token::Str("id"),
314                Token::NewtypeStruct { name: "Id" },
315                Token::Str("1"),
316                Token::Str("name"),
317                Token::Str("sticker name"),
318                Token::StructEnd,
319                Token::SeqEnd,
320                Token::Str("timestamp"),
321                Token::Str("2019-10-20T12:06:24.000000+00:00"),
322                Token::StructEnd,
323                Token::Str("guild_id"),
324                Token::Some,
325                Token::NewtypeStruct { name: "Id" },
326                Token::Str("1"),
327                Token::StructEnd,
328            ],
329        );
330    }
331}