@@ -15,6 +15,7 @@ import SkillRoles from "./skill-roles.js";
1515import { named_id } from "../../../channel-map.js" ;
1616import { unwrap } from "../../../utils/misc.js" ;
1717import { CommandSetBuilder } from "../../../command-abstractions/command-set-builder.js" ;
18+ import { channel_has_member_with_role } from "../../../utils/discord.js" ;
1819import { set_timeout } from "../../../utils/node.js" ;
1920
2021const categories_map = {
@@ -104,6 +105,7 @@ export default class PermissionManager extends BotComponent {
104105
105106 category_permissions : Partial < Record < string , permission_overwrites > > = { } ;
106107 channel_overwrites : Partial < Record < string , permission_overwrites > > = { } ;
108+ dynamic_channel_overwrites : Partial < Record < string , permission_overwrites > > = { } ;
107109
108110 override async setup ( commands : CommandSetBuilder ) {
109111 await this . channels . resolve ( ) ;
@@ -471,6 +473,11 @@ export default class PermissionManager extends BotComponent {
471473 }
472474
473475 async sync_channel_permissions ( channel : Discord . CategoryChildChannel ) {
476+ if ( channel . id in this . dynamic_channel_overwrites ) {
477+ M . log ( `Setting dynamic permissions for channel ${ channel . id } ${ channel . name } ` ) ;
478+ await this . set_channel_permissions ( channel , unwrap ( this . dynamic_channel_overwrites [ channel . id ] ) ) ;
479+ return ;
480+ }
474481 if ( channel . id in this . channel_overwrites ) {
475482 M . log ( `Setting permissions for channel ${ channel . id } ${ channel . name } ` ) ;
476483 await this . set_channel_permissions ( channel , unwrap ( this . channel_overwrites [ channel . id ] ) ) ;
@@ -487,6 +494,14 @@ export default class PermissionManager extends BotComponent {
487494 ) ;
488495 for ( const channel of category . children . cache . values ( ) ) {
489496 await this . sync_channel_permissions ( channel ) ;
497+ if ( channel . isVoiceBased ( ) ) {
498+ for ( const [ id , member ] of channel . members ) {
499+ if ( await this . wheatley . check_permissions ( member , Discord . PermissionFlagsBits . MuteMembers ) ) {
500+ await this . mod_has_entered_the_building ( channel , member . id ) ;
501+ break ;
502+ }
503+ }
504+ }
490505 }
491506 }
492507
@@ -506,4 +521,83 @@ export default class PermissionManager extends BotComponent {
506521 this . sync_permissions ( ) . catch ( this . wheatley . critical_error . bind ( this . wheatley ) ) ;
507522 } , HOUR ) ;
508523 }
524+
525+ private get_base_permissions (
526+ channel : Discord . VoiceChannel | Discord . StageChannel ,
527+ ) : permission_overwrites | undefined {
528+ if ( this . channel_overwrites [ channel . id ] != null ) {
529+ return this . channel_overwrites [ channel . id ] ;
530+ }
531+ if ( channel . parent != null ) {
532+ return this . category_permissions [ channel . parent . id ] ;
533+ }
534+ return undefined ;
535+ }
536+
537+ private has_moderator_in_channel ( channel : Discord . VoiceChannel | Discord . StageChannel ) : boolean {
538+ return channel . members . some ( member => member . permissions . has ( Discord . PermissionFlagsBits . MuteMembers ) ) ;
539+ }
540+
541+ private async mod_has_entered_the_building (
542+ channel : Discord . VoiceChannel | Discord . StageChannel ,
543+ entering_moderator_id : string ,
544+ ) {
545+ if ( channel . id in this . dynamic_channel_overwrites || channel . id == this . wheatley . guild . afkChannelId ) {
546+ return ;
547+ }
548+ const everyone = this . wheatley . guild . roles . everyone . id ;
549+ const base_perms = this . get_base_permissions ( channel ) ;
550+ if (
551+ ! base_perms ||
552+ ! base_perms [ everyone ] ||
553+ ! base_perms [ everyone ] . deny ||
554+ ! base_perms [ everyone ] . deny . includes ( Discord . PermissionsBitField . Flags . Speak ) ||
555+ ! base_perms [ everyone ] . deny . includes ( Discord . PermissionsBitField . Flags . Stream )
556+ ) {
557+ return ;
558+ }
559+ if ( channel_has_member_with_role ( channel , this . roles . voice_moderator . id , entering_moderator_id ) ) {
560+ return ;
561+ }
562+ const perms = Object . assign ( { } , base_perms ) ;
563+ perms [ everyone ] = {
564+ allow : [
565+ Discord . PermissionsBitField . Flags . Speak ,
566+ Discord . PermissionsBitField . Flags . Stream ,
567+ ...( perms [ everyone ] ?. allow ?? [ ] ) ,
568+ ] ,
569+ deny : perms [ everyone ] ?. deny ,
570+ } ;
571+ this . dynamic_channel_overwrites [ channel . id ] = perms ;
572+ await this . sync_channel_permissions ( channel ) ;
573+ }
574+
575+ private async mod_has_left_the_building ( channel : Discord . VoiceChannel | Discord . StageChannel ) {
576+ if ( ! ( channel . id in this . dynamic_channel_overwrites ) ) {
577+ return ;
578+ }
579+ if ( this . has_moderator_in_channel ( channel ) ) {
580+ return ;
581+ }
582+ delete this . dynamic_channel_overwrites [ channel . id ] ;
583+ await this . sync_channel_permissions ( channel ) ;
584+ }
585+
586+ override async on_voice_state_update ( old_state : Discord . VoiceState , new_state : Discord . VoiceState ) {
587+ if ( new_state . guild . id !== this . wheatley . guild . id ) {
588+ return ;
589+ }
590+ if (
591+ new_state . member &&
592+ new_state . member . permissions . has ( Discord . PermissionFlagsBits . MuteMembers ) &&
593+ new_state . channelId != old_state . channelId
594+ ) {
595+ if ( old_state . channel ) {
596+ await this . mod_has_left_the_building ( old_state . channel ) ;
597+ }
598+ if ( new_state . channel ) {
599+ await this . mod_has_entered_the_building ( new_state . channel , new_state . member . id ) ;
600+ }
601+ }
602+ }
509603}
0 commit comments