Skip to content

Commit

Permalink
Merge branch 'master' into edit-log-timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
jerbob authored Jan 12, 2019
2 parents 3fc94a9 + 0ff3bf4 commit 98ea5c1
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 9 deletions.
2 changes: 1 addition & 1 deletion bot/cogs/alias.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async def site_resources_alias(self, ctx):

@command(name="watch", hidden=True)
async def bigbrother_watch_alias(
self, ctx, user: User, *, reason: str = None
self, ctx, user: User, *, reason: str
):
"""
Alias for invoking <prefix>bigbrother watch user [text_channel].
Expand Down
62 changes: 56 additions & 6 deletions bot/cogs/bigbrother.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
import logging
import re
from collections import defaultdict, deque
from time import strptime, struct_time
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

Expand All @@ -26,9 +28,11 @@ 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())

Expand Down Expand Up @@ -62,6 +66,42 @@ async def get_watched_users(self):
data = await response.json()
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_infraction_time)
latest_reason = latest_reason_infraction['reason'][len(self.infraction_watch_prefix):]
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_infraction_time(infraction: str) -> struct_time:
"""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:
url = f"{URLs.site_bigbrother_api}?user_id={user.id}"
Expand All @@ -70,6 +110,7 @@ async def on_member_ban(self, guild: Guild, user: Union[User, Member]):
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 "
Expand Down Expand Up @@ -139,10 +180,17 @@ async def send_header(self, message: Message, destination: TextChannel):

# Send header if user/channel are different or if message limit exceeded.
if message.author.id != last_user or message.channel.id != last_channel or msg_count > limit:
# Retrieve watch reason from API if it's not already in the cache
if message.author.id not in self.watch_reasons:
log.trace(f"No watch reason for {message.author.id} found in cache; retrieving from API")
user_watch_reason = await self.get_watch_reason(message.author.id)
self.watch_reasons[message.author.id] = user_watch_reason

self.last_log = [message.author.id, message.channel.id, 0]

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
Expand Down Expand Up @@ -246,15 +294,15 @@ async def watch_command(self, ctx: Context, user: User, *, reason: str):
)
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)
Expand All @@ -270,6 +318,8 @@ async def unwatch_command(self, ctx: Context, user: User):
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")

Expand Down
4 changes: 2 additions & 2 deletions bot/cogs/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

from discord import Colour, Embed, HTTPException
from discord.ext import commands
from discord.ext.commands import CheckFailure
from fuzzywuzzy import fuzz, process

from bot import constants
from bot.decorators import InChannelCheckFailure
from bot.pagination import (
DELETE_EMOJI, FIRST_EMOJI, LAST_EMOJI,
LEFT_EMOJI, LinePaginator, RIGHT_EMOJI,
Expand Down Expand Up @@ -435,7 +435,7 @@ async def build_pages(self):
# the mean time.
try:
can_run = await command.can_run(self._ctx)
except InChannelCheckFailure:
except CheckFailure:
can_run = False

if not can_run:
Expand Down
1 change: 1 addition & 0 deletions config-default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down

0 comments on commit 98ea5c1

Please sign in to comment.