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