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#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
14pub struct MessageSnapshot {
15 pub message: MessageSnapshotFields,
17 #[serde(skip_serializing_if = "Option::is_none")]
19 pub guild_id: Option<Id<GuildMarker>>,
20}
21
22#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
24pub struct MessageSnapshotFields {
25 pub attachments: Vec<Attachment>,
27 #[serde(default, skip_serializing_if = "Vec::is_empty")]
29 pub components: Vec<Component>,
30 pub content: String,
32 pub edited_timestamp: Option<Timestamp>,
34 pub embeds: Vec<Embed>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub flags: Option<MessageFlags>,
39 #[serde(rename = "type")]
41 pub kind: MessageType,
42 #[serde(default, skip_serializing_if = "Vec::is_empty")]
44 pub mentions: Vec<Mention>,
45 #[serde(default, skip_serializing_if = "Vec::is_empty")]
47 pub mention_roles: Vec<Id<RoleMarker>>,
48 #[serde(default, skip_serializing_if = "Vec::is_empty")]
50 pub sticker_items: Vec<MessageSticker>,
51 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}