diff options
-rw-r--r-- | bot/exts/moderation/voice_gate.py | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/bot/exts/moderation/voice_gate.py b/bot/exts/moderation/voice_gate.py index 0cbce6a51..94b23a344 100644 --- a/bot/exts/moderation/voice_gate.py +++ b/bot/exts/moderation/voice_gate.py @@ -8,6 +8,7 @@ from async_rediscache import RedisCache from discord import Colour, Member, VoiceState from discord.ext.commands import Cog, Context, command + from bot.api import ResponseCodeError from bot.bot import Bot from bot.constants import Channels, Event, MODERATION_ROLES, Roles, VoiceGate as GateConf @@ -40,6 +41,12 @@ VOICE_PING = ( "If you don't yet qualify, you'll be told why!" ) +VOICE_PING_DM = ( + "Wondering why you can't talk in the voice channels? " + "Use the `!voiceverify` command in {channel_mention} to verify. " + "If you don't yet qualify, you'll be told why!" +) + class VoiceGate(Cog): """Voice channels verification management.""" @@ -75,35 +82,41 @@ class VoiceGate(Cog): log.trace(f"Voice gate reminder message for user {member_id} was already removed") @redis_cache.atomic_transaction - async def _ping_newcomer(self, member: discord.Member) -> bool: + async def _ping_newcomer(self, member: discord.Member) -> tuple: """ See if `member` should be sent a voice verification notification, and send it if so. - Returns False if the notification was not sent. This happens when: + Returns (False, None) if the notification was not sent. This happens when: * The `member` has already received the notification * The `member` is already voice-verified - Otherwise, the notification message ID is stored in `redis_cache` and True is returned. + Otherwise, the notification message ID is stored in `redis_cache` and return (True, channel). + channel is either [discord.TextChannel, discord.DMChannel]. """ if await self.redis_cache.contains(member.id): log.trace("User already in cache. Ignore.") - return False + return False, None log.trace("User not in cache and is in a voice channel.") verified = any(Roles.voice_verified == role.id for role in member.roles) if verified: log.trace("User is verified, add to the cache and ignore.") await self.redis_cache.set(member.id, NO_MSG) - return False + return False, None log.trace("User is unverified. Send ping.") + await self.bot.wait_until_guild_available() voice_verification_channel = self.bot.get_channel(Channels.voice_gate) - message = await voice_verification_channel.send(f"Hello, {member.mention}! {VOICE_PING}") - await self.redis_cache.set(member.id, message.id) + try: + message = await member.send(VOICE_PING_DM.format(channel_mention=voice_verification_channel.mention)) + except discord.Forbidden: + log.trace("DM failed for Voice ping message. Sending in channel.") + message = await voice_verification_channel.send(f"Hello, {member.mention}! {VOICE_PING}") - return True + await self.redis_cache.set(member.id, message.id) + return True, message.channel @command(aliases=('voiceverify',)) @has_no_roles(Roles.voice_verified) @@ -144,8 +157,12 @@ class VoiceGate(Cog): color=Colour.red() ) log.warning(f"Got response code {e.status} while trying to get {ctx.author.id} Metricity data.") + try: + await ctx.author.send(embed=embed) + except discord.Forbidden: + log.info("Could not send user DM. Sending in voice-verify channel and scheduling delete.") + await ctx.send(embed=embed) - await ctx.author.send(embed=embed) return checks = { @@ -239,11 +256,11 @@ class VoiceGate(Cog): # To avoid race conditions, checking if the user should receive a notification # and sending it if appropriate is delegated to an atomic helper - notification_sent = await self._ping_newcomer(member) + notification_sent, message_channel = await self._ping_newcomer(member) - # Schedule the notification to be deleted after the configured delay, which is + # Schedule the channel ping notification to be deleted after the configured delay, which is # again delegated to an atomic helper - if notification_sent: + if notification_sent and isinstance(message_channel, discord.TextChannel): await asyncio.sleep(GateConf.voice_ping_delete_delay) await self._delete_ping(member.id) |