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 marker::{
37 ApplicationMarker, ChannelMarker, GenericMarker, GuildMarker, TagMarker, UserMarker,
38 },
39 Id,
40 },
41 user::User,
42 util::{ImageHash, Timestamp},
43};
44use serde::{Deserialize, Serialize};
45
46#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
59pub struct Channel {
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub application_id: Option<Id<ApplicationMarker>>,
63 #[serde(skip_serializing_if = "Option::is_none")]
64 pub applied_tags: Option<Vec<Id<TagMarker>>>,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub available_tags: Option<Vec<ForumTag>>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub bitrate: Option<u32>,
70 #[serde(skip_serializing_if = "Option::is_none")]
76 pub default_auto_archive_duration: Option<AutoArchiveDuration>,
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub default_forum_layout: Option<ForumLayout>,
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub default_reaction_emoji: Option<DefaultReaction>,
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub default_sort_order: Option<ForumSortOrder>,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub default_thread_rate_limit_per_user: Option<u16>,
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub flags: Option<ChannelFlags>,
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub guild_id: Option<Id<GuildMarker>>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub icon: Option<ImageHash>,
96 pub id: Id<ChannelMarker>,
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub invitable: Option<bool>,
101 #[serde(rename = "type")]
105 pub kind: ChannelType,
106 #[serde(skip_serializing_if = "Option::is_none")]
112 pub last_message_id: Option<Id<GenericMarker>>,
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub last_pin_timestamp: Option<Timestamp>,
116 #[serde(skip_serializing_if = "Option::is_none")]
124 pub managed: Option<bool>,
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub member: Option<ThreadMember>,
128 #[serde(skip_serializing_if = "Option::is_none")]
133 pub member_count: Option<i8>,
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub message_count: Option<u32>,
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub name: Option<String>,
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub newly_created: Option<bool>,
143 #[serde(skip_serializing_if = "Option::is_none")]
145 pub nsfw: Option<bool>,
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub owner_id: Option<Id<UserMarker>>,
149 #[serde(skip_serializing_if = "Option::is_none")]
155 pub parent_id: Option<Id<ChannelMarker>>,
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub permission_overwrites: Option<Vec<PermissionOverwrite>>,
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub position: Option<i32>,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub rate_limit_per_user: Option<u16>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub recipients: Option<Vec<User>>,
168 #[serde(skip_serializing_if = "Option::is_none")]
172 pub rtc_region: Option<String>,
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub thread_metadata: Option<ThreadMetadata>,
176 #[serde(skip_serializing_if = "Option::is_none")]
178 pub topic: Option<String>,
179 #[serde(skip_serializing_if = "Option::is_none")]
183 pub user_limit: Option<u32>,
184 #[serde(skip_serializing_if = "Option::is_none")]
188 pub video_quality_mode: Option<VideoQualityMode>,
189}
190
191#[cfg(test)]
192mod tests {
193 use super::{AutoArchiveDuration, Channel, ChannelType, ThreadMember, ThreadMetadata};
194 use crate::{
195 channel::permission_overwrite::{PermissionOverwrite, PermissionOverwriteType},
196 guild::Permissions,
197 id::Id,
198 util::Timestamp,
199 };
200
201 #[test]
204 fn guild_channel_unknown_field_deserialization() {
205 let input = serde_json::json!({
206 "type": 0,
207 "topic": "a",
208 "rate_limit_per_user": 0,
209 "position": 0,
210 "permission_overwrites": [],
211 "parent_id": null,
212 "nsfw": false,
213 "name": "hey",
214 "last_message_id": "3",
215 "id": "2",
216 "guild_id": "1",
217 "guild_hashes": {
218 "version": 1,
219 "roles": {
220 "hash": "aaaaaaaaaaa"
221 },
222 "metadata": {
223 "hash": "bbbbbbbbbbb"
224 },
225 "channels": {
226 "hash": "ccccccccccc"
227 }
228 },
229 "unknown_field": "the deserializer should skip unknown field names",
230 });
231
232 let value = Channel {
233 application_id: None,
234 applied_tags: None,
235 available_tags: None,
236 bitrate: None,
237 default_auto_archive_duration: None,
238 default_forum_layout: None,
239 default_reaction_emoji: None,
240 default_sort_order: None,
241 default_thread_rate_limit_per_user: None,
242 flags: None,
243 guild_id: Some(Id::new(1)),
244 icon: None,
245 id: Id::new(2),
246 invitable: None,
247 kind: ChannelType::GuildText,
248 last_message_id: Some(Id::new(3)),
249 last_pin_timestamp: None,
250 managed: None,
251 member: None,
252 member_count: None,
253 message_count: None,
254 name: Some("hey".to_owned()),
255 newly_created: None,
256 nsfw: Some(false),
257 owner_id: None,
258 parent_id: None,
259 permission_overwrites: Some(Vec::new()),
260 position: Some(0),
261 rate_limit_per_user: Some(0),
262 recipients: None,
263 rtc_region: None,
264 thread_metadata: None,
265 topic: Some("a".to_owned()),
266 user_limit: None,
267 video_quality_mode: None,
268 };
269
270 assert_eq!(value, serde_json::from_value(input).unwrap());
271 }
272
273 #[test]
274 fn guild_category_channel_deserialization() {
275 let value = Channel {
276 application_id: None,
277 applied_tags: None,
278 available_tags: None,
279 bitrate: None,
280 default_auto_archive_duration: None,
281 default_forum_layout: None,
282 default_reaction_emoji: None,
283 default_sort_order: None,
284 default_thread_rate_limit_per_user: None,
285 flags: None,
286 guild_id: Some(Id::new(2)),
287 icon: None,
288 id: Id::new(1),
289 invitable: None,
290 kind: ChannelType::GuildCategory,
291 last_message_id: None,
292 last_pin_timestamp: None,
293 managed: None,
294 member: None,
295 member_count: None,
296 message_count: None,
297 name: Some("foo".to_owned()),
298 newly_created: None,
299 nsfw: None,
300 owner_id: None,
301 parent_id: None,
302 permission_overwrites: Some(Vec::new()),
303 position: Some(3),
304 rate_limit_per_user: None,
305 recipients: None,
306 rtc_region: None,
307 thread_metadata: None,
308 topic: None,
309 user_limit: None,
310 video_quality_mode: None,
311 };
312 let permission_overwrites: Vec<PermissionOverwrite> = Vec::new();
313
314 assert_eq!(
315 value,
316 serde_json::from_value(serde_json::json!({
317 "id": "1",
318 "guild_id": Some("2"),
319 "name": "foo",
320 "permission_overwrites": permission_overwrites,
321 "position": 3,
322 "type": 4,
323 }))
324 .unwrap()
325 );
326 }
327
328 #[test]
329 fn guild_announcement_channel_deserialization() {
330 let value = Channel {
331 application_id: None,
332 applied_tags: None,
333 available_tags: None,
334 bitrate: None,
335 default_auto_archive_duration: None,
336 default_forum_layout: None,
337 default_reaction_emoji: None,
338 default_sort_order: None,
339 default_thread_rate_limit_per_user: None,
340 flags: None,
341 guild_id: Some(Id::new(2)),
342 icon: None,
343 id: Id::new(1),
344 invitable: None,
345 kind: ChannelType::GuildAnnouncement,
346 last_message_id: Some(Id::new(4)),
347 last_pin_timestamp: None,
348 managed: None,
349 member: None,
350 member_count: None,
351 message_count: None,
352 name: Some("news".to_owned()),
353 newly_created: None,
354 nsfw: Some(true),
355 owner_id: None,
356 parent_id: Some(Id::new(5)),
357 permission_overwrites: Some(Vec::new()),
358 position: Some(3),
359 rate_limit_per_user: None,
360 recipients: None,
361 rtc_region: None,
362 thread_metadata: None,
363 topic: Some("a news channel".to_owned()),
364 user_limit: None,
365 video_quality_mode: None,
366 };
367 let permission_overwrites: Vec<PermissionOverwrite> = Vec::new();
368
369 assert_eq!(
370 value,
371 serde_json::from_value(serde_json::json!({
372 "id": "1",
373 "guild_id": "2",
374 "name": "news",
375 "nsfw": true,
376 "last_message_id": "4",
377 "parent_id": "5",
378 "permission_overwrites": permission_overwrites,
379 "position": 3,
380 "topic": "a news channel",
381 "type": ChannelType::GuildAnnouncement,
382 }))
383 .unwrap()
384 );
385 }
386
387 #[test]
388 fn guild_announcement_thread_deserialization() {
389 let timestamp = Timestamp::from_secs(1_632_074_792).expect("non zero");
390 let formatted = timestamp.iso_8601().to_string();
391
392 let value = Channel {
393 application_id: None,
394 applied_tags: None,
395 available_tags: None,
396 bitrate: None,
397 default_auto_archive_duration: Some(AutoArchiveDuration::Hour),
398 default_forum_layout: None,
399 default_reaction_emoji: None,
400 default_sort_order: None,
401 default_thread_rate_limit_per_user: None,
402 flags: None,
403 guild_id: Some(Id::new(1)),
404 icon: None,
405 id: Id::new(6),
406 invitable: None,
407 kind: ChannelType::AnnouncementThread,
408 last_message_id: Some(Id::new(3)),
409 last_pin_timestamp: None,
410 managed: Some(true),
411 member: Some(ThreadMember {
412 flags: 0_u64,
413 id: Some(Id::new(4)),
414 join_timestamp: timestamp,
415 member: None,
416 presence: None,
417 user_id: Some(Id::new(5)),
418 }),
419 member_count: Some(50),
420 message_count: Some(50),
421 name: Some("newsthread".into()),
422 newly_created: Some(true),
423 nsfw: None,
424 owner_id: Some(Id::new(5)),
425 parent_id: Some(Id::new(2)),
426 permission_overwrites: None,
427 position: None,
428 rate_limit_per_user: Some(1000),
429 recipients: None,
430 rtc_region: None,
431 thread_metadata: Some(ThreadMetadata {
432 archived: false,
433 auto_archive_duration: AutoArchiveDuration::Day,
434 archive_timestamp: timestamp,
435 create_timestamp: Some(timestamp),
436 invitable: None,
437 locked: false,
438 }),
439 topic: None,
440 user_limit: None,
441 video_quality_mode: None,
442 };
443
444 assert_eq!(
445 value,
446 serde_json::from_value(serde_json::json!({
447 "id": "6",
448 "guild_id": "1",
449 "type": ChannelType::AnnouncementThread,
450 "last_message_id": "3",
451 "member": {
452 "flags": 0,
453 "id": "4",
454 "join_timestamp": formatted,
455 "user_id": "5",
456 },
457 "default_auto_archive_duration": 60,
458 "managed": true,
459 "member_count": 50,
460 "message_count": 50,
461 "name": "newsthread",
462 "newly_created": true,
463 "owner_id": "5",
464 "parent_id": "2",
465 "rate_limit_per_user": 1000,
466 "thread_metadata": {
467 "archive_timestamp": formatted,
468 "archived": false,
469 "auto_archive_duration": AutoArchiveDuration::Day,
470 "create_timestamp": formatted,
471 "locked": false
472 }
473 }))
474 .unwrap()
475 )
476 }
477
478 #[test]
479 fn public_thread_deserialization() {
480 let timestamp = Timestamp::from_secs(1_632_074_792).expect("non zero");
481
482 let value = Channel {
483 application_id: None,
484 applied_tags: None,
485 available_tags: None,
486 bitrate: None,
487 default_auto_archive_duration: Some(AutoArchiveDuration::Hour),
488 default_forum_layout: None,
489 default_reaction_emoji: None,
490 default_sort_order: None,
491 default_thread_rate_limit_per_user: None,
492 flags: None,
493 guild_id: Some(Id::new(1)),
494 icon: None,
495 id: Id::new(6),
496 invitable: None,
497 kind: ChannelType::PublicThread,
498 last_message_id: Some(Id::new(3)),
499 last_pin_timestamp: None,
500 managed: Some(true),
501 member: Some(ThreadMember {
502 flags: 0_u64,
503 id: Some(Id::new(4)),
504 join_timestamp: timestamp,
505 member: None,
506 presence: None,
507 user_id: Some(Id::new(5)),
508 }),
509 member_count: Some(50),
510 message_count: Some(50),
511 name: Some("publicthread".into()),
512 newly_created: Some(true),
513 nsfw: None,
514 owner_id: Some(Id::new(5)),
515 parent_id: Some(Id::new(2)),
516 permission_overwrites: None,
517 position: None,
518 rate_limit_per_user: Some(1000),
519 recipients: None,
520 rtc_region: None,
521 thread_metadata: Some(ThreadMetadata {
522 archived: false,
523 auto_archive_duration: AutoArchiveDuration::Day,
524 archive_timestamp: timestamp,
525 create_timestamp: Some(timestamp),
526 invitable: None,
527 locked: false,
528 }),
529 topic: None,
530 user_limit: None,
531 video_quality_mode: None,
532 };
533
534 assert_eq!(
535 value,
536 serde_json::from_value(serde_json::json!({
537 "id": "6",
538 "guild_id": "1",
539 "type": ChannelType::PublicThread,
540 "last_message_id": "3",
541 "member": {
542 "flags": 0,
543 "id": "4",
544 "join_timestamp": timestamp,
545 "user_id": "5",
546 },
547 "default_auto_archive_duration": 60,
548 "managed": true,
549 "member_count": 50,
550 "message_count": 50,
551 "name": "publicthread",
552 "newly_created": true,
553 "owner_id": "5",
554 "parent_id": "2",
555 "rate_limit_per_user": 1000,
556 "thread_metadata": {
557 "archive_timestamp": timestamp,
558 "archived": false,
559 "auto_archive_duration": AutoArchiveDuration::Day,
560 "create_timestamp": timestamp,
561 "locked": false
562 }
563 }))
564 .unwrap()
565 )
566 }
567
568 #[test]
569 fn private_thread_deserialization() {
570 let timestamp = Timestamp::from_secs(1_632_074_792).expect("non zero");
571 let formatted = timestamp.iso_8601().to_string();
572
573 let value = Channel {
574 application_id: None,
575 applied_tags: None,
576 available_tags: None,
577 bitrate: None,
578 default_auto_archive_duration: Some(AutoArchiveDuration::Hour),
579 default_forum_layout: None,
580 default_reaction_emoji: None,
581 default_sort_order: None,
582 default_thread_rate_limit_per_user: None,
583 flags: None,
584 guild_id: Some(Id::new(1)),
585 icon: None,
586 id: Id::new(6),
587 invitable: Some(true),
588 kind: ChannelType::PrivateThread,
589 last_message_id: Some(Id::new(3)),
590 last_pin_timestamp: None,
591 managed: Some(true),
592 member: Some(ThreadMember {
593 flags: 0_u64,
594 id: Some(Id::new(4)),
595 join_timestamp: timestamp,
596 member: None,
597 presence: None,
598 user_id: Some(Id::new(5)),
599 }),
600 member_count: Some(-1),
603 message_count: Some(50),
604 name: Some("privatethread".into()),
605 newly_created: Some(true),
606 nsfw: None,
607 owner_id: Some(Id::new(5)),
608 parent_id: Some(Id::new(2)),
609 permission_overwrites: Some(Vec::from([PermissionOverwrite {
610 allow: Permissions::empty(),
611 deny: Permissions::empty(),
612 id: Id::new(5),
613 kind: PermissionOverwriteType::Member,
614 }])),
615 position: None,
616 rate_limit_per_user: Some(1000),
617 recipients: None,
618 rtc_region: None,
619 thread_metadata: Some(ThreadMetadata {
620 archived: false,
621 auto_archive_duration: AutoArchiveDuration::Day,
622 archive_timestamp: timestamp,
623 create_timestamp: Some(timestamp),
624 invitable: None,
625 locked: false,
626 }),
627 topic: None,
628 user_limit: None,
629 video_quality_mode: None,
630 };
631
632 assert_eq!(
633 value,
634 serde_json::from_value(serde_json::json!({
635 "id": "6",
636 "guild_id": "1",
637 "type": ChannelType::PrivateThread,
638 "last_message_id": "3",
639 "member": {
640 "flags": 0,
641 "id": "4",
642 "join_timestamp": formatted,
643 "user_id": "5",
644 },
645 "default_auto_archive_duration": 60,
646 "invitable": true,
647 "managed": true,
648 "member_count": -1,
649 "message_count": 50,
650 "name": "privatethread",
651 "newly_created": true,
652 "owner_id": "5",
653 "parent_id": "2",
654 "rate_limit_per_user": 1000,
655 "thread_metadata": {
656 "archive_timestamp": formatted,
657 "archived": false,
658 "auto_archive_duration": AutoArchiveDuration::Day,
659 "create_timestamp": formatted,
660 "locked": false
661 },
662 "permission_overwrites": [
663 {
664 "allow": "0",
665 "deny": "0",
666 "type": 1,
667 "id": "5"
668 }
669 ]
670 }))
671 .unwrap()
672 )
673 }
674}