1pub mod forum;
2pub mod message;
3pub mod permission_overwrite;
4pub mod stage_instance;
5pub mod thread;
6pub mod webhook;
7
8mod attachment;
9mod attachment_flags;
10mod channel_mention;
11mod channel_type;
12mod flags;
13mod followed_channel;
14mod video_quality_mode;
15
16pub use self::{
17 attachment::Attachment,
18 attachment_flags::AttachmentFlags,
19 channel_mention::ChannelMention,
20 channel_type::ChannelType,
21 flags::ChannelFlags,
22 followed_channel::FollowedChannel,
23 message::Message,
24 stage_instance::StageInstance,
25 video_quality_mode::VideoQualityMode,
26 webhook::{Webhook, WebhookType},
27};
28
29use crate::{
30 channel::{
31 forum::{DefaultReaction, ForumLayout, ForumSortOrder, ForumTag},
32 permission_overwrite::PermissionOverwrite,
33 thread::{AutoArchiveDuration, ThreadMember, ThreadMetadata},
34 },
35 id::{
36 Id,
37 marker::{
38 ApplicationMarker, ChannelMarker, GenericMarker, GuildMarker, TagMarker, UserMarker,
39 },
40 },
41 user::User,
42 util::{ImageHash, Timestamp},
43};
44use serde::{Deserialize, Serialize};
45
46#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
84pub struct Channel {
85 #[serde(skip_serializing_if = "Option::is_none")]
87 pub application_id: Option<Id<ApplicationMarker>>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub applied_tags: Option<Vec<Id<TagMarker>>>,
90 #[serde(skip_serializing_if = "Option::is_none")]
91 pub available_tags: Option<Vec<ForumTag>>,
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub bitrate: Option<u32>,
95 #[serde(skip_serializing_if = "Option::is_none")]
101 pub default_auto_archive_duration: Option<AutoArchiveDuration>,
102 #[serde(skip_serializing_if = "Option::is_none")]
104 pub default_forum_layout: Option<ForumLayout>,
105 #[serde(skip_serializing_if = "Option::is_none")]
106 pub default_reaction_emoji: Option<DefaultReaction>,
107 #[serde(skip_serializing_if = "Option::is_none")]
109 pub default_sort_order: Option<ForumSortOrder>,
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub default_thread_rate_limit_per_user: Option<u16>,
112 #[serde(skip_serializing_if = "Option::is_none")]
114 pub flags: Option<ChannelFlags>,
115 #[serde(skip_serializing_if = "Option::is_none")]
117 pub guild_id: Option<Id<GuildMarker>>,
118 #[serde(skip_serializing_if = "Option::is_none")]
120 pub icon: Option<ImageHash>,
121 pub id: Id<ChannelMarker>,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub invitable: Option<bool>,
126 #[serde(rename = "type")]
130 pub kind: ChannelType,
131 #[serde(skip_serializing_if = "Option::is_none")]
137 pub last_message_id: Option<Id<GenericMarker>>,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub last_pin_timestamp: Option<Timestamp>,
141 #[serde(skip_serializing_if = "Option::is_none")]
149 pub managed: Option<bool>,
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub member: Option<ThreadMember>,
153 #[serde(skip_serializing_if = "Option::is_none")]
158 pub member_count: Option<i8>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub message_count: Option<u32>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub name: Option<String>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub newly_created: Option<bool>,
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub nsfw: Option<bool>,
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub owner_id: Option<Id<UserMarker>>,
174 #[serde(skip_serializing_if = "Option::is_none")]
180 pub parent_id: Option<Id<ChannelMarker>>,
181 #[serde(skip_serializing_if = "Option::is_none")]
183 pub permission_overwrites: Option<Vec<PermissionOverwrite>>,
184 #[serde(skip_serializing_if = "Option::is_none")]
186 pub position: Option<i32>,
187 #[serde(skip_serializing_if = "Option::is_none")]
189 pub rate_limit_per_user: Option<u16>,
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub recipients: Option<Vec<User>>,
193 #[serde(skip_serializing_if = "Option::is_none")]
197 pub rtc_region: Option<String>,
198 #[serde(skip_serializing_if = "Option::is_none")]
200 pub thread_metadata: Option<ThreadMetadata>,
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub topic: Option<String>,
204 #[serde(skip_serializing_if = "Option::is_none")]
209 pub total_message_sent: Option<u32>,
210 #[serde(skip_serializing_if = "Option::is_none")]
214 pub user_limit: Option<u32>,
215 #[serde(skip_serializing_if = "Option::is_none")]
219 pub video_quality_mode: Option<VideoQualityMode>,
220}
221
222#[cfg(test)]
223mod tests {
224 use super::{AutoArchiveDuration, Channel, ChannelType, ThreadMember, ThreadMetadata};
225 use crate::{
226 channel::permission_overwrite::{PermissionOverwrite, PermissionOverwriteType},
227 guild::Permissions,
228 id::Id,
229 util::Timestamp,
230 };
231
232 #[test]
235 fn guild_channel_unknown_field_deserialization() {
236 let input = serde_json::json!({
237 "type": 0,
238 "topic": "a",
239 "rate_limit_per_user": 0,
240 "position": 0,
241 "permission_overwrites": [],
242 "parent_id": null,
243 "nsfw": false,
244 "name": "hey",
245 "last_message_id": "3",
246 "id": "2",
247 "guild_id": "1",
248 "guild_hashes": {
249 "version": 1,
250 "roles": {
251 "hash": "aaaaaaaaaaa"
252 },
253 "metadata": {
254 "hash": "bbbbbbbbbbb"
255 },
256 "channels": {
257 "hash": "ccccccccccc"
258 }
259 },
260 "total_message_sent": 17,
261 "unknown_field": "the deserializer should skip unknown field names",
262 });
263
264 let value = Channel {
265 application_id: None,
266 applied_tags: None,
267 available_tags: None,
268 bitrate: None,
269 default_auto_archive_duration: None,
270 default_forum_layout: None,
271 default_reaction_emoji: None,
272 default_sort_order: None,
273 default_thread_rate_limit_per_user: None,
274 flags: None,
275 guild_id: Some(Id::new(1)),
276 icon: None,
277 id: Id::new(2),
278 invitable: None,
279 kind: ChannelType::GuildText,
280 last_message_id: Some(Id::new(3)),
281 last_pin_timestamp: None,
282 managed: None,
283 member: None,
284 member_count: None,
285 message_count: None,
286 name: Some("hey".to_owned()),
287 newly_created: None,
288 nsfw: Some(false),
289 owner_id: None,
290 parent_id: None,
291 permission_overwrites: Some(Vec::new()),
292 position: Some(0),
293 rate_limit_per_user: Some(0),
294 recipients: None,
295 rtc_region: None,
296 thread_metadata: None,
297 topic: Some("a".to_owned()),
298 total_message_sent: Some(17),
299 user_limit: None,
300 video_quality_mode: None,
301 };
302
303 assert_eq!(value, serde_json::from_value(input).unwrap());
304 }
305
306 #[test]
307 fn guild_category_channel_deserialization() {
308 let value = Channel {
309 application_id: None,
310 applied_tags: None,
311 available_tags: None,
312 bitrate: None,
313 default_auto_archive_duration: None,
314 default_forum_layout: None,
315 default_reaction_emoji: None,
316 default_sort_order: None,
317 default_thread_rate_limit_per_user: None,
318 flags: None,
319 guild_id: Some(Id::new(2)),
320 icon: None,
321 id: Id::new(1),
322 invitable: None,
323 kind: ChannelType::GuildCategory,
324 last_message_id: None,
325 last_pin_timestamp: None,
326 managed: None,
327 member: None,
328 member_count: None,
329 message_count: None,
330 name: Some("foo".to_owned()),
331 newly_created: None,
332 nsfw: None,
333 owner_id: None,
334 parent_id: None,
335 permission_overwrites: Some(Vec::new()),
336 position: Some(3),
337 rate_limit_per_user: None,
338 recipients: None,
339 rtc_region: None,
340 thread_metadata: None,
341 topic: None,
342 total_message_sent: Some(11),
343 user_limit: None,
344 video_quality_mode: None,
345 };
346 let permission_overwrites: Vec<PermissionOverwrite> = Vec::new();
347
348 assert_eq!(
349 value,
350 serde_json::from_value(serde_json::json!({
351 "id": "1",
352 "guild_id": Some("2"),
353 "name": "foo",
354 "permission_overwrites": permission_overwrites,
355 "position": 3,
356 "total_message_sent": 11,
357 "type": 4,
358 }))
359 .unwrap()
360 );
361 }
362
363 #[test]
364 fn guild_announcement_channel_deserialization() {
365 let value = Channel {
366 application_id: None,
367 applied_tags: None,
368 available_tags: None,
369 bitrate: None,
370 default_auto_archive_duration: None,
371 default_forum_layout: None,
372 default_reaction_emoji: None,
373 default_sort_order: None,
374 default_thread_rate_limit_per_user: None,
375 flags: None,
376 guild_id: Some(Id::new(2)),
377 icon: None,
378 id: Id::new(1),
379 invitable: None,
380 kind: ChannelType::GuildAnnouncement,
381 last_message_id: Some(Id::new(4)),
382 last_pin_timestamp: None,
383 managed: None,
384 member: None,
385 member_count: None,
386 message_count: None,
387 name: Some("news".to_owned()),
388 newly_created: None,
389 nsfw: Some(true),
390 owner_id: None,
391 parent_id: Some(Id::new(5)),
392 permission_overwrites: Some(Vec::new()),
393 position: Some(3),
394 rate_limit_per_user: None,
395 recipients: None,
396 rtc_region: None,
397 thread_metadata: None,
398 topic: Some("a news channel".to_owned()),
399 total_message_sent: None,
400 user_limit: None,
401 video_quality_mode: None,
402 };
403 let permission_overwrites: Vec<PermissionOverwrite> = Vec::new();
404
405 assert_eq!(
406 value,
407 serde_json::from_value(serde_json::json!({
408 "id": "1",
409 "guild_id": "2",
410 "name": "news",
411 "nsfw": true,
412 "last_message_id": "4",
413 "parent_id": "5",
414 "permission_overwrites": permission_overwrites,
415 "position": 3,
416 "topic": "a news channel",
417 "type": ChannelType::GuildAnnouncement,
418 }))
419 .unwrap()
420 );
421 }
422
423 #[test]
424 fn guild_announcement_thread_deserialization() {
425 let timestamp = Timestamp::from_secs(1_632_074_792).expect("non zero");
426 let formatted = timestamp.iso_8601().to_string();
427
428 let value = Channel {
429 application_id: None,
430 applied_tags: None,
431 available_tags: None,
432 bitrate: None,
433 default_auto_archive_duration: Some(AutoArchiveDuration::Hour),
434 default_forum_layout: None,
435 default_reaction_emoji: None,
436 default_sort_order: None,
437 default_thread_rate_limit_per_user: None,
438 flags: None,
439 guild_id: Some(Id::new(1)),
440 icon: None,
441 id: Id::new(6),
442 invitable: None,
443 kind: ChannelType::AnnouncementThread,
444 last_message_id: Some(Id::new(3)),
445 last_pin_timestamp: None,
446 managed: Some(true),
447 member: Some(ThreadMember {
448 flags: 0_u64,
449 id: Some(Id::new(4)),
450 join_timestamp: timestamp,
451 member: None,
452 presence: None,
453 user_id: Some(Id::new(5)),
454 }),
455 member_count: Some(50),
456 message_count: Some(50),
457 name: Some("newsthread".into()),
458 newly_created: Some(true),
459 nsfw: None,
460 owner_id: Some(Id::new(5)),
461 parent_id: Some(Id::new(2)),
462 permission_overwrites: None,
463 position: None,
464 rate_limit_per_user: Some(1000),
465 recipients: None,
466 rtc_region: None,
467 thread_metadata: Some(ThreadMetadata {
468 archived: false,
469 auto_archive_duration: AutoArchiveDuration::Day,
470 archive_timestamp: timestamp,
471 create_timestamp: Some(timestamp),
472 invitable: None,
473 locked: false,
474 }),
475 topic: None,
476 total_message_sent: None,
477 user_limit: None,
478 video_quality_mode: None,
479 };
480
481 assert_eq!(
482 value,
483 serde_json::from_value(serde_json::json!({
484 "id": "6",
485 "guild_id": "1",
486 "type": ChannelType::AnnouncementThread,
487 "last_message_id": "3",
488 "member": {
489 "flags": 0,
490 "id": "4",
491 "join_timestamp": formatted,
492 "user_id": "5",
493 },
494 "default_auto_archive_duration": 60,
495 "managed": true,
496 "member_count": 50,
497 "message_count": 50,
498 "name": "newsthread",
499 "newly_created": true,
500 "owner_id": "5",
501 "parent_id": "2",
502 "rate_limit_per_user": 1000,
503 "thread_metadata": {
504 "archive_timestamp": formatted,
505 "archived": false,
506 "auto_archive_duration": AutoArchiveDuration::Day,
507 "create_timestamp": formatted,
508 "locked": false
509 }
510 }))
511 .unwrap()
512 )
513 }
514
515 #[test]
516 fn public_thread_deserialization() {
517 let timestamp = Timestamp::from_secs(1_632_074_792).expect("non zero");
518
519 let value = Channel {
520 application_id: None,
521 applied_tags: None,
522 available_tags: None,
523 bitrate: None,
524 default_auto_archive_duration: Some(AutoArchiveDuration::Hour),
525 default_forum_layout: None,
526 default_reaction_emoji: None,
527 default_sort_order: None,
528 default_thread_rate_limit_per_user: None,
529 flags: None,
530 guild_id: Some(Id::new(1)),
531 icon: None,
532 id: Id::new(6),
533 invitable: None,
534 kind: ChannelType::PublicThread,
535 last_message_id: Some(Id::new(3)),
536 last_pin_timestamp: None,
537 managed: Some(true),
538 member: Some(ThreadMember {
539 flags: 0_u64,
540 id: Some(Id::new(4)),
541 join_timestamp: timestamp,
542 member: None,
543 presence: None,
544 user_id: Some(Id::new(5)),
545 }),
546 member_count: Some(50),
547 message_count: Some(50),
548 name: Some("publicthread".into()),
549 newly_created: Some(true),
550 nsfw: None,
551 owner_id: Some(Id::new(5)),
552 parent_id: Some(Id::new(2)),
553 permission_overwrites: None,
554 position: None,
555 rate_limit_per_user: Some(1000),
556 recipients: None,
557 rtc_region: None,
558 thread_metadata: Some(ThreadMetadata {
559 archived: false,
560 auto_archive_duration: AutoArchiveDuration::Day,
561 archive_timestamp: timestamp,
562 create_timestamp: Some(timestamp),
563 invitable: None,
564 locked: false,
565 }),
566 topic: None,
567 total_message_sent: None,
568 user_limit: None,
569 video_quality_mode: None,
570 };
571
572 assert_eq!(
573 value,
574 serde_json::from_value(serde_json::json!({
575 "id": "6",
576 "guild_id": "1",
577 "type": ChannelType::PublicThread,
578 "last_message_id": "3",
579 "member": {
580 "flags": 0,
581 "id": "4",
582 "join_timestamp": timestamp,
583 "user_id": "5",
584 },
585 "default_auto_archive_duration": 60,
586 "managed": true,
587 "member_count": 50,
588 "message_count": 50,
589 "name": "publicthread",
590 "newly_created": true,
591 "owner_id": "5",
592 "parent_id": "2",
593 "rate_limit_per_user": 1000,
594 "thread_metadata": {
595 "archive_timestamp": timestamp,
596 "archived": false,
597 "auto_archive_duration": AutoArchiveDuration::Day,
598 "create_timestamp": timestamp,
599 "locked": false
600 }
601 }))
602 .unwrap()
603 )
604 }
605
606 #[test]
607 fn private_thread_deserialization() {
608 let timestamp = Timestamp::from_secs(1_632_074_792).expect("non zero");
609 let formatted = timestamp.iso_8601().to_string();
610
611 let value = Channel {
612 application_id: None,
613 applied_tags: None,
614 available_tags: None,
615 bitrate: None,
616 default_auto_archive_duration: Some(AutoArchiveDuration::Hour),
617 default_forum_layout: None,
618 default_reaction_emoji: None,
619 default_sort_order: None,
620 default_thread_rate_limit_per_user: None,
621 flags: None,
622 guild_id: Some(Id::new(1)),
623 icon: None,
624 id: Id::new(6),
625 invitable: Some(true),
626 kind: ChannelType::PrivateThread,
627 last_message_id: Some(Id::new(3)),
628 last_pin_timestamp: None,
629 managed: Some(true),
630 member: Some(ThreadMember {
631 flags: 0_u64,
632 id: Some(Id::new(4)),
633 join_timestamp: timestamp,
634 member: None,
635 presence: None,
636 user_id: Some(Id::new(5)),
637 }),
638 member_count: Some(-1),
641 message_count: Some(50),
642 name: Some("privatethread".into()),
643 newly_created: Some(true),
644 nsfw: None,
645 owner_id: Some(Id::new(5)),
646 parent_id: Some(Id::new(2)),
647 permission_overwrites: Some(Vec::from([PermissionOverwrite {
648 allow: Permissions::empty(),
649 deny: Permissions::empty(),
650 id: Id::new(5),
651 kind: PermissionOverwriteType::Member,
652 }])),
653 position: None,
654 rate_limit_per_user: Some(1000),
655 recipients: None,
656 rtc_region: None,
657 thread_metadata: Some(ThreadMetadata {
658 archived: false,
659 auto_archive_duration: AutoArchiveDuration::Day,
660 archive_timestamp: timestamp,
661 create_timestamp: Some(timestamp),
662 invitable: None,
663 locked: false,
664 }),
665 topic: None,
666 total_message_sent: None,
667 user_limit: None,
668 video_quality_mode: None,
669 };
670
671 assert_eq!(
672 value,
673 serde_json::from_value(serde_json::json!({
674 "id": "6",
675 "guild_id": "1",
676 "type": ChannelType::PrivateThread,
677 "last_message_id": "3",
678 "member": {
679 "flags": 0,
680 "id": "4",
681 "join_timestamp": formatted,
682 "user_id": "5",
683 },
684 "default_auto_archive_duration": 60,
685 "invitable": true,
686 "managed": true,
687 "member_count": -1,
688 "message_count": 50,
689 "name": "privatethread",
690 "newly_created": true,
691 "owner_id": "5",
692 "parent_id": "2",
693 "rate_limit_per_user": 1000,
694 "thread_metadata": {
695 "archive_timestamp": formatted,
696 "archived": false,
697 "auto_archive_duration": AutoArchiveDuration::Day,
698 "create_timestamp": formatted,
699 "locked": false
700 },
701 "permission_overwrites": [
702 {
703 "allow": "0",
704 "deny": "0",
705 "type": 1,
706 "id": "5"
707 }
708 ]
709 }))
710 .unwrap()
711 )
712 }
713}