aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Hassan Abouelela <[email protected]>2020-11-22 13:07:46 +0300
committerGravatar Hassan Abouelela <[email protected]>2020-11-22 13:07:46 +0300
commit06f9c48e136644a15044b84a0b25f1b6feba0e09 (patch)
tree945dc9d21eeb1174062acb056260f59c8f6894c7
parentMerge branch 'master' into voicechannel-mute (diff)
Add VC Mute Functionality
Adds and calls a function to force a voice channel member to sync permissions. See #1160 for why this is necessary. Signed-off-by: Hassan Abouelela <[email protected]>
-rw-r--r--bot/exts/moderation/silence.py66
1 files changed, 64 insertions, 2 deletions
diff --git a/bot/exts/moderation/silence.py b/bot/exts/moderation/silence.py
index 314aa946e..415ab19a6 100644
--- a/bot/exts/moderation/silence.py
+++ b/bot/exts/moderation/silence.py
@@ -6,7 +6,7 @@ from operator import attrgetter
from typing import Optional, Union
from async_rediscache import RedisCache
-from discord import TextChannel, VoiceChannel
+from discord import HTTPException, Member, PermissionOverwrite, TextChannel, VoiceChannel
from discord.ext import commands, tasks
from discord.ext.commands import Context
@@ -93,9 +93,13 @@ class Silence(commands.Cog):
await self.bot.wait_until_guild_available()
guild = self.bot.get_guild(Guild.id)
+
self._verified_msg_role = guild.get_role(Roles.verified)
self._verified_voice_role = guild.get_role(Roles.voice_verified)
+ self._helper_role = guild.get_role(Roles.helpers)
+
self._mod_alerts_channel = self.bot.get_channel(Channels.mod_alerts)
+
self.notifier = SilenceNotifier(self.bot.get_channel(Channels.mod_log))
await self._reschedule()
@@ -226,12 +230,70 @@ class Silence(commands.Cog):
else:
overwrite.update(speak=False)
await channel.set_permissions(self._verified_voice_role, overwrite=overwrite)
+ try:
+ await self._force_voice_silence(channel)
+ except HTTPException:
+ # TODO: Relay partial failure to invocation channel
+ pass
await self.previous_overwrites.set(channel.id, json.dumps(prev_overwrites))
return True
- async def _schedule_unsilence(self, ctx: Context, channel: typing.Union[TextChannel, VoiceChannel],
+ async def _force_voice_silence(self, channel: VoiceChannel, member: Optional[Member] = None) -> None:
+ """
+ Move all non-staff members from `channel` to a temporary channel and back to force toggle role mute.
+
+ If `member` is passed, the mute only occurs to that member.
+ Permission modification has to happen before this function.
+
+ Raises `discord.HTTPException` if the task fails.
+ """
+ # Obtain temporary channel
+ afk_channel = channel.guild.afk_channel
+ if afk_channel is None:
+ try:
+ overwrites = {
+ channel.guild.default_role: PermissionOverwrite(speak=False, connect=False, view_channel=False)
+ }
+ afk_channel = await channel.guild.create_voice_channel("mute-temp", overwrites=overwrites)
+ log.info(f"Failed to get afk-channel, created temporary channel #{afk_channel} ({afk_channel.id})")
+
+ # Schedule channel deletion in case function errors out
+ self.scheduler.schedule_later(30, afk_channel.id,
+ afk_channel.delete(reason="Deleting temp mute channel."))
+
+ except HTTPException as e:
+ log.warning("Failed to create temporary mute channel.", exc_info=e)
+ raise e
+
+ # Handle member picking logic
+ if member is not None:
+ members = [member]
+ else:
+ members = channel.members
+
+ # Move all members to temporary channel and back
+ for member in members:
+ # Skip staff
+ if self._helper_role in member.roles:
+ continue
+
+ try:
+ await member.move_to(afk_channel, reason="Muting member.")
+ log.debug(f"Moved {member.name} to afk channel.")
+
+ await member.move_to(channel, reason="Muting member.")
+ log.debug(f"Moved {member.name} to original voice channel.")
+
+ except HTTPException as e:
+ log.warning(f"Failed to move {member.name} while muting, falling back to kick.", exc_info=e)
+ try:
+ await member.move_to(None, reason="Forcing member mute.")
+ except HTTPException:
+ pass
+
+ async def _schedule_unsilence(self, ctx: Context, channel: Union[TextChannel, VoiceChannel],
duration: Optional[int]) -> None:
"""Schedule `ctx.channel` to be unsilenced if `duration` is not None."""
if duration is None: