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#[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 id: None,
182 components: Vec::from([Component::Button(Button {
183 id: None,
184 custom_id: Some("button-1".to_owned()),
185 disabled: false,
186 emoji: None,
187 style: ButtonStyle::Primary,
188 label: Some("Button".to_owned()),
189 url: None,
190 sku_id: None,
191 })]),
192 })],
193 content: "test".to_owned(),
194 edited_timestamp: Some(Timestamp::from_secs(1_571_573_184).unwrap()),
195 embeds: Vec::new(),
196 kind: MessageType::Regular,
197 flags: None,
198 mentions: Vec::new(),
199 mention_roles: Vec::new(),
200 sticker_items: vec![MessageSticker {
201 format_type: StickerFormatType::Png,
202 id: Id::new(1),
203 name: "sticker name".to_owned(),
204 }],
205 timestamp: Timestamp::from_secs(1_571_573_184).unwrap(),
206 },
207 guild_id: Some(Id::new(1)),
208 };
209
210 serde_test::assert_tokens(
211 &value,
212 &[
213 Token::Struct {
214 name: "MessageSnapshot",
215 len: 2,
216 },
217 Token::Str("message"),
218 Token::Struct {
219 name: "MessageSnapshotFields",
220 len: 8,
221 },
222 Token::Str("attachments"),
223 Token::Seq { len: Some(1) },
224 Token::Struct {
225 name: "Attachment",
226 len: 8,
227 },
228 Token::Str("content_type"),
229 Token::None,
230 Token::Str("filename"),
231 Token::Str("file.jpg"),
232 Token::Str("height"),
233 Token::Some,
234 Token::U64(100),
235 Token::Str("id"),
236 Token::NewtypeStruct { name: "Id" },
237 Token::Str("1"),
238 Token::Str("proxy_url"),
239 Token::Str("https://example.com"),
240 Token::Str("size"),
241 Token::U64(1000),
242 Token::Str("url"),
243 Token::Str("https://example.com"),
244 Token::Str("width"),
245 Token::Some,
246 Token::U64(100),
247 Token::StructEnd,
248 Token::SeqEnd,
249 Token::String("components"),
250 Token::Seq { len: Some(1) },
251 Token::Struct {
252 name: "Component",
253 len: 2,
254 },
255 Token::String("type"),
256 Token::U8(ComponentType::ActionRow.into()),
257 Token::String("components"),
258 Token::Seq { len: Some(1) },
259 Token::Struct {
260 name: "Component",
261 len: 4,
262 },
263 Token::String("type"),
264 Token::U8(2),
265 Token::String("custom_id"),
266 Token::Some,
267 Token::String("button-1"),
268 Token::String("label"),
269 Token::Some,
270 Token::String("Button"),
271 Token::String("style"),
272 Token::U8(1),
273 Token::StructEnd,
274 Token::SeqEnd,
275 Token::StructEnd,
276 Token::SeqEnd,
277 Token::Str("content"),
278 Token::Str("test"),
279 Token::Str("edited_timestamp"),
280 Token::Some,
281 Token::Str("2019-10-20T12:06:24.000000+00:00"),
282 Token::Str("embeds"),
283 Token::Seq { len: Some(0) },
284 Token::SeqEnd,
285 Token::Str("type"),
286 Token::U8(0),
287 Token::Str("sticker_items"),
288 Token::Seq { len: Some(1) },
289 Token::Struct {
290 name: "MessageSticker",
291 len: 3,
292 },
293 Token::Str("format_type"),
294 Token::U8(1),
295 Token::Str("id"),
296 Token::NewtypeStruct { name: "Id" },
297 Token::Str("1"),
298 Token::Str("name"),
299 Token::Str("sticker name"),
300 Token::StructEnd,
301 Token::SeqEnd,
302 Token::Str("timestamp"),
303 Token::Str("2019-10-20T12:06:24.000000+00:00"),
304 Token::StructEnd,
305 Token::Str("guild_id"),
306 Token::Some,
307 Token::NewtypeStruct { name: "Id" },
308 Token::Str("1"),
309 Token::StructEnd,
310 ],
311 );
312 }
313}