aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar S. Co1 <[email protected]>2020-03-20 16:30:42 -0400
committerGravatar GitHub <[email protected]>2020-03-20 16:30:42 -0400
commit44b33d570642905d4eeb64300a3a2d3d0cb80b72 (patch)
tree048a2bf6ea3e1aa80cf059449a5102e3a638ca8c
parentMerge pull request #530 from python-discord/spoiler-check (diff)
parentChanged a logging level (diff)
Merge pull request #821 from python-discord/hemlock-perma-ban-watch-removal
Automatically Remove Users from BigBrother Watch List on Perma Ban
-rw-r--r--bot/cogs/moderation/infractions.py22
-rw-r--r--bot/cogs/verification.py71
-rw-r--r--bot/cogs/watchchannels/bigbrother.py45
3 files changed, 94 insertions, 44 deletions
diff --git a/bot/cogs/moderation/infractions.py b/bot/cogs/moderation/infractions.py
index 9ea17b2b3..efa19f59e 100644
--- a/bot/cogs/moderation/infractions.py
+++ b/bot/cogs/moderation/infractions.py
@@ -67,7 +67,7 @@ class Infractions(InfractionScheduler, commands.Cog):
@command()
async def ban(self, ctx: Context, user: FetchedMember, *, reason: str = None) -> None:
- """Permanently ban a user for the given reason."""
+ """Permanently ban a user for the given reason and stop watching them with Big Brother."""
await self.apply_ban(ctx, user, reason)
# endregion
@@ -230,7 +230,11 @@ class Infractions(InfractionScheduler, commands.Cog):
@respect_role_hierarchy()
async def apply_ban(self, ctx: Context, user: UserSnowflake, reason: str, **kwargs) -> None:
- """Apply a ban infraction with kwargs passed to `post_infraction`."""
+ """
+ Apply a ban infraction with kwargs passed to `post_infraction`.
+
+ Will also remove the banned user from the Big Brother watch list if applicable.
+ """
if await utils.has_active_infraction(ctx, user, "ban"):
return
@@ -243,6 +247,20 @@ class Infractions(InfractionScheduler, commands.Cog):
action = ctx.guild.ban(user, reason=reason, delete_message_days=0)
await self.apply_infraction(ctx, infraction, user, action)
+ if infraction.get('expires_at') is not None:
+ log.trace(f"Ban isn't permanent; user {user} won't be unwatched by Big Brother.")
+ return
+
+ bb_cog = self.bot.get_cog("Big Brother")
+ if not bb_cog:
+ log.error(f"Big Brother cog not loaded; perma-banned user {user} won't be unwatched.")
+ return
+
+ log.trace(f"Big Brother cog loaded; attempting to unwatch perma-banned user {user}.")
+
+ bb_reason = "User has been permanently banned from the server. Automatically removed."
+ await bb_cog.apply_unwatch(ctx, user, bb_reason, send_message=False)
+
# endregion
# region: Base pardon functions
diff --git a/bot/cogs/verification.py b/bot/cogs/verification.py
index 57b50c34f..107bc1058 100644
--- a/bot/cogs/verification.py
+++ b/bot/cogs/verification.py
@@ -6,13 +6,9 @@ from discord import Colour, Forbidden, Message, NotFound, Object
from discord.ext import tasks
from discord.ext.commands import Cog, Context, command
+from bot import constants
from bot.bot import Bot
from bot.cogs.moderation import ModLog
-from bot.constants import (
- Bot as BotConfig,
- Channels, Colours, Event,
- Filter, Icons, MODERATION_ROLES, Roles
-)
from bot.decorators import InChannelCheckFailure, in_channel, without_role
from bot.utils.checks import without_role_check
@@ -29,18 +25,23 @@ your information removed here as well.
Feel free to review them at any point!
-Additionally, if you'd like to receive notifications for the announcements we post in <#{Channels.announcements}> \
-from time to time, you can send `!subscribe` to <#{Channels.bot_commands}> at any time to assign yourself the \
-**Announcements** role. We'll mention this role every time we make an announcement.
+Additionally, if you'd like to receive notifications for the announcements \
+we post in <#{constants.Channels.announcements}>
+from time to time, you can send `!subscribe` to <#{constants.Channels.bot_commands}> at any time \
+to assign yourself the **Announcements** role. We'll mention this role every time we make an announcement.
If you'd like to unsubscribe from the announcement notifications, simply send `!unsubscribe` to \
-<#{Channels.bot_commands}>.
+<#{constants.Channels.bot_commands}>.
"""
-PERIODIC_PING = (
- f"@everyone To verify that you have read our rules, please type `{BotConfig.prefix}accept`."
- f" If you encounter any problems during the verification process, ping the <@&{Roles.admins}> role in this channel."
-)
+if constants.DEBUG_MODE:
+ PERIODIC_PING = "Periodic checkpoint message successfully sent."
+else:
+ PERIODIC_PING = (
+ f"@everyone To verify that you have read our rules, please type `{constants.Bot.prefix}accept`."
+ " If you encounter any problems during the verification process, "
+ f"ping the <@&{constants.Roles.admins}> role in this channel."
+ )
BOT_MESSAGE_DELETE_DELAY = 10
@@ -59,7 +60,7 @@ class Verification(Cog):
@Cog.listener()
async def on_message(self, message: Message) -> None:
"""Check new message event for messages to the checkpoint channel & process."""
- if message.channel.id != Channels.verification:
+ if message.channel.id != constants.Channels.verification:
return # Only listen for #checkpoint messages
if message.author.bot:
@@ -85,20 +86,20 @@ class Verification(Cog):
# Send pretty mod log embed to mod-alerts
await self.mod_log.send_log_message(
- icon_url=Icons.filtering,
- colour=Colour(Colours.soft_red),
+ icon_url=constants.Icons.filtering,
+ colour=Colour(constants.Colours.soft_red),
title=f"User/Role mentioned in {message.channel.name}",
text=embed_text,
thumbnail=message.author.avatar_url_as(static_format="png"),
- channel_id=Channels.mod_alerts,
- ping_everyone=Filter.ping_everyone,
+ channel_id=constants.Channels.mod_alerts,
+ ping_everyone=constants.Filter.ping_everyone,
)
- ctx: Context = await self.bot.get_context(message)
+ ctx: Context = await self.get_context(message)
if ctx.command is not None and ctx.command.name == "accept":
return
- if any(r.id == Roles.verified for r in ctx.author.roles):
+ if any(r.id == constants.Roles.verified for r in ctx.author.roles):
log.info(
f"{ctx.author} posted '{ctx.message.content}' "
"in the verification channel, but is already verified."
@@ -120,12 +121,12 @@ class Verification(Cog):
await ctx.message.delete()
@command(name='accept', aliases=('verify', 'verified', 'accepted'), hidden=True)
- @without_role(Roles.verified)
- @in_channel(Channels.verification)
+ @without_role(constants.Roles.verified)
+ @in_channel(constants.Channels.verification)
async def accept_command(self, ctx: Context, *_) -> None: # We don't actually care about the args
"""Accept our rules and gain access to the rest of the server."""
log.debug(f"{ctx.author} called !accept. Assigning the 'Developer' role.")
- await ctx.author.add_roles(Object(Roles.verified), reason="Accepted the rules")
+ await ctx.author.add_roles(Object(constants.Roles.verified), reason="Accepted the rules")
try:
await ctx.author.send(WELCOME_MESSAGE)
except Forbidden:
@@ -133,17 +134,17 @@ class Verification(Cog):
finally:
log.trace(f"Deleting accept message by {ctx.author}.")
with suppress(NotFound):
- self.mod_log.ignore(Event.message_delete, ctx.message.id)
+ self.mod_log.ignore(constants.Event.message_delete, ctx.message.id)
await ctx.message.delete()
@command(name='subscribe')
- @in_channel(Channels.bot_commands)
+ @in_channel(constants.Channels.bot_commands)
async def subscribe_command(self, ctx: Context, *_) -> None: # We don't actually care about the args
"""Subscribe to announcement notifications by assigning yourself the role."""
has_role = False
for role in ctx.author.roles:
- if role.id == Roles.announcements:
+ if role.id == constants.Roles.announcements:
has_role = True
break
@@ -152,22 +153,22 @@ class Verification(Cog):
return
log.debug(f"{ctx.author} called !subscribe. Assigning the 'Announcements' role.")
- await ctx.author.add_roles(Object(Roles.announcements), reason="Subscribed to announcements")
+ await ctx.author.add_roles(Object(constants.Roles.announcements), reason="Subscribed to announcements")
log.trace(f"Deleting the message posted by {ctx.author}.")
await ctx.send(
- f"{ctx.author.mention} Subscribed to <#{Channels.announcements}> notifications.",
+ f"{ctx.author.mention} Subscribed to <#{constants.Channels.announcements}> notifications.",
)
@command(name='unsubscribe')
- @in_channel(Channels.bot_commands)
+ @in_channel(constants.Channels.bot_commands)
async def unsubscribe_command(self, ctx: Context, *_) -> None: # We don't actually care about the args
"""Unsubscribe from announcement notifications by removing the role from yourself."""
has_role = False
for role in ctx.author.roles:
- if role.id == Roles.announcements:
+ if role.id == constants.Roles.announcements:
has_role = True
break
@@ -176,12 +177,12 @@ class Verification(Cog):
return
log.debug(f"{ctx.author} called !unsubscribe. Removing the 'Announcements' role.")
- await ctx.author.remove_roles(Object(Roles.announcements), reason="Unsubscribed from announcements")
+ await ctx.author.remove_roles(Object(constants.Roles.announcements), reason="Unsubscribed from announcements")
log.trace(f"Deleting the message posted by {ctx.author}.")
await ctx.send(
- f"{ctx.author.mention} Unsubscribed from <#{Channels.announcements}> notifications."
+ f"{ctx.author.mention} Unsubscribed from <#{constants.Channels.announcements}> notifications."
)
# This cannot be static (must have a __func__ attribute).
@@ -193,7 +194,7 @@ class Verification(Cog):
@staticmethod
def bot_check(ctx: Context) -> bool:
"""Block any command within the verification channel that is not !accept."""
- if ctx.channel.id == Channels.verification and without_role_check(ctx, *MODERATION_ROLES):
+ if ctx.channel.id == constants.Channels.verification and without_role_check(ctx, *constants.MODERATION_ROLES):
return ctx.command.name == "accept"
else:
return True
@@ -201,7 +202,7 @@ class Verification(Cog):
@tasks.loop(hours=12)
async def periodic_ping(self) -> None:
"""Every week, mention @everyone to remind them to verify."""
- messages = self.bot.get_channel(Channels.verification).history(limit=10)
+ messages = self.bot.get_channel(constants.Channels.verification).history(limit=10)
need_to_post = True # True if a new message needs to be sent.
async for message in messages:
@@ -215,7 +216,7 @@ class Verification(Cog):
break
if need_to_post:
- await self.bot.get_channel(Channels.verification).send(PERIODIC_PING)
+ await self.bot.get_channel(constants.Channels.verification).send(PERIODIC_PING)
@periodic_ping.before_loop
async def before_ping(self) -> None:
diff --git a/bot/cogs/watchchannels/bigbrother.py b/bot/cogs/watchchannels/bigbrother.py
index c601e0d4d..903c87f85 100644
--- a/bot/cogs/watchchannels/bigbrother.py
+++ b/bot/cogs/watchchannels/bigbrother.py
@@ -52,6 +52,21 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
A `reason` for adding the user to Big Brother is required and will be displayed
in the header when relaying messages of this user to the watchchannel.
"""
+ await self.apply_watch(ctx, user, reason)
+
+ @bigbrother_group.command(name='unwatch', aliases=('uw',))
+ @with_role(*MODERATION_ROLES)
+ async def unwatch_command(self, ctx: Context, user: FetchedMember, *, reason: str) -> None:
+ """Stop relaying messages by the given `user`."""
+ await self.apply_unwatch(ctx, user, reason)
+
+ async def apply_watch(self, ctx: Context, user: FetchedMember, reason: str) -> None:
+ """
+ Add `user` to watched users and apply a watch infraction with `reason`.
+
+ A message indicating the result of the operation is sent to `ctx`.
+ The message will include `user`'s previous watch infraction history, if it exists.
+ """
if user.bot:
await ctx.send(f":x: I'm sorry {ctx.author}, I'm afraid I can't do that. I only watch humans.")
return
@@ -90,10 +105,13 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
await ctx.send(msg)
- @bigbrother_group.command(name='unwatch', aliases=('uw',))
- @with_role(*MODERATION_ROLES)
- async def unwatch_command(self, ctx: Context, user: FetchedMember, *, reason: str) -> None:
- """Stop relaying messages by the given `user`."""
+ async def apply_unwatch(self, ctx: Context, user: FetchedMember, reason: str, send_message: bool = True) -> None:
+ """
+ Remove `user` from watched users and mark their infraction as inactive with `reason`.
+
+ If `send_message` is True, a message indicating the result of the operation is sent to
+ `ctx`.
+ """
active_watches = await self.bot.api_client.get(
self.api_endpoint,
params=ChainMap(
@@ -102,6 +120,7 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
)
)
if active_watches:
+ log.trace("Active watches for user found. Attempting to remove.")
[infraction] = active_watches
await self.bot.api_client.patch(
@@ -111,8 +130,20 @@ class BigBrother(WatchChannel, Cog, name="Big Brother"):
await post_infraction(ctx, user, 'watch', f"Unwatched: {reason}", hidden=True, active=False)
- await ctx.send(f":white_check_mark: Messages sent by {user} will no longer be relayed.")
-
self._remove_user(user.id)
+
+ if not send_message: # Prevents a message being sent to the channel if part of a permanent ban
+ log.debug(f"Perma-banned user {user} was unwatched.")
+ return
+ log.trace("User is not banned. Sending message to channel")
+ message = f":white_check_mark: Messages sent by {user} will no longer be relayed."
+
else:
- await ctx.send(":x: The specified user is currently not being watched.")
+ log.trace("No active watches found for user.")
+ if not send_message: # Prevents a message being sent to the channel if part of a permanent ban
+ log.debug(f"{user} was not on the watch list; no removal necessary.")
+ return
+ log.trace("User is not perma banned. Send the error message.")
+ message = ":x: The specified user is currently not being watched."
+
+ await ctx.send(message)