diff options
| author | 2019-01-10 16:55:55 +0100 | |
|---|---|---|
| committer | 2019-01-10 16:55:55 +0100 | |
| commit | b2929ef2e72d42950169db4a46c064eedc228c4e (patch) | |
| tree | dd4d3acecf6625d4eaa1d3a81941810c29c7eb64 | |
| parent | Merge pull request #259 from python-discord/SebastiaanZ/embed-detection-filter (diff) | |
Adding watch reason to the big-brother header embeds
| -rw-r--r-- | bot/cogs/bigbrother.py | 65 | ||||
| -rw-r--r-- | config-default.yml | 1 |
2 files changed, 57 insertions, 9 deletions
diff --git a/bot/cogs/bigbrother.py b/bot/cogs/bigbrother.py index 29b13f038..26d35a97c 100644 --- a/bot/cogs/bigbrother.py +++ b/bot/cogs/bigbrother.py @@ -2,8 +2,10 @@ import asyncio import logging import re from collections import defaultdict, deque +from time import strptime from typing import List, Union +from aiohttp import ClientError from discord import Color, Embed, Guild, Member, Message, TextChannel, User from discord.ext.commands import Bot, Context, group @@ -26,13 +28,15 @@ class BigBrother: def __init__(self, bot: Bot): self.bot = bot self.watched_users = {} # { user_id: log_channel_id } + self.watch_reasons = {} # { user_id: watch_reason } self.channel_queues = defaultdict(lambda: defaultdict(deque)) # { user_id: { channel_id: queue(messages) } self.last_log = [None, None, 0] # [user_id, channel_id, message_count] self.consuming = False + self.infraction_watch_prefix = "bb watch: " # Please do not change or we won't be able to find old reasons self.bot.loop.create_task(self.get_watched_users()) - def update_cache(self, api_response: List[dict]): + async def update_cache(self, api_response: List[dict]): """ Updates the internal cache of watched users from the given `api_response`. This function will only add (or update) existing keys, it will not delete @@ -54,13 +58,52 @@ class BigBrother: "but the given channel could not be found. Ignoring." ) + watch_reason = await self.get_watch_reason(user_id) + self.watch_reasons[user_id] = watch_reason + async def get_watched_users(self): """Retrieves watched users from the API.""" await self.bot.wait_until_ready() async with self.bot.http_session.get(URLs.site_bigbrother_api, headers=self.HEADERS) as response: data = await response.json() - self.update_cache(data) + await self.update_cache(data) + + async def get_watch_reason(self, user_id: int) -> str: + """ Fetches and returns the latest watch reason for a user using the infraction API """ + + re_bb_watch = rf"^{self.infraction_watch_prefix}" + user_id = str(user_id) + + try: + response = await self.bot.http_session.get( + URLs.site_infractions_user_type.format( + user_id=user_id, + infraction_type="note", + ), + params={"search": re_bb_watch, "hidden": "True", "active": "False"}, + headers=self.HEADERS + ) + infraction_list = await response.json() + except ClientError: + log.exception(f"Failed to retrieve bb watch reason for {user_id}.") + return "(error retrieving bb reason)" + + if infraction_list: + latest_reason_infraction = max(infraction_list, key=self._parse_time) + latest_reason = latest_reason_infraction['reason'][10:] + log.trace(f"The latest bb watch reason for {user_id}: {latest_reason}") + return latest_reason + + log.trace(f"No bb watch reason found for {user_id}; returning default string") + return "(no reason specified)" + + @staticmethod + def _parse_time(infraction): + """Takes RFC1123 date_time string and returns time object for sorting purposes""" + + date_string = infraction["inserted_at"] + return strptime(date_string, "%a, %d %b %Y %H:%M:%S %Z") async def on_member_ban(self, guild: Guild, user: Union[User, Member]): if guild.id == GuildConfig.id and user.id in self.watched_users: @@ -70,6 +113,7 @@ class BigBrother: async with self.bot.http_session.delete(url, headers=self.HEADERS) as response: del self.watched_users[user.id] del self.channel_queues[user.id] + del self.watch_reasons[user.id] if response.status == 204: await channel.send( f"{Emojis.bb_message}:hammer: {user} got banned, so " @@ -143,6 +187,7 @@ class BigBrother: embed = Embed(description=f"{message.author.mention} in [#{message.channel.name}]({message.jump_url})") embed.set_author(name=message.author.nick or message.author.name, icon_url=message.author.avatar_url) + embed.set_footer(text=f"Watch reason: {self.watch_reasons[message.author.id]}") await destination.send(embed=embed) @staticmethod @@ -201,7 +246,7 @@ class BigBrother: async with self.bot.http_session.get(URLs.site_bigbrother_api, headers=self.HEADERS) as response: if response.status == 200: data = await response.json() - self.update_cache(data) + await self.update_cache(data) lines = tuple(f"• <@{entry['user_id']}> in <#{entry['channel_id']}>" for entry in data) await LinePaginator.paginate( @@ -246,15 +291,15 @@ class BigBrother: ) else: self.watched_users[user.id] = channel + self.watch_reasons[user.id] = reason + # Add a note (shadow warning) with the reason for watching + reason = f"{self.infraction_watch_prefix}{reason}" + await post_infraction(ctx, user, type="warning", reason=reason, hidden=True) else: data = await response.json() - reason = data.get('error_message', "no message provided") - await ctx.send(f":x: the API returned an error: {reason}") - - # Add a note (shadow warning) with the reason for watching - reason = "bb watch: " + reason # Prepend for situational awareness - await post_infraction(ctx, user, type="warning", reason=reason, hidden=True) + error_reason = data.get('error_message', "no message provided") + await ctx.send(f":x: the API returned an error: {error_reason}") @bigbrother_group.command(name='unwatch', aliases=('uw',)) @with_role(Roles.owner, Roles.admin, Roles.moderator) @@ -270,6 +315,8 @@ class BigBrother: del self.watched_users[user.id] if user.id in self.channel_queues: del self.channel_queues[user.id] + if user.id in self.watch_reasons: + del self.watch_reasons[user.id] else: log.warning(f"user {user.id} was unwatched but was not found in the cache") diff --git a/config-default.yml b/config-default.yml index 21d7f20b9..1a5a63c6a 100644 --- a/config-default.yml +++ b/config-default.yml @@ -240,6 +240,7 @@ urls: site_infractions_type: !JOIN [*SCHEMA, *API, "/bot/infractions/type/{infraction_type}"] site_infractions_by_id: !JOIN [*SCHEMA, *API, "/bot/infractions/id/{infraction_id}"] site_infractions_user_type_current: !JOIN [*SCHEMA, *API, "/bot/infractions/user/{user_id}/{infraction_type}/current"] + site_infractions_user_type: !JOIN [*SCHEMA, *API, "/bot/infractions/user/{user_id}/{infraction_type}"] site_logs_api: !JOIN [*SCHEMA, *API, "/bot/logs"] site_logs_view: !JOIN [*SCHEMA, *DOMAIN, "/bot/logs"] site_names_api: !JOIN [*SCHEMA, *API, "/bot/snake_names"] |