1mod guild;
2mod role;
3
4pub use guild::TemplateGuild;
5pub use role::TemplateRole;
6
7use crate::{
8 id::{
9 Id,
10 marker::{GuildMarker, UserMarker},
11 },
12 user::User,
13 util::Timestamp,
14};
15use serde::{Deserialize, Serialize};
16
17#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
18pub struct Template {
19 pub code: String,
20 pub created_at: Timestamp,
21 pub creator: User,
23 pub creator_id: Id<UserMarker>,
25 pub description: Option<String>,
26 pub is_dirty: Option<bool>,
28 pub name: String,
29 pub serialized_source_guild: TemplateGuild,
30 pub source_guild_id: Id<GuildMarker>,
31 pub updated_at: Timestamp,
32 pub usage_count: u64,
33}
34
35#[cfg(test)]
36mod tests {
37 use super::{Template, TemplateGuild, TemplateRole};
38 use crate::{
39 channel::{
40 Channel, ChannelType,
41 permission_overwrite::{PermissionOverwrite, PermissionOverwriteType},
42 },
43 guild::{
44 AfkTimeout, DefaultMessageNotificationLevel, ExplicitContentFilter, Permissions,
45 SystemChannelFlags, VerificationLevel,
46 },
47 id::Id,
48 test::image_hash,
49 user::{User, UserFlags},
50 util::datetime::{Timestamp, TimestampParseError},
51 };
52 use serde_test::Token;
53 use std::str::FromStr;
54
55 #[test]
56 #[allow(clippy::too_many_lines)]
57 fn test_template() -> Result<(), TimestampParseError> {
58 let created_at = Timestamp::from_str("2021-04-07T14:55:37+00:00")?;
59 let updated_at = Timestamp::from_str("2021-04-07T14:55:37+00:00")?;
60
61 let raw = format!(
62 r#"{{
63 "code": "code",
64 "created_at": "2021-04-07T14:55:37+00:00",
65 "creator": {{
66 "accent_color": null,
67 "avatar": "{avatar}",
68 "banner": "{banner}",
69 "discriminator": "1111",
70 "global_name": "test",
71 "id": "100",
72 "public_flags": 0,
73 "username": "username"
74 }},
75 "creator_id": "100",
76 "description": "description",
77 "is_dirty": null,
78 "name": "name",
79 "serialized_source_guild": {{
80 "afk_channel_id": null,
81 "afk_timeout": 300,
82 "channels": [
83 {{
84 "bitrate": null,
85 "id": 1,
86 "name": "Text Channels",
87 "nsfw": false,
88 "parent_id": null,
89 "permission_overwrites": [],
90 "position": 0,
91 "topic": null,
92 "type": 4
93 }},
94 {{
95 "bitrate": null,
96 "id": 2,
97 "name": "general",
98 "nsfw": false,
99 "parent_id": 1,
100 "permission_overwrites": [
101 {{
102 "allow": "0",
103 "deny": "2048",
104 "id": 1,
105 "type": 0
106 }},
107 {{
108 "allow": "2048",
109 "deny": "0",
110 "id": 2,
111 "type": 0
112 }}
113 ],
114 "position": 0,
115 "rate_limit_per_user": 0,
116 "topic": null,
117 "type": 0
118 }},
119 {{
120 "bitrate": null,
121 "id": 3,
122 "name": "Voice Channels",
123 "nsfw": false,
124 "parent_id": null,
125 "permission_overwrites": [],
126 "position": 0,
127 "topic": null,
128 "type": 4
129 }},
130 {{
131 "bitrate": 64000,
132 "id": 4,
133 "name": "General",
134 "nsfw": false,
135 "parent_id": 3,
136 "permission_overwrites": [],
137 "position": 0,
138 "topic": null,
139 "type": 2,
140 "user_limit": 0
141 }}
142 ],
143 "default_message_notifications": 0,
144 "description": null,
145 "explicit_content_filter": 0,
146 "icon_hash": null,
147 "name": "server name",
148 "preferred_locale": "en-US",
149 "roles": [
150 {{
151 "color": 0,
152 "hoist": false,
153 "id": 200,
154 "mentionable": false,
155 "name": "@everyone",
156 "permissions": "104320577"
157 }},
158 {{
159 "color": 0,
160 "hoist": false,
161 "id": 1,
162 "mentionable": false,
163 "name": "new role",
164 "permissions": "104320577"
165 }}
166 ],
167 "system_channel_flags": 0,
168 "system_channel_id": 2,
169 "verification_level": 0
170 }},
171 "source_guild_id": "200",
172 "updated_at": "2021-04-07T14:55:37+00:00",
173 "usage_count": 0
174}}"#,
175 avatar = image_hash::AVATAR_INPUT,
176 banner = image_hash::BANNER_INPUT
177 );
178
179 let value = Template {
180 code: "code".into(),
181 created_at,
182 creator: User {
183 accent_color: None,
184 avatar: Some(image_hash::AVATAR),
185 avatar_decoration: None,
186 avatar_decoration_data: None,
187 banner: Some(image_hash::BANNER),
188 bot: false,
189 email: None,
190 discriminator: 1111,
191 flags: None,
192 global_name: Some("test".into()),
193 id: Id::new(100),
194 locale: None,
195 mfa_enabled: None,
196 name: "username".into(),
197 premium_type: None,
198 primary_guild: None,
199 public_flags: Some(UserFlags::empty()),
200 system: None,
201 verified: None,
202 },
203 creator_id: Id::new(100),
204 description: Some("description".into()),
205 is_dirty: None,
206 name: "name".into(),
207 serialized_source_guild: TemplateGuild {
208 afk_channel_id: None,
209 afk_timeout: AfkTimeout::FIVE_MINUTES,
210 channels: Vec::from([
211 Channel {
212 application_id: None,
213 applied_tags: None,
214 available_tags: None,
215 bitrate: None,
216 default_auto_archive_duration: None,
217 default_forum_layout: None,
218 default_reaction_emoji: None,
219 default_sort_order: None,
220 default_thread_rate_limit_per_user: None,
221 flags: None,
222 guild_id: None,
223 icon: None,
224 id: Id::new(1),
225 invitable: None,
226 kind: ChannelType::GuildCategory,
227 last_message_id: None,
228 last_pin_timestamp: None,
229 managed: None,
230 member: None,
231 member_count: None,
232 message_count: None,
233 name: Some("Text Channels".into()),
234 newly_created: None,
235 nsfw: Some(false),
236 owner_id: None,
237 parent_id: None,
238 permission_overwrites: Some(vec![]),
239 position: Some(0),
240 rate_limit_per_user: None,
241 recipients: None,
242 rtc_region: None,
243 thread_metadata: None,
244 topic: None,
245 total_message_sent: None,
246 user_limit: None,
247 video_quality_mode: None,
248 },
249 Channel {
250 application_id: None,
251 applied_tags: None,
252 available_tags: None,
253 bitrate: None,
254 default_auto_archive_duration: None,
255 default_forum_layout: None,
256 default_reaction_emoji: None,
257 default_sort_order: None,
258 default_thread_rate_limit_per_user: None,
259 flags: None,
260 guild_id: None,
261 icon: None,
262 id: Id::new(2),
263 invitable: None,
264 kind: ChannelType::GuildText,
265 last_message_id: None,
266 last_pin_timestamp: None,
267 managed: None,
268 member: None,
269 member_count: None,
270 message_count: None,
271 name: Some("general".into()),
272 newly_created: None,
273 nsfw: Some(false),
274 owner_id: None,
275 parent_id: Some(Id::new(1)),
276 permission_overwrites: Some(vec![
277 PermissionOverwrite {
278 allow: Permissions::from_bits(0).unwrap(),
279 deny: Permissions::from_bits(2048).unwrap(),
280 id: Id::new(1),
281 kind: PermissionOverwriteType::Role,
282 },
283 PermissionOverwrite {
284 allow: Permissions::from_bits(2048).unwrap(),
285 deny: Permissions::from_bits(0).unwrap(),
286 id: Id::new(2),
287 kind: PermissionOverwriteType::Role,
288 },
289 ]),
290 position: Some(0),
291 rate_limit_per_user: Some(0),
292 recipients: None,
293 rtc_region: None,
294 thread_metadata: None,
295 topic: None,
296 total_message_sent: None,
297 user_limit: None,
298 video_quality_mode: None,
299 },
300 Channel {
301 application_id: None,
302 applied_tags: None,
303 available_tags: None,
304 bitrate: None,
305 default_auto_archive_duration: None,
306 default_forum_layout: None,
307 default_reaction_emoji: None,
308 default_sort_order: None,
309 default_thread_rate_limit_per_user: None,
310 flags: None,
311 guild_id: None,
312 icon: None,
313 id: Id::new(3),
314 invitable: None,
315 kind: ChannelType::GuildCategory,
316 last_message_id: None,
317 last_pin_timestamp: None,
318 managed: None,
319 member: None,
320 member_count: None,
321 message_count: None,
322 name: Some("Voice Channels".into()),
323 newly_created: None,
324 nsfw: Some(false),
325 owner_id: None,
326 parent_id: None,
327 permission_overwrites: Some(vec![]),
328 position: Some(0),
329 rate_limit_per_user: None,
330 recipients: None,
331 rtc_region: None,
332 thread_metadata: None,
333 topic: None,
334 total_message_sent: None,
335 user_limit: None,
336 video_quality_mode: None,
337 },
338 Channel {
339 application_id: None,
340 applied_tags: None,
341 available_tags: None,
342 bitrate: Some(64000),
343 default_auto_archive_duration: None,
344 default_forum_layout: None,
345 default_reaction_emoji: None,
346 default_sort_order: None,
347 default_thread_rate_limit_per_user: None,
348 flags: None,
349 guild_id: None,
350 icon: None,
351 id: Id::new(4),
352 invitable: None,
353 kind: ChannelType::GuildVoice,
354 last_message_id: None,
355 last_pin_timestamp: None,
356 managed: None,
357 member: None,
358 member_count: None,
359 message_count: None,
360 name: Some("General".into()),
361 newly_created: None,
362 nsfw: Some(false),
363 owner_id: None,
364 parent_id: Some(Id::new(3)),
365 permission_overwrites: Some(vec![]),
366 position: Some(0),
367 rate_limit_per_user: None,
368 recipients: None,
369 rtc_region: None,
370 thread_metadata: None,
371 topic: None,
372 total_message_sent: None,
373 user_limit: Some(0),
374 video_quality_mode: None,
375 },
376 ]),
377 default_message_notifications: DefaultMessageNotificationLevel::All,
378 description: None,
379 explicit_content_filter: ExplicitContentFilter::None,
380 icon_hash: None,
381 name: "server name".into(),
382 preferred_locale: "en-US".into(),
383 roles: vec![
384 TemplateRole {
385 color: 0,
386 hoist: false,
387 id: Id::new(200),
388 mentionable: false,
389 name: "@everyone".into(),
390 permissions: Permissions::CREATE_INVITE
391 | Permissions::ADD_REACTIONS
392 | Permissions::STREAM
393 | Permissions::VIEW_CHANNEL
394 | Permissions::SEND_MESSAGES
395 | Permissions::EMBED_LINKS
396 | Permissions::ATTACH_FILES
397 | Permissions::READ_MESSAGE_HISTORY
398 | Permissions::MENTION_EVERYONE
399 | Permissions::USE_EXTERNAL_EMOJIS
400 | Permissions::CONNECT
401 | Permissions::SPEAK
402 | Permissions::USE_VAD
403 | Permissions::CHANGE_NICKNAME,
404 tags: None,
405 },
406 TemplateRole {
407 color: 0,
408 hoist: false,
409 id: Id::new(1),
410 mentionable: false,
411 name: "new role".into(),
412 permissions: Permissions::CREATE_INVITE
413 | Permissions::ADD_REACTIONS
414 | Permissions::STREAM
415 | Permissions::VIEW_CHANNEL
416 | Permissions::SEND_MESSAGES
417 | Permissions::EMBED_LINKS
418 | Permissions::ATTACH_FILES
419 | Permissions::READ_MESSAGE_HISTORY
420 | Permissions::MENTION_EVERYONE
421 | Permissions::USE_EXTERNAL_EMOJIS
422 | Permissions::CONNECT
423 | Permissions::SPEAK
424 | Permissions::USE_VAD
425 | Permissions::CHANGE_NICKNAME,
426 tags: None,
427 },
428 ],
429 system_channel_flags: SystemChannelFlags::empty(),
430 system_channel_id: Some(Id::new(2)),
431 verification_level: VerificationLevel::None,
432 },
433 source_guild_id: Id::new(200),
434 updated_at,
435 usage_count: 0,
436 };
437
438 let deserialized = serde_json::from_str::<Template>(&raw).unwrap();
439
440 assert_eq!(deserialized, value);
441
442 serde_test::assert_tokens(
443 &value,
444 &[
445 Token::Struct {
446 name: "Template",
447 len: 11,
448 },
449 Token::Str("code"),
450 Token::Str("code"),
451 Token::Str("created_at"),
452 Token::Str("2021-04-07T14:55:37.000000+00:00"),
453 Token::Str("creator"),
454 Token::Struct {
455 name: "User",
456 len: 11,
457 },
458 Token::Str("accent_color"),
459 Token::None,
460 Token::Str("avatar"),
461 Token::Some,
462 Token::Str(image_hash::AVATAR_INPUT),
463 Token::Str("avatar_decoration"),
464 Token::None,
465 Token::Str("avatar_decoration_data"),
466 Token::None,
467 Token::Str("banner"),
468 Token::Some,
469 Token::Str(image_hash::BANNER_INPUT),
470 Token::Str("bot"),
471 Token::Bool(false),
472 Token::Str("discriminator"),
473 Token::Str("1111"),
474 Token::Str("global_name"),
475 Token::Some,
476 Token::Str("test"),
477 Token::Str("id"),
478 Token::NewtypeStruct { name: "Id" },
479 Token::Str("100"),
480 Token::Str("username"),
481 Token::Str("username"),
482 Token::Str("public_flags"),
483 Token::Some,
484 Token::U64(0),
485 Token::StructEnd,
486 Token::Str("creator_id"),
487 Token::NewtypeStruct { name: "Id" },
488 Token::Str("100"),
489 Token::Str("description"),
490 Token::Some,
491 Token::Str("description"),
492 Token::Str("is_dirty"),
493 Token::None,
494 Token::Str("name"),
495 Token::Str("name"),
496 Token::Str("serialized_source_guild"),
497 Token::Struct {
498 name: "TemplateGuild",
499 len: 13,
500 },
501 Token::Str("afk_channel_id"),
502 Token::None,
503 Token::Str("afk_timeout"),
504 Token::NewtypeStruct { name: "AfkTimeout" },
505 Token::U16(300),
506 Token::Str("channels"),
507 Token::Seq { len: Some(4) },
508 Token::Struct {
509 name: "Channel",
510 len: 6,
511 },
512 Token::Str("id"),
513 Token::NewtypeStruct { name: "Id" },
514 Token::Str("1"),
515 Token::Str("type"),
516 Token::U8(4),
517 Token::Str("name"),
518 Token::Some,
519 Token::Str("Text Channels"),
520 Token::Str("nsfw"),
521 Token::Some,
522 Token::Bool(false),
523 Token::Str("permission_overwrites"),
524 Token::Some,
525 Token::Seq { len: Some(0) },
526 Token::SeqEnd,
527 Token::Str("position"),
528 Token::Some,
529 Token::I32(0),
530 Token::StructEnd,
531 Token::Struct {
532 name: "Channel",
533 len: 8,
534 },
535 Token::Str("id"),
536 Token::NewtypeStruct { name: "Id" },
537 Token::Str("2"),
538 Token::Str("type"),
539 Token::U8(0),
540 Token::Str("name"),
541 Token::Some,
542 Token::Str("general"),
543 Token::Str("nsfw"),
544 Token::Some,
545 Token::Bool(false),
546 Token::Str("parent_id"),
547 Token::Some,
548 Token::NewtypeStruct { name: "Id" },
549 Token::Str("1"),
550 Token::Str("permission_overwrites"),
551 Token::Some,
552 Token::Seq { len: Some(2) },
553 Token::Struct {
554 name: "PermissionOverwrite",
555 len: 4,
556 },
557 Token::Str("allow"),
558 Token::Str("0"),
559 Token::Str("deny"),
560 Token::Str("2048"),
561 Token::Str("id"),
562 Token::NewtypeStruct { name: "Id" },
563 Token::Str("1"),
564 Token::Str("type"),
565 Token::U8(0),
566 Token::StructEnd,
567 Token::Struct {
568 name: "PermissionOverwrite",
569 len: 4,
570 },
571 Token::Str("allow"),
572 Token::Str("2048"),
573 Token::Str("deny"),
574 Token::Str("0"),
575 Token::Str("id"),
576 Token::NewtypeStruct { name: "Id" },
577 Token::Str("2"),
578 Token::Str("type"),
579 Token::U8(0),
580 Token::StructEnd,
581 Token::SeqEnd,
582 Token::Str("position"),
583 Token::Some,
584 Token::I32(0),
585 Token::Str("rate_limit_per_user"),
586 Token::Some,
587 Token::U16(0),
588 Token::StructEnd,
589 Token::Struct {
590 name: "Channel",
591 len: 6,
592 },
593 Token::Str("id"),
594 Token::NewtypeStruct { name: "Id" },
595 Token::Str("3"),
596 Token::Str("type"),
597 Token::U8(4),
598 Token::Str("name"),
599 Token::Some,
600 Token::Str("Voice Channels"),
601 Token::Str("nsfw"),
602 Token::Some,
603 Token::Bool(false),
604 Token::Str("permission_overwrites"),
605 Token::Some,
606 Token::Seq { len: Some(0) },
607 Token::SeqEnd,
608 Token::Str("position"),
609 Token::Some,
610 Token::I32(0),
611 Token::StructEnd,
612 Token::Struct {
613 name: "Channel",
614 len: 9,
615 },
616 Token::Str("bitrate"),
617 Token::Some,
618 Token::U32(64000),
619 Token::Str("id"),
620 Token::NewtypeStruct { name: "Id" },
621 Token::Str("4"),
622 Token::Str("type"),
623 Token::U8(2),
624 Token::Str("name"),
625 Token::Some,
626 Token::Str("General"),
627 Token::Str("nsfw"),
628 Token::Some,
629 Token::Bool(false),
630 Token::Str("parent_id"),
631 Token::Some,
632 Token::NewtypeStruct { name: "Id" },
633 Token::Str("3"),
634 Token::Str("permission_overwrites"),
635 Token::Some,
636 Token::Seq { len: Some(0) },
637 Token::SeqEnd,
638 Token::Str("position"),
639 Token::Some,
640 Token::I32(0),
641 Token::Str("user_limit"),
642 Token::Some,
643 Token::U32(0),
644 Token::StructEnd,
645 Token::SeqEnd,
646 Token::Str("default_message_notifications"),
647 Token::U8(0),
648 Token::Str("description"),
649 Token::None,
650 Token::Str("explicit_content_filter"),
651 Token::U8(0),
652 Token::Str("icon_hash"),
653 Token::None,
654 Token::Str("name"),
655 Token::Str("server name"),
656 Token::Str("preferred_locale"),
657 Token::Str("en-US"),
658 Token::Str("roles"),
659 Token::Seq { len: Some(2) },
660 Token::Struct {
661 name: "TemplateRole",
662 len: 6,
663 },
664 Token::Str("color"),
665 Token::U32(0),
666 Token::Str("hoist"),
667 Token::Bool(false),
668 Token::Str("id"),
669 Token::NewtypeStruct { name: "Id" },
670 Token::Str("200"),
671 Token::Str("mentionable"),
672 Token::Bool(false),
673 Token::Str("name"),
674 Token::Str("@everyone"),
675 Token::Str("permissions"),
676 Token::Str("104320577"),
677 Token::StructEnd,
678 Token::Struct {
679 name: "TemplateRole",
680 len: 6,
681 },
682 Token::Str("color"),
683 Token::U32(0),
684 Token::Str("hoist"),
685 Token::Bool(false),
686 Token::Str("id"),
687 Token::NewtypeStruct { name: "Id" },
688 Token::Str("1"),
689 Token::Str("mentionable"),
690 Token::Bool(false),
691 Token::Str("name"),
692 Token::Str("new role"),
693 Token::Str("permissions"),
694 Token::Str("104320577"),
695 Token::StructEnd,
696 Token::SeqEnd,
697 Token::Str("system_channel_flags"),
698 Token::U64(0),
699 Token::Str("system_channel_id"),
700 Token::Some,
701 Token::NewtypeStruct { name: "Id" },
702 Token::Str("2"),
703 Token::Str("verification_level"),
704 Token::U8(0),
705 Token::StructEnd,
706 Token::Str("source_guild_id"),
707 Token::NewtypeStruct { name: "Id" },
708 Token::Str("200"),
709 Token::Str("updated_at"),
710 Token::Str("2021-04-07T14:55:37.000000+00:00"),
711 Token::Str("usage_count"),
712 Token::U64(0),
713 Token::StructEnd,
714 ],
715 );
716
717 Ok(())
718 }
719}