twilight_model/guild/template/
mod.rs

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    /// User object of who created this template.
22    pub creator: User,
23    /// ID of the user who created this template.
24    pub creator_id: Id<UserMarker>,
25    pub description: Option<String>,
26    /// Whether the template has unsynced changes.
27    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                        user_limit: None,
246                        video_quality_mode: None,
247                    },
248                    Channel {
249                        application_id: None,
250                        applied_tags: None,
251                        available_tags: None,
252                        bitrate: None,
253                        default_auto_archive_duration: None,
254                        default_forum_layout: None,
255                        default_reaction_emoji: None,
256                        default_sort_order: None,
257                        default_thread_rate_limit_per_user: None,
258                        flags: None,
259                        guild_id: None,
260                        icon: None,
261                        id: Id::new(2),
262                        invitable: None,
263                        kind: ChannelType::GuildText,
264                        last_message_id: None,
265                        last_pin_timestamp: None,
266                        managed: None,
267                        member: None,
268                        member_count: None,
269                        message_count: None,
270                        name: Some("general".into()),
271                        newly_created: None,
272                        nsfw: Some(false),
273                        owner_id: None,
274                        parent_id: Some(Id::new(1)),
275                        permission_overwrites: Some(vec![
276                            PermissionOverwrite {
277                                allow: Permissions::from_bits(0).unwrap(),
278                                deny: Permissions::from_bits(2048).unwrap(),
279                                id: Id::new(1),
280                                kind: PermissionOverwriteType::Role,
281                            },
282                            PermissionOverwrite {
283                                allow: Permissions::from_bits(2048).unwrap(),
284                                deny: Permissions::from_bits(0).unwrap(),
285                                id: Id::new(2),
286                                kind: PermissionOverwriteType::Role,
287                            },
288                        ]),
289                        position: Some(0),
290                        rate_limit_per_user: Some(0),
291                        recipients: None,
292                        rtc_region: None,
293                        thread_metadata: None,
294                        topic: None,
295                        user_limit: None,
296                        video_quality_mode: None,
297                    },
298                    Channel {
299                        application_id: None,
300                        applied_tags: None,
301                        available_tags: None,
302                        bitrate: None,
303                        default_auto_archive_duration: None,
304                        default_forum_layout: None,
305                        default_reaction_emoji: None,
306                        default_sort_order: None,
307                        default_thread_rate_limit_per_user: None,
308                        flags: None,
309                        guild_id: None,
310                        icon: None,
311                        id: Id::new(3),
312                        invitable: None,
313                        kind: ChannelType::GuildCategory,
314                        last_message_id: None,
315                        last_pin_timestamp: None,
316                        managed: None,
317                        member: None,
318                        member_count: None,
319                        message_count: None,
320                        name: Some("Voice Channels".into()),
321                        newly_created: None,
322                        nsfw: Some(false),
323                        owner_id: None,
324                        parent_id: None,
325                        permission_overwrites: Some(vec![]),
326                        position: Some(0),
327                        rate_limit_per_user: None,
328                        recipients: None,
329                        rtc_region: None,
330                        thread_metadata: None,
331                        topic: None,
332                        user_limit: None,
333                        video_quality_mode: None,
334                    },
335                    Channel {
336                        application_id: None,
337                        applied_tags: None,
338                        available_tags: None,
339                        bitrate: Some(64000),
340                        default_auto_archive_duration: None,
341                        default_forum_layout: None,
342                        default_reaction_emoji: None,
343                        default_sort_order: None,
344                        default_thread_rate_limit_per_user: None,
345                        flags: None,
346                        guild_id: None,
347                        icon: None,
348                        id: Id::new(4),
349                        invitable: None,
350                        kind: ChannelType::GuildVoice,
351                        last_message_id: None,
352                        last_pin_timestamp: None,
353                        managed: None,
354                        member: None,
355                        member_count: None,
356                        message_count: None,
357                        name: Some("General".into()),
358                        newly_created: None,
359                        nsfw: Some(false),
360                        owner_id: None,
361                        parent_id: Some(Id::new(3)),
362                        permission_overwrites: Some(vec![]),
363                        position: Some(0),
364                        rate_limit_per_user: None,
365                        recipients: None,
366                        rtc_region: None,
367                        thread_metadata: None,
368                        topic: None,
369                        user_limit: Some(0),
370                        video_quality_mode: None,
371                    },
372                ]),
373                default_message_notifications: DefaultMessageNotificationLevel::All,
374                description: None,
375                explicit_content_filter: ExplicitContentFilter::None,
376                icon_hash: None,
377                name: "server name".into(),
378                preferred_locale: "en-US".into(),
379                roles: vec![
380                    TemplateRole {
381                        color: 0,
382                        hoist: false,
383                        id: Id::new(200),
384                        mentionable: false,
385                        name: "@everyone".into(),
386                        permissions: Permissions::CREATE_INVITE
387                            | Permissions::ADD_REACTIONS
388                            | Permissions::STREAM
389                            | Permissions::VIEW_CHANNEL
390                            | Permissions::SEND_MESSAGES
391                            | Permissions::EMBED_LINKS
392                            | Permissions::ATTACH_FILES
393                            | Permissions::READ_MESSAGE_HISTORY
394                            | Permissions::MENTION_EVERYONE
395                            | Permissions::USE_EXTERNAL_EMOJIS
396                            | Permissions::CONNECT
397                            | Permissions::SPEAK
398                            | Permissions::USE_VAD
399                            | Permissions::CHANGE_NICKNAME,
400                        tags: None,
401                    },
402                    TemplateRole {
403                        color: 0,
404                        hoist: false,
405                        id: Id::new(1),
406                        mentionable: false,
407                        name: "new role".into(),
408                        permissions: Permissions::CREATE_INVITE
409                            | Permissions::ADD_REACTIONS
410                            | Permissions::STREAM
411                            | Permissions::VIEW_CHANNEL
412                            | Permissions::SEND_MESSAGES
413                            | Permissions::EMBED_LINKS
414                            | Permissions::ATTACH_FILES
415                            | Permissions::READ_MESSAGE_HISTORY
416                            | Permissions::MENTION_EVERYONE
417                            | Permissions::USE_EXTERNAL_EMOJIS
418                            | Permissions::CONNECT
419                            | Permissions::SPEAK
420                            | Permissions::USE_VAD
421                            | Permissions::CHANGE_NICKNAME,
422                        tags: None,
423                    },
424                ],
425                system_channel_flags: SystemChannelFlags::empty(),
426                system_channel_id: Some(Id::new(2)),
427                verification_level: VerificationLevel::None,
428            },
429            source_guild_id: Id::new(200),
430            updated_at,
431            usage_count: 0,
432        };
433
434        let deserialized = serde_json::from_str::<Template>(&raw).unwrap();
435
436        assert_eq!(deserialized, value);
437
438        serde_test::assert_tokens(
439            &value,
440            &[
441                Token::Struct {
442                    name: "Template",
443                    len: 11,
444                },
445                Token::Str("code"),
446                Token::Str("code"),
447                Token::Str("created_at"),
448                Token::Str("2021-04-07T14:55:37.000000+00:00"),
449                Token::Str("creator"),
450                Token::Struct {
451                    name: "User",
452                    len: 11,
453                },
454                Token::Str("accent_color"),
455                Token::None,
456                Token::Str("avatar"),
457                Token::Some,
458                Token::Str(image_hash::AVATAR_INPUT),
459                Token::Str("avatar_decoration"),
460                Token::None,
461                Token::Str("avatar_decoration_data"),
462                Token::None,
463                Token::Str("banner"),
464                Token::Some,
465                Token::Str(image_hash::BANNER_INPUT),
466                Token::Str("bot"),
467                Token::Bool(false),
468                Token::Str("discriminator"),
469                Token::Str("1111"),
470                Token::Str("global_name"),
471                Token::Some,
472                Token::Str("test"),
473                Token::Str("id"),
474                Token::NewtypeStruct { name: "Id" },
475                Token::Str("100"),
476                Token::Str("username"),
477                Token::Str("username"),
478                Token::Str("public_flags"),
479                Token::Some,
480                Token::U64(0),
481                Token::StructEnd,
482                Token::Str("creator_id"),
483                Token::NewtypeStruct { name: "Id" },
484                Token::Str("100"),
485                Token::Str("description"),
486                Token::Some,
487                Token::Str("description"),
488                Token::Str("is_dirty"),
489                Token::None,
490                Token::Str("name"),
491                Token::Str("name"),
492                Token::Str("serialized_source_guild"),
493                Token::Struct {
494                    name: "TemplateGuild",
495                    len: 13,
496                },
497                Token::Str("afk_channel_id"),
498                Token::None,
499                Token::Str("afk_timeout"),
500                Token::NewtypeStruct { name: "AfkTimeout" },
501                Token::U16(300),
502                Token::Str("channels"),
503                Token::Seq { len: Some(4) },
504                Token::Struct {
505                    name: "Channel",
506                    len: 6,
507                },
508                Token::Str("id"),
509                Token::NewtypeStruct { name: "Id" },
510                Token::Str("1"),
511                Token::Str("type"),
512                Token::U8(4),
513                Token::Str("name"),
514                Token::Some,
515                Token::Str("Text Channels"),
516                Token::Str("nsfw"),
517                Token::Some,
518                Token::Bool(false),
519                Token::Str("permission_overwrites"),
520                Token::Some,
521                Token::Seq { len: Some(0) },
522                Token::SeqEnd,
523                Token::Str("position"),
524                Token::Some,
525                Token::I32(0),
526                Token::StructEnd,
527                Token::Struct {
528                    name: "Channel",
529                    len: 8,
530                },
531                Token::Str("id"),
532                Token::NewtypeStruct { name: "Id" },
533                Token::Str("2"),
534                Token::Str("type"),
535                Token::U8(0),
536                Token::Str("name"),
537                Token::Some,
538                Token::Str("general"),
539                Token::Str("nsfw"),
540                Token::Some,
541                Token::Bool(false),
542                Token::Str("parent_id"),
543                Token::Some,
544                Token::NewtypeStruct { name: "Id" },
545                Token::Str("1"),
546                Token::Str("permission_overwrites"),
547                Token::Some,
548                Token::Seq { len: Some(2) },
549                Token::Struct {
550                    name: "PermissionOverwrite",
551                    len: 4,
552                },
553                Token::Str("allow"),
554                Token::Str("0"),
555                Token::Str("deny"),
556                Token::Str("2048"),
557                Token::Str("id"),
558                Token::NewtypeStruct { name: "Id" },
559                Token::Str("1"),
560                Token::Str("type"),
561                Token::U8(0),
562                Token::StructEnd,
563                Token::Struct {
564                    name: "PermissionOverwrite",
565                    len: 4,
566                },
567                Token::Str("allow"),
568                Token::Str("2048"),
569                Token::Str("deny"),
570                Token::Str("0"),
571                Token::Str("id"),
572                Token::NewtypeStruct { name: "Id" },
573                Token::Str("2"),
574                Token::Str("type"),
575                Token::U8(0),
576                Token::StructEnd,
577                Token::SeqEnd,
578                Token::Str("position"),
579                Token::Some,
580                Token::I32(0),
581                Token::Str("rate_limit_per_user"),
582                Token::Some,
583                Token::U16(0),
584                Token::StructEnd,
585                Token::Struct {
586                    name: "Channel",
587                    len: 6,
588                },
589                Token::Str("id"),
590                Token::NewtypeStruct { name: "Id" },
591                Token::Str("3"),
592                Token::Str("type"),
593                Token::U8(4),
594                Token::Str("name"),
595                Token::Some,
596                Token::Str("Voice Channels"),
597                Token::Str("nsfw"),
598                Token::Some,
599                Token::Bool(false),
600                Token::Str("permission_overwrites"),
601                Token::Some,
602                Token::Seq { len: Some(0) },
603                Token::SeqEnd,
604                Token::Str("position"),
605                Token::Some,
606                Token::I32(0),
607                Token::StructEnd,
608                Token::Struct {
609                    name: "Channel",
610                    len: 9,
611                },
612                Token::Str("bitrate"),
613                Token::Some,
614                Token::U32(64000),
615                Token::Str("id"),
616                Token::NewtypeStruct { name: "Id" },
617                Token::Str("4"),
618                Token::Str("type"),
619                Token::U8(2),
620                Token::Str("name"),
621                Token::Some,
622                Token::Str("General"),
623                Token::Str("nsfw"),
624                Token::Some,
625                Token::Bool(false),
626                Token::Str("parent_id"),
627                Token::Some,
628                Token::NewtypeStruct { name: "Id" },
629                Token::Str("3"),
630                Token::Str("permission_overwrites"),
631                Token::Some,
632                Token::Seq { len: Some(0) },
633                Token::SeqEnd,
634                Token::Str("position"),
635                Token::Some,
636                Token::I32(0),
637                Token::Str("user_limit"),
638                Token::Some,
639                Token::U32(0),
640                Token::StructEnd,
641                Token::SeqEnd,
642                Token::Str("default_message_notifications"),
643                Token::U8(0),
644                Token::Str("description"),
645                Token::None,
646                Token::Str("explicit_content_filter"),
647                Token::U8(0),
648                Token::Str("icon_hash"),
649                Token::None,
650                Token::Str("name"),
651                Token::Str("server name"),
652                Token::Str("preferred_locale"),
653                Token::Str("en-US"),
654                Token::Str("roles"),
655                Token::Seq { len: Some(2) },
656                Token::Struct {
657                    name: "TemplateRole",
658                    len: 6,
659                },
660                Token::Str("color"),
661                Token::U32(0),
662                Token::Str("hoist"),
663                Token::Bool(false),
664                Token::Str("id"),
665                Token::NewtypeStruct { name: "Id" },
666                Token::Str("200"),
667                Token::Str("mentionable"),
668                Token::Bool(false),
669                Token::Str("name"),
670                Token::Str("@everyone"),
671                Token::Str("permissions"),
672                Token::Str("104320577"),
673                Token::StructEnd,
674                Token::Struct {
675                    name: "TemplateRole",
676                    len: 6,
677                },
678                Token::Str("color"),
679                Token::U32(0),
680                Token::Str("hoist"),
681                Token::Bool(false),
682                Token::Str("id"),
683                Token::NewtypeStruct { name: "Id" },
684                Token::Str("1"),
685                Token::Str("mentionable"),
686                Token::Bool(false),
687                Token::Str("name"),
688                Token::Str("new role"),
689                Token::Str("permissions"),
690                Token::Str("104320577"),
691                Token::StructEnd,
692                Token::SeqEnd,
693                Token::Str("system_channel_flags"),
694                Token::U64(0),
695                Token::Str("system_channel_id"),
696                Token::Some,
697                Token::NewtypeStruct { name: "Id" },
698                Token::Str("2"),
699                Token::Str("verification_level"),
700                Token::U8(0),
701                Token::StructEnd,
702                Token::Str("source_guild_id"),
703                Token::NewtypeStruct { name: "Id" },
704                Token::Str("200"),
705                Token::Str("updated_at"),
706                Token::Str("2021-04-07T14:55:37.000000+00:00"),
707                Token::Str("usage_count"),
708                Token::U64(0),
709                Token::StructEnd,
710            ],
711        );
712
713        Ok(())
714    }
715}