aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar MarkKoz <[email protected]>2019-10-25 17:29:28 -0700
committerGravatar MarkKoz <[email protected]>2019-11-04 18:17:29 -0800
commit071bc9d775a48750cc8d44236523c7ec5a30f7f9 (patch)
tree319ac525cea5236723583a87ef9023b07ed95891
parentMerge pull request #618 from python-discord/schedule-superstarify (diff)
Add logging for moderation functions
Diffstat (limited to '')
-rw-r--r--bot/cogs/moderation/scheduler.py51
-rw-r--r--bot/cogs/moderation/superstarify.py21
-rw-r--r--bot/cogs/moderation/utils.py12
-rw-r--r--bot/utils/scheduling.py6
4 files changed, 81 insertions, 9 deletions
diff --git a/bot/cogs/moderation/scheduler.py b/bot/cogs/moderation/scheduler.py
index 7990df226..7a08fc236 100644
--- a/bot/cogs/moderation/scheduler.py
+++ b/bot/cogs/moderation/scheduler.py
@@ -39,6 +39,8 @@ class InfractionScheduler(Scheduler):
"""Schedule expiration for previous infractions."""
await self.bot.wait_until_ready()
+ log.trace(f"Rescheduling infractions for {self.__class__.__name__}.")
+
infractions = await self.bot.api_client.get(
'bot/infractions',
params={'active': 'true'}
@@ -59,6 +61,10 @@ class InfractionScheduler(Scheduler):
# Mark as inactive if less than a minute remains.
if delta < 60:
+ log.info(
+ "Infraction will be deactivated instead of re-applied "
+ "because less than 1 minute remains."
+ )
await self.deactivate_infraction(infraction)
return
@@ -78,6 +84,9 @@ class InfractionScheduler(Scheduler):
icon = utils.INFRACTION_ICONS[infr_type][0]
reason = infraction["reason"]
expiry = infraction["expires_at"]
+ _id = infraction['id']
+
+ log.trace(f"Applying {infr_type} infraction #{_id} to {user}.")
if expiry:
expiry = time.format_infraction(expiry)
@@ -111,10 +120,20 @@ class InfractionScheduler(Scheduler):
log_content = ctx.author.mention
if infraction["actor"] == self.bot.user.id:
+ log.trace(
+ f"Infraction #{_id} actor is bot; including the reason in the confirmation message."
+ )
+
end_msg = f" (reason: {infraction['reason']})"
elif ctx.channel.id not in STAFF_CHANNELS:
+ log.trace(
+ f"Infraction #{_id} context is not in a staff channel; omitting infraction count."
+ )
+
end_msg = ""
else:
+ log.trace(f"Fetching total infraction count for {user}.")
+
infractions = await self.bot.api_client.get(
"bot/infractions",
params={"user__id": str(user.id)}
@@ -124,6 +143,7 @@ class InfractionScheduler(Scheduler):
# Execute the necessary actions to apply the infraction on Discord.
if action_coro:
+ log.trace(f"Awaiting the infraction #{_id} application action coroutine.")
try:
await action_coro
if expiry:
@@ -136,12 +156,16 @@ class InfractionScheduler(Scheduler):
log_content = ctx.author.mention
log_title = "failed to apply"
+ log.warning(f"Failed to apply {infr_type} infraction #{_id} to {user}.")
+
# Send a confirmation message to the invoking context.
+ log.trace(f"Sending infraction #{_id} confirmation message.")
await ctx.send(
f"{dm_result}{confirm_msg} **{infr_type}** to {user.mention}{expiry_msg}{end_msg}."
)
# Send a log message to the mod log.
+ log.trace(f"Sending apply mod log for infraction #{_id}.")
await self.mod_log.send_log_message(
icon_url=icon,
colour=Colours.soft_red,
@@ -157,9 +181,14 @@ class InfractionScheduler(Scheduler):
footer=f"ID {infraction['id']}"
)
+ log.info(f"Applied {infr_type} infraction #{_id} to {user}.")
+
async def pardon_infraction(self, ctx: Context, infr_type: str, user: MemberObject) -> None:
"""Prematurely end an infraction for a user and log the action in the mod log."""
+ log.trace(f"Pardoning {infr_type} infraction for {user}.")
+
# Check the current active infraction
+ log.trace(f"Fetching active {infr_type} infractions for {user}.")
response = await self.bot.api_client.get(
'bot/infractions',
params={
@@ -170,6 +199,7 @@ class InfractionScheduler(Scheduler):
)
if not response:
+ log.debug(f"No active {infr_type} infraction found for {user}.")
await ctx.send(f":x: There's no active {infr_type} infraction for user {user.mention}.")
return
@@ -179,12 +209,16 @@ class InfractionScheduler(Scheduler):
log_text["Member"] = f"{user.mention}(`{user.id}`)"
log_text["Actor"] = str(ctx.message.author)
log_content = None
- footer = f"ID: {response[0]['id']}"
+ _id = response[0]['id']
+ footer = f"ID: {_id}"
# If multiple active infractions were found, mark them as inactive in the database
# and cancel their expiration tasks.
if len(response) > 1:
- log.warning(f"Found more than one active {infr_type} infraction for user {user.id}")
+ log.warning(
+ f"Found more than one active {infr_type} infraction for user {user.id}; "
+ "deactivating the extra active infractions too."
+ )
footer = f"Infraction IDs: {', '.join(str(infr['id']) for infr in response)}"
@@ -227,11 +261,16 @@ class InfractionScheduler(Scheduler):
confirm_msg = ":x: failed to pardon"
log_title = "pardon failed"
log_content = ctx.author.mention
+
+ log.warning(f"Failed to pardon {infr_type} infraction #{_id} for {user}.")
else:
confirm_msg = f":ok_hand: pardoned"
log_title = "pardoned"
+ log.info(f"Pardoned {infr_type} infraction #{_id} for {user}.")
+
# Send a confirmation message to the invoking context.
+ log.trace(f"Sending infraction #{_id} pardon confirmation message.")
await ctx.send(
f"{dm_emoji}{confirm_msg} infraction **{infr_type}** for {user.mention}. "
f"{log_text.get('Failure', '')}"
@@ -268,7 +307,7 @@ class InfractionScheduler(Scheduler):
_type = infraction["type"]
_id = infraction["id"]
- log.debug(f"Marking infraction #{_id} as inactive (expired).")
+ log.info(f"Marking infraction #{_id} as inactive (expired).")
log_content = None
log_text = {
@@ -278,7 +317,9 @@ class InfractionScheduler(Scheduler):
}
try:
+ log.trace("Awaiting the pardon action coroutine.")
returned_log = await self._pardon_action(infraction)
+
if returned_log is not None:
log_text = {**log_text, **returned_log} # Merge the logs together
else:
@@ -296,6 +337,8 @@ class InfractionScheduler(Scheduler):
# Check if the user is currently being watched by Big Brother.
try:
+ log.trace(f"Determining if user {user_id} is currently being watched by Big Brother.")
+
active_watch = await self.bot.api_client.get(
"bot/infractions",
params={
@@ -312,6 +355,7 @@ class InfractionScheduler(Scheduler):
try:
# Mark infraction as inactive in the database.
+ log.trace(f"Marking infraction #{_id} as inactive in the database.")
await self.bot.api_client.patch(
f"bot/infractions/{_id}",
json={"active": False}
@@ -335,6 +379,7 @@ class InfractionScheduler(Scheduler):
if send_log:
log_title = f"expiration failed" if "Failure" in log_text else "expired"
+ log.trace(f"Sending deactivation mod log for infraction #{_id}.")
await self.mod_log.send_log_message(
icon_url=utils.INFRACTION_ICONS[_type][1],
colour=Colours.soft_green,
diff --git a/bot/cogs/moderation/superstarify.py b/bot/cogs/moderation/superstarify.py
index c66222e5a..9ab870823 100644
--- a/bot/cogs/moderation/superstarify.py
+++ b/bot/cogs/moderation/superstarify.py
@@ -34,8 +34,8 @@ class Superstarify(InfractionScheduler, Cog):
return # User didn't change their nickname. Abort!
log.trace(
- f"{before.display_name} is trying to change their nickname to {after.display_name}. "
- "Checking if the user is in superstar-prison..."
+ f"{before} ({before.display_name}) is trying to change their nickname to "
+ f"{after.display_name}. Checking if the user is in superstar-prison..."
)
active_superstarifies = await self.bot.api_client.get(
@@ -48,6 +48,7 @@ class Superstarify(InfractionScheduler, Cog):
)
if not active_superstarifies:
+ log.trace(f"{before} has no active superstar infractions.")
return
infraction = active_superstarifies[0]
@@ -132,15 +133,17 @@ class Superstarify(InfractionScheduler, Cog):
# Post the infraction to the API
reason = reason or f"old nick: {member.display_name}"
infraction = await utils.post_infraction(ctx, member, "superstar", reason, duration)
+ _id = infraction["id"]
old_nick = member.display_name
- forced_nick = self.get_nick(infraction["id"], member.id)
+ forced_nick = self.get_nick(_id, member.id)
expiry_str = format_infraction(infraction["expires_at"])
# Apply the infraction and schedule the expiration task.
+ log.debug(f"Changing nickname of {member} to {forced_nick}.")
self.mod_log.ignore(constants.Event.member_update, member.id)
await member.edit(nick=forced_nick, reason=reason)
- self.schedule_task(ctx.bot.loop, infraction["id"], infraction)
+ self.schedule_task(ctx.bot.loop, _id, infraction)
# Send a DM to the user to notify them of their new infraction.
await utils.notify_infraction(
@@ -152,6 +155,7 @@ class Superstarify(InfractionScheduler, Cog):
)
# Send an embed with the infraction information to the invoking context.
+ log.trace(f"Sending superstar #{_id} embed.")
embed = Embed(
title="Congratulations!",
colour=constants.Colours.soft_orange,
@@ -167,6 +171,7 @@ class Superstarify(InfractionScheduler, Cog):
await ctx.send(embed=embed)
# Log to the mod log channel.
+ log.trace(f"Sending apply mod log for superstar #{_id}.")
await self.mod_log.send_log_message(
icon_url=utils.INFRACTION_ICONS["superstar"][0],
colour=Colour.gold(),
@@ -180,7 +185,7 @@ class Superstarify(InfractionScheduler, Cog):
Old nickname: `{old_nick}`
New nickname: `{forced_nick}`
"""),
- footer=f"ID {infraction['id']}"
+ footer=f"ID {_id}"
)
@command(name="unsuperstarify", aliases=("release_nick", "unstar"))
@@ -198,6 +203,10 @@ class Superstarify(InfractionScheduler, Cog):
# Don't bother sending a notification if the user left the guild.
if not user:
+ log.debug(
+ "User left the guild and therefore won't be notified about superstar "
+ f"{infraction['id']} pardon."
+ )
return {}
# DM the user about the expiration.
@@ -216,6 +225,8 @@ class Superstarify(InfractionScheduler, Cog):
@staticmethod
def get_nick(infraction_id: int, member_id: int) -> str:
"""Randomly select a nickname from the Superstarify nickname list."""
+ log.trace(f"Choosing a random nickname for superstar #{infraction_id}.")
+
rng = random.Random(str(infraction_id) + str(member_id))
return rng.choice(STAR_NAMES)
diff --git a/bot/cogs/moderation/utils.py b/bot/cogs/moderation/utils.py
index 9179c0afb..325b9567a 100644
--- a/bot/cogs/moderation/utils.py
+++ b/bot/cogs/moderation/utils.py
@@ -37,6 +37,8 @@ def proxy_user(user_id: str) -> discord.Object:
Used when a Member or User object cannot be resolved.
"""
+ log.trace(f"Attempting to create a proxy user for the user id {user_id}.")
+
try:
user_id = int(user_id)
except ValueError:
@@ -59,6 +61,8 @@ async def post_infraction(
active: bool = True,
) -> t.Optional[dict]:
"""Posts an infraction to the API."""
+ log.trace(f"Posting {infr_type} infraction for {user} to the API.")
+
payload = {
"actor": ctx.message.author.id,
"hidden": hidden,
@@ -92,6 +96,8 @@ async def post_infraction(
async def has_active_infraction(ctx: Context, user: MemberObject, infr_type: str) -> bool:
"""Checks if a user already has an active infraction of the given type."""
+ log.trace(f"Checking if {user} has active infractions of type {infr_type}.")
+
active_infractions = await ctx.bot.api_client.get(
'bot/infractions',
params={
@@ -101,12 +107,14 @@ async def has_active_infraction(ctx: Context, user: MemberObject, infr_type: str
}
)
if active_infractions:
+ log.trace(f"{user} has active infractions of type {infr_type}.")
await ctx.send(
f":x: According to my records, this user already has a {infr_type} infraction. "
f"See infraction **#{active_infractions[0]['id']}**."
)
return True
else:
+ log.trace(f"{user} does not have active infractions of type {infr_type}.")
return False
@@ -118,6 +126,8 @@ async def notify_infraction(
icon_url: str = Icons.token_removed
) -> bool:
"""DM a user about their new infraction and return True if the DM is successful."""
+ log.trace(f"Sending {user} a DM about their {infr_type} infraction.")
+
embed = discord.Embed(
description=textwrap.dedent(f"""
**Type:** {infr_type.capitalize()}
@@ -146,6 +156,8 @@ async def notify_pardon(
icon_url: str = Icons.user_verified
) -> bool:
"""DM a user about their pardoned infraction and return True if the DM is successful."""
+ log.trace(f"Sending {user} a DM about their pardoned infraction.")
+
embed = discord.Embed(
description=content,
colour=Colours.soft_green
diff --git a/bot/utils/scheduling.py b/bot/utils/scheduling.py
index 08abd91d7..ee6c0a8e6 100644
--- a/bot/utils/scheduling.py
+++ b/bot/utils/scheduling.py
@@ -36,11 +36,15 @@ class Scheduler(metaclass=CogABCMeta):
`task_data` is passed to `Scheduler._scheduled_expiration`
"""
if task_id in self.scheduled_tasks:
+ log.debug(
+ f"{self.cog_name}: did not schedule task #{task_id}; task was already scheduled."
+ )
return
task: asyncio.Task = create_task(loop, self._scheduled_task(task_data))
self.scheduled_tasks[task_id] = task
+ log.debug(f"{self.cog_name}: scheduled task #{task_id}.")
def cancel_task(self, task_id: str) -> None:
"""Un-schedules a task."""
@@ -51,7 +55,7 @@ class Scheduler(metaclass=CogABCMeta):
return
task.cancel()
- log.debug(f"{self.cog_name}: Unscheduled {task_id}.")
+ log.debug(f"{self.cog_name}: unscheduled task #{task_id}.")
del self.scheduled_tasks[task_id]