1use super::InMemoryCache;
39use crate::{
40 traits::{CacheableChannel, CacheableGuild, CacheableMember, CacheableRole},
41 CacheableModels,
42};
43use std::{
44 error::Error,
45 fmt::{Display, Formatter, Result as FmtResult},
46 time::{Duration, SystemTime},
47};
48use twilight_model::{
49 channel::{permission_overwrite::PermissionOverwrite, ChannelType},
50 guild::Permissions,
51 id::{
52 marker::{ChannelMarker, GuildMarker, RoleMarker, UserMarker},
53 Id,
54 },
55};
56use twilight_util::permission_calculator::PermissionCalculator;
57
58pub const MEMBER_COMMUNICATION_DISABLED_ALLOWLIST: Permissions = Permissions::from_bits_truncate(
67 Permissions::READ_MESSAGE_HISTORY.bits() | Permissions::VIEW_CHANNEL.bits(),
68);
69
70#[derive(Debug)]
72pub struct ChannelError {
73 kind: ChannelErrorType,
74 source: Option<Box<dyn Error + Send + Sync>>,
75}
76
77impl ChannelError {
78 #[must_use = "retrieving the type has no effect if left unused"]
80 pub const fn kind(&self) -> &ChannelErrorType {
81 &self.kind
82 }
83
84 #[must_use = "consuming the error and retrieving the source has no effect if left unused"]
86 pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
87 self.source
88 }
89
90 #[must_use = "consuming the error into its parts has no effect if left unused"]
92 pub fn into_parts(self) -> (ChannelErrorType, Option<Box<dyn Error + Send + Sync>>) {
93 (self.kind, self.source)
94 }
95
96 #[allow(clippy::needless_pass_by_value)]
99 fn from_member_roles(member_roles_error: MemberRolesErrorType) -> Self {
100 Self {
101 kind: match member_roles_error {
102 MemberRolesErrorType::RoleMissing { role_id } => {
103 ChannelErrorType::RoleUnavailable { role_id }
104 }
105 },
106 source: None,
107 }
108 }
109}
110
111impl Display for ChannelError {
112 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
113 match self.kind {
114 ChannelErrorType::ChannelNotInGuild { channel_id } => {
115 f.write_str("channel ")?;
116 Display::fmt(&channel_id, f)?;
117
118 f.write_str(" is not in a guild")
119 }
120 ChannelErrorType::ChannelUnavailable { channel_id } => {
121 f.write_str("channel ")?;
122 Display::fmt(&channel_id, f)?;
123
124 f.write_str(" is either not in the cache or is not a guild channel")
125 }
126 ChannelErrorType::MemberUnavailable { guild_id, user_id } => {
127 f.write_str("member (guild: ")?;
128 Display::fmt(&guild_id, f)?;
129 f.write_str("; user: ")?;
130 Display::fmt(&user_id, f)?;
131
132 f.write_str(") is not present in the cache")
133 }
134 ChannelErrorType::ParentChannelNotPresent { thread_id } => {
135 f.write_str("thread ")?;
136 Display::fmt(&thread_id, f)?;
137
138 f.write_str(" has no parent")
139 }
140 ChannelErrorType::RoleUnavailable { role_id } => {
141 f.write_str("member has role ")?;
142 Display::fmt(&role_id, f)?;
143
144 f.write_str(" but it is not present in the cache")
145 }
146 }
147 }
148}
149
150impl Error for ChannelError {}
151
152#[derive(Debug)]
154#[non_exhaustive]
155pub enum ChannelErrorType {
156 ChannelNotInGuild {
160 channel_id: Id<ChannelMarker>,
162 },
163 ChannelUnavailable {
165 channel_id: Id<ChannelMarker>,
167 },
168 MemberUnavailable {
173 guild_id: Id<GuildMarker>,
175 user_id: Id<UserMarker>,
177 },
178 ParentChannelNotPresent {
180 thread_id: Id<ChannelMarker>,
182 },
183 RoleUnavailable {
190 role_id: Id<RoleMarker>,
192 },
193}
194
195#[derive(Debug)]
197pub struct RootError {
198 kind: RootErrorType,
199 source: Option<Box<dyn Error + Send + Sync>>,
200}
201
202impl RootError {
203 #[must_use = "retrieving the type has no effect if left unused"]
205 pub const fn kind(&self) -> &RootErrorType {
206 &self.kind
207 }
208
209 #[must_use = "consuming the error and retrieving the source has no effect if left unused"]
211 pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
212 self.source
213 }
214
215 #[must_use = "consuming the error into its parts has no effect if left unused"]
217 pub fn into_parts(self) -> (RootErrorType, Option<Box<dyn Error + Send + Sync>>) {
218 (self.kind, self.source)
219 }
220
221 #[allow(clippy::needless_pass_by_value)]
224 fn from_member_roles(member_roles_error: MemberRolesErrorType) -> Self {
225 Self {
226 kind: match member_roles_error {
227 MemberRolesErrorType::RoleMissing { role_id } => {
228 RootErrorType::RoleUnavailable { role_id }
229 }
230 },
231 source: None,
232 }
233 }
234}
235
236impl Display for RootError {
237 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
238 match self.kind {
239 RootErrorType::MemberUnavailable { guild_id, user_id } => {
240 f.write_str("member (guild: ")?;
241 Display::fmt(&guild_id, f)?;
242 f.write_str("; user: ")?;
243 Display::fmt(&user_id, f)?;
244
245 f.write_str(") is not present in the cache")
246 }
247 RootErrorType::RoleUnavailable { role_id } => {
248 f.write_str("member has role ")?;
249 Display::fmt(&role_id, f)?;
250
251 f.write_str(" but it is not present in the cache")
252 }
253 }
254 }
255}
256
257impl Error for RootError {}
258
259#[derive(Debug)]
261#[non_exhaustive]
262pub enum RootErrorType {
263 MemberUnavailable {
268 guild_id: Id<GuildMarker>,
270 user_id: Id<UserMarker>,
272 },
273 RoleUnavailable {
280 role_id: Id<RoleMarker>,
282 },
283}
284
285enum MemberRolesErrorType {
288 RoleMissing { role_id: Id<RoleMarker> },
290}
291
292struct MemberRoles {
294 assigned: Vec<(Id<RoleMarker>, Permissions)>,
296 everyone: Permissions,
298}
299
300#[allow(clippy::type_complexity)]
302#[derive(Clone, Debug)]
303#[must_use = "has no effect if unused"]
304pub struct InMemoryCachePermissions<'a, CacheModels: CacheableModels> {
305 cache: &'a InMemoryCache<CacheModels>,
306 check_member_communication_disabled: bool,
307}
308
309impl<'a, CacheModels: CacheableModels> InMemoryCachePermissions<'a, CacheModels> {
310 #[allow(clippy::type_complexity)]
311 pub(super) const fn new(cache: &'a InMemoryCache<CacheModels>) -> Self {
312 Self {
313 cache,
314 check_member_communication_disabled: true,
315 }
316 }
317
318 #[allow(clippy::type_complexity)]
320 pub const fn cache_ref(&'a self) -> &'a InMemoryCache<CacheModels> {
321 self.cache
322 }
323
324 #[allow(clippy::type_complexity)]
327 pub const fn into_cache(self) -> &'a InMemoryCache<CacheModels> {
328 self.cache
329 }
330
331 pub const fn check_member_communication_disabled(
340 mut self,
341 check_member_communication_disabled: bool,
342 ) -> Self {
343 self.check_member_communication_disabled = check_member_communication_disabled;
344
345 self
346 }
347
348 pub fn in_channel(
401 &self,
402 user_id: Id<UserMarker>,
403 channel_id: Id<ChannelMarker>,
404 ) -> Result<Permissions, ChannelError> {
405 let channel = self.cache.channels.get(&channel_id).ok_or(ChannelError {
406 kind: ChannelErrorType::ChannelUnavailable { channel_id },
407 source: None,
408 })?;
409
410 let guild_id = channel.guild_id().ok_or(ChannelError {
411 kind: ChannelErrorType::ChannelNotInGuild { channel_id },
412 source: None,
413 })?;
414
415 if self.is_owner(user_id, guild_id) {
416 return Ok(Permissions::all());
417 }
418
419 let member = self.cache.member(guild_id, user_id).ok_or(ChannelError {
420 kind: ChannelErrorType::MemberUnavailable { guild_id, user_id },
421 source: None,
422 })?;
423
424 let MemberRoles { assigned, everyone } = self
425 .member_roles(guild_id, &member)
426 .map_err(ChannelError::from_member_roles)?;
427
428 let overwrites = match channel.kind() {
429 ChannelType::AnnouncementThread
430 | ChannelType::PrivateThread
431 | ChannelType::PublicThread => self.parent_overwrites(&channel)?,
432 _ => channel.permission_overwrites().unwrap_or_default().to_vec(),
433 };
434
435 let calculator =
436 PermissionCalculator::new(guild_id, user_id, everyone, assigned.as_slice());
437
438 let permissions = calculator.in_channel(channel.kind(), overwrites.as_slice());
439
440 Ok(self.disable_member_communication(&member, permissions))
441 }
442
443 pub fn root(
491 &self,
492 user_id: Id<UserMarker>,
493 guild_id: Id<GuildMarker>,
494 ) -> Result<Permissions, RootError> {
495 if self.is_owner(user_id, guild_id) {
496 return Ok(Permissions::all());
497 }
498
499 let member = self.cache.member(guild_id, user_id).ok_or(RootError {
500 kind: RootErrorType::MemberUnavailable { guild_id, user_id },
501 source: None,
502 })?;
503
504 let MemberRoles { assigned, everyone } = self
505 .member_roles(guild_id, &member)
506 .map_err(RootError::from_member_roles)?;
507 let calculator =
508 PermissionCalculator::new(guild_id, user_id, everyone, assigned.as_slice());
509
510 let permissions = calculator.root();
511
512 Ok(self.disable_member_communication(&member, permissions))
513 }
514
515 fn disable_member_communication(
526 &self,
527 member: &CacheModels::Member,
528 permissions: Permissions,
529 ) -> Permissions {
530 if !self.check_member_communication_disabled
532 || permissions.contains(Permissions::ADMINISTRATOR)
533 {
534 return permissions;
535 }
536
537 let micros = if let Some(until) = member.communication_disabled_until() {
538 until.as_micros()
539 } else {
540 return permissions;
541 };
542
543 let Ok(absolute) = micros.try_into() else {
544 return permissions;
545 };
546
547 let ends = SystemTime::UNIX_EPOCH + Duration::from_micros(absolute);
548 let now = SystemTime::now();
549
550 if now > ends {
551 return permissions;
552 }
553
554 permissions.intersection(MEMBER_COMMUNICATION_DISABLED_ALLOWLIST)
555 }
556
557 fn is_owner(&self, user_id: Id<UserMarker>, guild_id: Id<GuildMarker>) -> bool {
562 self.cache
563 .guilds
564 .get(&guild_id)
565 .is_some_and(|r| r.owner_id() == user_id)
566 }
567
568 fn member_roles(
576 &self,
577 guild_id: Id<GuildMarker>,
578 member: &'a CacheModels::Member,
579 ) -> Result<MemberRoles, MemberRolesErrorType> {
580 let mut member_roles = Vec::with_capacity(member.roles().len());
581
582 for role_id in member.roles() {
583 let Some(role) = self.cache.roles.get(role_id) else {
584 return Err(MemberRolesErrorType::RoleMissing { role_id: *role_id });
585 };
586
587 member_roles.push((*role_id, role.permissions()));
588 }
589
590 let everyone_role_id = guild_id.cast();
591
592 if let Some(everyone_role) = self.cache.roles.get(&everyone_role_id) {
593 Ok(MemberRoles {
594 assigned: member_roles,
595 everyone: everyone_role.permissions(),
596 })
597 } else {
598 Err(MemberRolesErrorType::RoleMissing {
599 role_id: everyone_role_id,
600 })
601 }
602 }
603
604 fn parent_overwrites(
607 &self,
608 thread: &CacheModels::Channel,
609 ) -> Result<Vec<PermissionOverwrite>, ChannelError> {
610 let parent_id = thread.parent_id().ok_or(ChannelError {
611 kind: ChannelErrorType::ParentChannelNotPresent {
612 thread_id: thread.id(),
613 },
614 source: None,
615 })?;
616
617 let channel = self.cache.channels.get(&parent_id).ok_or(ChannelError {
618 kind: ChannelErrorType::ChannelUnavailable {
619 channel_id: parent_id,
620 },
621 source: None,
622 })?;
623
624 if channel.guild_id().is_some() {
625 let channel_overwrites = channel.permission_overwrites().unwrap_or_default();
626 let thread_overwrites = thread.permission_overwrites().unwrap_or_default();
627
628 let mut overwrites =
629 Vec::with_capacity(channel_overwrites.len() + thread_overwrites.len());
630
631 overwrites.extend_from_slice(channel_overwrites);
632 overwrites.extend_from_slice(thread_overwrites);
633
634 Ok(overwrites)
635 } else {
636 Err(ChannelError {
637 kind: ChannelErrorType::ChannelNotInGuild {
638 channel_id: channel.id(),
639 },
640 source: None,
641 })
642 }
643 }
644}
645
646#[cfg(test)]
647mod tests {
648 use super::{
649 ChannelError, ChannelErrorType, InMemoryCachePermissions, RootError, RootErrorType,
650 };
651 use crate::{test, DefaultCacheModels, DefaultInMemoryCache};
652 use static_assertions::{assert_fields, assert_impl_all};
653 use std::{
654 error::Error,
655 fmt::Debug,
656 str::FromStr,
657 time::{Duration, SystemTime},
658 };
659 use twilight_model::{
660 channel::{
661 permission_overwrite::{PermissionOverwrite, PermissionOverwriteType},
662 Channel, ChannelType,
663 },
664 gateway::payload::incoming::{
665 ChannelCreate, GuildCreate, MemberAdd, MemberUpdate, RoleCreate, ThreadCreate,
666 },
667 guild::{
668 AfkTimeout, DefaultMessageNotificationLevel, ExplicitContentFilter, Guild, MfaLevel,
669 NSFWLevel, Permissions, PremiumTier, Role, SystemChannelFlags, VerificationLevel,
670 },
671 id::{
672 marker::{ChannelMarker, GuildMarker, RoleMarker, UserMarker},
673 Id,
674 },
675 util::Timestamp,
676 };
677
678 assert_fields!(ChannelErrorType::ChannelUnavailable: channel_id);
679 assert_fields!(ChannelErrorType::MemberUnavailable: guild_id, user_id);
680 assert_fields!(ChannelErrorType::RoleUnavailable: role_id);
681 assert_impl_all!(ChannelErrorType: Debug, Send, Sync);
682 assert_impl_all!(ChannelError: Debug, Send, Sync);
683 assert_impl_all!(InMemoryCachePermissions<'_, DefaultCacheModels>: Clone, Debug, Send, Sync);
684 assert_fields!(RootErrorType::MemberUnavailable: guild_id, user_id);
685 assert_fields!(RootErrorType::RoleUnavailable: role_id);
686 assert_impl_all!(RootErrorType: Debug, Send, Sync);
687 assert_impl_all!(RootError: Debug, Send, Sync);
688
689 const GUILD_ID: Id<GuildMarker> = Id::new(1);
691
692 const EVERYONE_ROLE_ID: Id<RoleMarker> = GUILD_ID.cast();
694
695 const USER_ID: Id<UserMarker> = Id::new(2);
697
698 const OTHER_ROLE_ID: Id<RoleMarker> = Id::new(3);
700
701 const OWNER_ID: Id<UserMarker> = Id::new(4);
703
704 const CHANNEL_ID: Id<ChannelMarker> = GUILD_ID.cast();
708
709 const THREAD_ID: Id<ChannelMarker> = Id::new(5);
711
712 const SAFETY_ALERTS_CHANNEL_ID: Id<ChannelMarker> = Id::new(6);
714
715 fn base_guild() -> Guild {
716 Guild {
717 id: GUILD_ID,
718 afk_channel_id: None,
719 afk_timeout: AfkTimeout::FIVE_MINUTES,
720 application_id: None,
721 banner: None,
722 channels: Vec::new(),
723 default_message_notifications: DefaultMessageNotificationLevel::Mentions,
724 description: None,
725 discovery_splash: None,
726 emojis: Vec::new(),
727 explicit_content_filter: ExplicitContentFilter::AllMembers,
728 features: Vec::new(),
729 guild_scheduled_events: Vec::new(),
730 icon: None,
731 joined_at: None,
732 large: false,
733 max_members: None,
734 max_presences: None,
735 max_stage_video_channel_users: None,
736 member_count: None,
737 members: Vec::new(),
738 mfa_level: MfaLevel::Elevated,
739 name: "this is a guild".to_owned(),
740 nsfw_level: NSFWLevel::AgeRestricted,
741 owner: Some(false),
742 owner_id: OWNER_ID,
743 permissions: None,
744 preferred_locale: "en-GB".to_owned(),
745 premium_progress_bar_enabled: false,
746 premium_subscription_count: Some(0),
747 premium_tier: PremiumTier::None,
748 presences: Vec::new(),
749 public_updates_channel_id: None,
750 roles: Vec::from([
751 role_with_permissions(
754 EVERYONE_ROLE_ID,
755 Permissions::CREATE_INVITE | Permissions::VIEW_AUDIT_LOG,
756 ),
757 ]),
758 safety_alerts_channel_id: Some(SAFETY_ALERTS_CHANNEL_ID),
759 splash: None,
760 stage_instances: Vec::new(),
761 stickers: Vec::new(),
762 system_channel_id: None,
763 system_channel_flags: SystemChannelFlags::SUPPRESS_JOIN_NOTIFICATIONS,
764 threads: Vec::new(),
765 rules_channel_id: None,
766 unavailable: Some(false),
767 verification_level: VerificationLevel::VeryHigh,
768 voice_states: Vec::new(),
769 vanity_url_code: None,
770 widget_channel_id: None,
771 widget_enabled: None,
772 max_video_channel_users: None,
773 approximate_member_count: None,
774 approximate_presence_count: None,
775 }
776 }
777
778 fn channel() -> Channel {
779 Channel {
780 application_id: None,
781 applied_tags: None,
782 available_tags: None,
783 bitrate: None,
784 default_auto_archive_duration: None,
785 default_forum_layout: None,
786 default_reaction_emoji: None,
787 default_sort_order: None,
788 default_thread_rate_limit_per_user: None,
789 flags: None,
790 guild_id: Some(GUILD_ID),
791 icon: None,
792 id: CHANNEL_ID,
793 invitable: None,
794 kind: ChannelType::GuildText,
795 last_message_id: None,
796 last_pin_timestamp: None,
797 managed: None,
798 member: None,
799 member_count: None,
800 message_count: None,
801 name: Some("test".to_owned()),
802 newly_created: None,
803 nsfw: Some(false),
804 owner_id: None,
805 parent_id: None,
806 permission_overwrites: Some(Vec::from([
807 PermissionOverwrite {
808 allow: Permissions::empty(),
809 deny: Permissions::CREATE_INVITE,
810 id: EVERYONE_ROLE_ID.cast(),
811 kind: PermissionOverwriteType::Role,
812 },
813 PermissionOverwrite {
814 allow: Permissions::EMBED_LINKS,
815 deny: Permissions::empty(),
816 id: USER_ID.cast(),
817 kind: PermissionOverwriteType::Member,
818 },
819 ])),
820 position: Some(0),
821 rate_limit_per_user: None,
822 recipients: None,
823 rtc_region: None,
824 thread_metadata: None,
825 topic: None,
826 user_limit: None,
827 video_quality_mode: None,
828 }
829 }
830
831 fn thread() -> Channel {
832 Channel {
833 application_id: None,
834 applied_tags: None,
835 available_tags: None,
836 bitrate: None,
837 default_auto_archive_duration: None,
838 default_forum_layout: None,
839 default_reaction_emoji: None,
840 default_sort_order: None,
841 default_thread_rate_limit_per_user: None,
842 flags: None,
843 guild_id: Some(GUILD_ID),
844 icon: None,
845 id: THREAD_ID,
846 invitable: None,
847 kind: ChannelType::PublicThread,
848 last_message_id: None,
849 last_pin_timestamp: None,
850 managed: None,
851 member: None,
852 member_count: None,
853 message_count: None,
854 name: Some("test thread".to_owned()),
855 newly_created: None,
856 nsfw: Some(false),
857 owner_id: None,
858 parent_id: Some(CHANNEL_ID),
859 permission_overwrites: Some(Vec::from([PermissionOverwrite {
860 allow: Permissions::ATTACH_FILES,
861 deny: Permissions::empty(),
862 id: EVERYONE_ROLE_ID.cast(),
863 kind: PermissionOverwriteType::Role,
864 }])),
865 position: Some(0),
866 rate_limit_per_user: None,
867 recipients: None,
868 rtc_region: None,
869 thread_metadata: None,
870 topic: None,
871 user_limit: None,
872 video_quality_mode: None,
873 }
874 }
875
876 fn role_with_permissions(id: Id<RoleMarker>, permissions: Permissions) -> Role {
877 let mut role = test::role(id);
878 role.permissions = permissions;
879
880 role
881 }
882
883 const fn role_create(guild_id: Id<GuildMarker>, role: Role) -> RoleCreate {
884 RoleCreate { guild_id, role }
885 }
886
887 #[test]
892 fn root_errors() {
893 let cache = DefaultInMemoryCache::new();
894 let permissions = cache.permissions();
895 assert!(matches!(
896 permissions.root(USER_ID, GUILD_ID).unwrap_err().kind(),
897 &RootErrorType::MemberUnavailable { guild_id: g_id, user_id: u_id }
898 if g_id == GUILD_ID && u_id == USER_ID
899 ));
900
901 cache.update(&MemberAdd {
902 guild_id: GUILD_ID,
903 member: test::member(USER_ID),
904 });
905
906 assert!(matches!(
907 permissions.root(USER_ID, GUILD_ID).unwrap_err().kind(),
908 &RootErrorType::RoleUnavailable { role_id }
909 if role_id == EVERYONE_ROLE_ID
910 ));
911 }
912
913 #[test]
921 fn root() -> Result<(), Box<dyn Error>> {
922 let joined_at = Some(Timestamp::from_str("2021-09-19T14:17:32.000000+00:00")?);
923
924 let cache = DefaultInMemoryCache::new();
925 let permissions = cache.permissions();
926
927 cache.update(&GuildCreate::Available(base_guild()));
928 cache.update(&MemberAdd {
929 guild_id: GUILD_ID,
930 member: test::member(USER_ID),
931 });
932 cache.update(&MemberUpdate {
933 avatar: None,
934 communication_disabled_until: None,
935 guild_id: GUILD_ID,
936 deaf: None,
937 flags: None,
938 joined_at,
939 mute: None,
940 nick: None,
941 pending: false,
942 premium_since: None,
943 roles: Vec::from([OTHER_ROLE_ID]),
944 user: test::user(USER_ID),
945 });
946 cache.update(&role_create(
947 GUILD_ID,
948 role_with_permissions(
949 OTHER_ROLE_ID,
950 Permissions::SEND_MESSAGES | Permissions::BAN_MEMBERS,
951 ),
952 ));
953
954 let expected = Permissions::CREATE_INVITE
955 | Permissions::BAN_MEMBERS
956 | Permissions::VIEW_AUDIT_LOG
957 | Permissions::SEND_MESSAGES;
958
959 assert_eq!(expected, permissions.root(USER_ID, GUILD_ID)?);
960
961 Ok(())
962 }
963
964 #[test]
970 fn in_channel() -> Result<(), Box<dyn Error>> {
971 let cache = DefaultInMemoryCache::new();
972 let permissions = cache.permissions();
973
974 cache.update(&GuildCreate::Available(base_guild()));
975 assert!(matches!(
976 permissions.in_channel(USER_ID, CHANNEL_ID).unwrap_err().kind(),
977 ChannelErrorType::ChannelUnavailable { channel_id: c_id }
978 if *c_id == CHANNEL_ID
979 ));
980
981 cache.update(&ChannelCreate(channel()));
982 assert!(matches!(
983 permissions.in_channel(USER_ID, CHANNEL_ID).unwrap_err().kind(),
984 ChannelErrorType::MemberUnavailable { guild_id: g_id, user_id: u_id }
985 if *g_id == GUILD_ID && *u_id == USER_ID
986 ));
987 let mut member = test::member(USER_ID);
988 member.roles.push(OTHER_ROLE_ID);
989
990 cache.update(&MemberAdd {
991 guild_id: GUILD_ID,
992 member,
993 });
994 assert!(matches!(
995 permissions.in_channel(USER_ID, CHANNEL_ID).unwrap_err().kind(),
996 &ChannelErrorType::RoleUnavailable { role_id }
997 if role_id == OTHER_ROLE_ID
998 ));
999
1000 cache.update(&role_create(
1001 GUILD_ID,
1002 role_with_permissions(
1003 OTHER_ROLE_ID,
1004 Permissions::SEND_MESSAGES | Permissions::BAN_MEMBERS,
1005 ),
1006 ));
1007
1008 assert_eq!(
1009 Permissions::EMBED_LINKS | Permissions::SEND_MESSAGES,
1010 permissions.in_channel(USER_ID, CHANNEL_ID)?,
1011 );
1012
1013 cache.update(&ThreadCreate(thread()));
1014
1015 assert_eq!(
1016 Permissions::EMBED_LINKS | Permissions::SEND_MESSAGES | Permissions::ATTACH_FILES,
1017 permissions.in_channel(USER_ID, THREAD_ID)?
1018 );
1019
1020 Ok(())
1021 }
1022
1023 #[test]
1032 fn owner() -> Result<(), Box<dyn Error>> {
1033 let cache = DefaultInMemoryCache::new();
1034 let permissions = cache.permissions();
1035 cache.update(&GuildCreate::Available(base_guild()));
1036
1037 assert!(permissions.root(OWNER_ID, GUILD_ID)?.is_all());
1038
1039 cache.update(&ChannelCreate(channel()));
1040 assert!(permissions.in_channel(OWNER_ID, CHANNEL_ID)?.is_all());
1041
1042 Ok(())
1043 }
1044
1045 #[test]
1059 fn member_communication_disabled() -> Result<(), Box<dyn Error>> {
1060 fn acceptable_time(in_future: bool) -> Result<Timestamp, Box<dyn Error>> {
1061 const TIME_RANGE: Duration = Duration::from_secs(60);
1062
1063 let now = SystemTime::now();
1064
1065 let system_time = if in_future {
1066 now + TIME_RANGE
1067 } else {
1068 now - TIME_RANGE
1069 };
1070
1071 let since = system_time.duration_since(SystemTime::UNIX_EPOCH)?;
1072 let micros = since.as_micros().try_into()?;
1073
1074 Timestamp::from_micros(micros).map_err(From::from)
1075 }
1076
1077 let cache = DefaultInMemoryCache::new();
1078 let mut permissions = cache.permissions();
1079
1080 let in_past = acceptable_time(false)?;
1081 let in_future = acceptable_time(true)?;
1082
1083 let mut guild = base_guild();
1084 let everyone_permissions = Permissions::CREATE_INVITE
1085 | Permissions::READ_MESSAGE_HISTORY
1086 | Permissions::VIEW_AUDIT_LOG
1087 | Permissions::VIEW_CHANNEL;
1088 guild.roles = Vec::from([role_with_permissions(
1089 EVERYONE_ROLE_ID,
1090 everyone_permissions,
1091 )]);
1092
1093 cache.update(&GuildCreate::Available(guild));
1094 let mut member = test::member(USER_ID);
1095 member.communication_disabled_until = Some(in_future);
1096 cache.update(&MemberAdd {
1097 guild_id: GUILD_ID,
1098 member,
1099 });
1100 assert_eq!(
1101 Permissions::VIEW_CHANNEL | Permissions::READ_MESSAGE_HISTORY,
1102 permissions.root(USER_ID, GUILD_ID)?
1103 );
1104
1105 cache.update(&ChannelCreate(channel()));
1106 assert_eq!(
1107 Permissions::VIEW_CHANNEL | Permissions::READ_MESSAGE_HISTORY,
1108 permissions.in_channel(USER_ID, CHANNEL_ID)?
1109 );
1110
1111 permissions = permissions.check_member_communication_disabled(false);
1113 assert_eq!(everyone_permissions, permissions.root(USER_ID, GUILD_ID)?);
1114 permissions = permissions.check_member_communication_disabled(true);
1115
1116 cache.update(&role_create(
1118 GUILD_ID,
1119 role_with_permissions(OTHER_ROLE_ID, Permissions::ADMINISTRATOR),
1120 ));
1121 cache.update(&MemberUpdate {
1122 avatar: None,
1123 communication_disabled_until: Some(in_past),
1124 guild_id: GUILD_ID,
1125 deaf: None,
1126 flags: None,
1127 joined_at: Some(Timestamp::from_secs(1).unwrap()),
1128 mute: None,
1129 nick: None,
1130 pending: false,
1131 premium_since: None,
1132 roles: Vec::from([OTHER_ROLE_ID]),
1133 user: test::user(USER_ID),
1134 });
1135 assert_eq!(Permissions::all(), permissions.root(USER_ID, GUILD_ID)?);
1136
1137 Ok(())
1138 }
1139}