twilight_model/channel/message/
snapshot.rs

1use crate::{
2    channel::Attachment,
3    id::{marker::GuildMarker, Id},
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                    proxy_url: "https://example.com".to_owned(),
78                    size: 1000,
79                    title: None,
80                    url: "https://example.com".to_owned(),
81                    waveform: None,
82                    width: Some(100),
83                }],
84                components: vec![],
85                content: "test".to_owned(),
86                edited_timestamp: Some(Timestamp::from_secs(1_571_573_184).unwrap()),
87                embeds: Vec::new(),
88                kind: MessageType::Regular,
89                flags: None,
90                mentions: Vec::new(),
91                mention_roles: Vec::new(),
92                sticker_items: Vec::new(),
93                timestamp: Timestamp::from_secs(1_571_573_184).unwrap(),
94            },
95            guild_id: Some(Id::new(1)),
96        };
97
98        serde_test::assert_tokens(
99            &value,
100            &[
101                Token::Struct {
102                    name: "MessageSnapshot",
103                    len: 2,
104                },
105                Token::Str("message"),
106                Token::Struct {
107                    name: "MessageSnapshotFields",
108                    len: 6,
109                },
110                Token::Str("attachments"),
111                Token::Seq { len: Some(1) },
112                Token::Struct {
113                    name: "Attachment",
114                    len: 8,
115                },
116                Token::Str("content_type"),
117                Token::None,
118                Token::Str("filename"),
119                Token::Str("file.jpg"),
120                Token::Str("height"),
121                Token::Some,
122                Token::U64(100),
123                Token::Str("id"),
124                Token::NewtypeStruct { name: "Id" },
125                Token::Str("1"),
126                Token::Str("proxy_url"),
127                Token::Str("https://example.com"),
128                Token::Str("size"),
129                Token::U64(1000),
130                Token::Str("url"),
131                Token::Str("https://example.com"),
132                Token::Str("width"),
133                Token::Some,
134                Token::U64(100),
135                Token::StructEnd,
136                Token::SeqEnd,
137                Token::Str("content"),
138                Token::Str("test"),
139                Token::Str("edited_timestamp"),
140                Token::Some,
141                Token::Str("2019-10-20T12:06:24.000000+00:00"),
142                Token::Str("embeds"),
143                Token::Seq { len: Some(0) },
144                Token::SeqEnd,
145                Token::Str("type"),
146                Token::U8(0),
147                Token::Str("timestamp"),
148                Token::Str("2019-10-20T12:06:24.000000+00:00"),
149                Token::StructEnd,
150                Token::Str("guild_id"),
151                Token::Some,
152                Token::NewtypeStruct { name: "Id" },
153                Token::Str("1"),
154                Token::StructEnd,
155            ],
156        );
157    }
158
159    #[allow(clippy::too_many_lines)]
160    #[test]
161    fn test_message_snapshot_with_sticker_and_components() {
162        let value = MessageSnapshot {
163            message: MessageSnapshotFields {
164                attachments: vec![Attachment {
165                    content_type: None,
166                    description: None,
167                    duration_secs: None,
168                    ephemeral: false,
169                    filename: "file.jpg".to_owned(),
170                    flags: None,
171                    height: Some(100),
172                    id: Id::new(1),
173                    proxy_url: "https://example.com".to_owned(),
174                    size: 1000,
175                    title: None,
176                    url: "https://example.com".to_owned(),
177                    waveform: None,
178                    width: Some(100),
179                }],
180                components: vec![Component::ActionRow(ActionRow {
181                    components: Vec::from([Component::Button(Button {
182                        custom_id: Some("button-1".to_owned()),
183                        disabled: false,
184                        emoji: None,
185                        style: ButtonStyle::Primary,
186                        label: Some("Button".to_owned()),
187                        url: None,
188                        sku_id: None,
189                    })]),
190                })],
191                content: "test".to_owned(),
192                edited_timestamp: Some(Timestamp::from_secs(1_571_573_184).unwrap()),
193                embeds: Vec::new(),
194                kind: MessageType::Regular,
195                flags: None,
196                mentions: Vec::new(),
197                mention_roles: Vec::new(),
198                sticker_items: vec![MessageSticker {
199                    format_type: StickerFormatType::Png,
200                    id: Id::new(1),
201                    name: "sticker name".to_owned(),
202                }],
203                timestamp: Timestamp::from_secs(1_571_573_184).unwrap(),
204            },
205            guild_id: Some(Id::new(1)),
206        };
207
208        serde_test::assert_tokens(
209            &value,
210            &[
211                Token::Struct {
212                    name: "MessageSnapshot",
213                    len: 2,
214                },
215                Token::Str("message"),
216                Token::Struct {
217                    name: "MessageSnapshotFields",
218                    len: 8,
219                },
220                Token::Str("attachments"),
221                Token::Seq { len: Some(1) },
222                Token::Struct {
223                    name: "Attachment",
224                    len: 8,
225                },
226                Token::Str("content_type"),
227                Token::None,
228                Token::Str("filename"),
229                Token::Str("file.jpg"),
230                Token::Str("height"),
231                Token::Some,
232                Token::U64(100),
233                Token::Str("id"),
234                Token::NewtypeStruct { name: "Id" },
235                Token::Str("1"),
236                Token::Str("proxy_url"),
237                Token::Str("https://example.com"),
238                Token::Str("size"),
239                Token::U64(1000),
240                Token::Str("url"),
241                Token::Str("https://example.com"),
242                Token::Str("width"),
243                Token::Some,
244                Token::U64(100),
245                Token::StructEnd,
246                Token::SeqEnd,
247                Token::String("components"),
248                Token::Seq { len: Some(1) },
249                Token::Struct {
250                    name: "Component",
251                    len: 2,
252                },
253                Token::String("type"),
254                Token::U8(ComponentType::ActionRow.into()),
255                Token::String("components"),
256                Token::Seq { len: Some(1) },
257                Token::Struct {
258                    name: "Component",
259                    len: 4,
260                },
261                Token::String("type"),
262                Token::U8(2),
263                Token::String("custom_id"),
264                Token::Some,
265                Token::String("button-1"),
266                Token::String("label"),
267                Token::Some,
268                Token::String("Button"),
269                Token::String("style"),
270                Token::U8(1),
271                Token::StructEnd,
272                Token::SeqEnd,
273                Token::StructEnd,
274                Token::SeqEnd,
275                Token::Str("content"),
276                Token::Str("test"),
277                Token::Str("edited_timestamp"),
278                Token::Some,
279                Token::Str("2019-10-20T12:06:24.000000+00:00"),
280                Token::Str("embeds"),
281                Token::Seq { len: Some(0) },
282                Token::SeqEnd,
283                Token::Str("type"),
284                Token::U8(0),
285                Token::Str("sticker_items"),
286                Token::Seq { len: Some(1) },
287                Token::Struct {
288                    name: "MessageSticker",
289                    len: 3,
290                },
291                Token::Str("format_type"),
292                Token::U8(1),
293                Token::Str("id"),
294                Token::NewtypeStruct { name: "Id" },
295                Token::Str("1"),
296                Token::Str("name"),
297                Token::Str("sticker name"),
298                Token::StructEnd,
299                Token::SeqEnd,
300                Token::Str("timestamp"),
301                Token::Str("2019-10-20T12:06:24.000000+00:00"),
302                Token::StructEnd,
303                Token::Str("guild_id"),
304                Token::Some,
305                Token::NewtypeStruct { name: "Id" },
306                Token::Str("1"),
307                Token::StructEnd,
308            ],
309        );
310    }
311}