diff options
| author | 2018-10-06 20:08:12 +0000 | |
|---|---|---|
| committer | 2018-10-06 20:08:12 +0000 | |
| commit | e99ce9c896addd8eb88a901854f50a4fc33e00f8 (patch) | |
| tree | b76e21b5d00f5d1ec55aba4f932b929afae4bb77 | |
| parent | Hem's fixes. (diff) | |
| parent | Infraction search improvements (diff) | |
Merge branch 'better-moderation' into 'master'
Infraction search improvements
See merge request python-discord/projects/bot!47
| -rw-r--r-- | bot/cogs/moderation.py | 160 | ||||
| -rw-r--r-- | bot/converters.py | 9 |
2 files changed, 90 insertions, 79 deletions
diff --git a/bot/cogs/moderation.py b/bot/cogs/moderation.py index ee28a3600..79e7f0f9f 100644 --- a/bot/cogs/moderation.py +++ b/bot/cogs/moderation.py @@ -488,7 +488,7 @@ class Moderation: # region: Edit infraction commands @with_role(*MODERATION_ROLES) - @group(name='infraction', aliases=('infr',)) + @group(name='infraction', aliases=('infr', 'infractions', 'inf')) async def infraction_group(self, ctx: Context): """Infraction manipulation commands.""" @@ -654,70 +654,88 @@ class Moderation: # region: Search infractions @with_role(*MODERATION_ROLES) - @infraction_group.command(name="search") - async def search(self, ctx, arg: InfractionSearchQuery): + @infraction_group.group(name="search", invoke_without_command=True) + async def infraction_search_group(self, ctx: Context, query: InfractionSearchQuery): """ Searches for infractions in the database. - :param arg: Either a user or a reason string. If a string, you can use the Re2 matching syntax. - """ - - if isinstance(arg, User): - user: User = arg - # get infractions for this user - try: - response = await self.bot.http_session.get( - URLs.site_infractions_user.format( - user_id=user.id - ), - headers=self.headers - ) - infraction_list = await response.json() - except ClientError: - log.exception("There was an error fetching infractions.") - await ctx.send(":x: There was an error fetching infraction.") - return + """ - if not infraction_list: - await ctx.send(f":warning: No infractions found for {user}.") - return + if isinstance(query, User): + await ctx.invoke(self.search_user, query) - embed = Embed( - title=f"Infractions for {user} ({len(infraction_list)} total)", - colour=Colour.orange() + else: + await ctx.invoke(self.search_reason, query) + + @with_role(*MODERATION_ROLES) + @infraction_search_group.command(name="user", aliases=("member", "id")) + async def search_user(self, ctx, user: User): + """ + Search for infractions by member. + """ + + try: + response = await self.bot.http_session.get( + URLs.site_infractions_user.format( + user_id=user.id + ), + headers=self.headers ) + infraction_list = await response.json() + except ClientError: + log.exception(f"Failed to fetch infractions for user {user} ({user.id}).") + await ctx.send(":x: An error occurred while fetching infractions.") + return - elif isinstance(arg, str): - # search by reason - try: - response = await self.bot.http_session.get( - URLs.site_infractions, - headers=self.headers, - params={"search": arg} - ) - infraction_list = await response.json() - except ClientError: - log.exception("There was an error fetching infractions.") - await ctx.send(":x: There was an error fetching infraction.") - return + embed = Embed( + title=f"Infractions for {user} ({len(infraction_list)} total)", + colour=Colour.orange() + ) - if not infraction_list: - await ctx.send(f":warning: No infractions matching `{arg}`.") - return + await self.send_infraction_list(ctx, embed, infraction_list) + + @with_role(*MODERATION_ROLES) + @infraction_search_group.command(name="reason", aliases=("match", "regex", "re")) + async def search_reason(self, ctx, reason: str): + """ + Search for infractions by their reason. Use Re2 for matching. + """ - embed = Embed( - title=f"Infractions matching `{arg}` ({len(infraction_list)} total)", - colour=Colour.orange() + try: + response = await self.bot.http_session.get( + URLs.site_infractions, + params={"search": reason}, + headers=self.headers ) + infraction_list = await response.json() + except ClientError: + log.exception(f"Failed to fetch infractions matching reason `{reason}`.") + await ctx.send(":x: An error occurred while fetching infractions.") + return - else: - await ctx.send(":x: Invalid infraction search query.") + embed = Embed( + title=f"Infractions matching `{reason}` ({len(infraction_list)} total)", + colour=Colour.orange() + ) + + await self.send_infraction_list(ctx, embed, infraction_list) + + # endregion + # region: Utility functions + + async def send_infraction_list(self, ctx: Context, embed: Embed, infractions: list): + + if not infractions: + await ctx.send(f":warning: No infractions could be found for that query.") return + lines = [] + for infraction in infractions: + lines.append( + self._infraction_to_string(infraction) + ) + await LinePaginator.paginate( - lines=( - self._infraction_to_string(infraction_object, show_user=isinstance(arg, str)) - for infraction_object in infraction_list - ), + lines, ctx=ctx, embed=embed, empty=True, @@ -725,9 +743,6 @@ class Moderation: max_size=1000 ) - # endregion - # region: Utility functions - def schedule_expiration(self, loop: asyncio.AbstractEventLoop, infraction_object: dict): """ Schedules a task to expire a temporary infraction. @@ -815,30 +830,27 @@ class Moderation: } ) - def _infraction_to_string(self, infraction_object, show_user=False): + def _infraction_to_string(self, infraction_object): actor_id = int(infraction_object["actor"]["user_id"]) guild: Guild = self.bot.get_guild(constants.Guild.id) actor = guild.get_member(actor_id) active = infraction_object["active"] is True + user_id = int(infraction_object["user"]["user_id"]) - lines = [ - "**===============**" if active else "===============", - "Status: {0}".format("__**Active**__" if active else "Inactive"), - "Type: **{0}**".format(infraction_object["type"]), - "Reason: {0}".format(infraction_object["reason"] or "*None*"), - "Created: {0}".format(infraction_object["inserted_at"]), - "Expires: {0}".format(infraction_object["expires_at"] or "*Permanent*"), - "Actor: {0}".format(actor.mention if actor else actor_id), - "ID: `{0}`".format(infraction_object["id"]), - "**===============**" if active else "===============" - ] - - if show_user: - user_id = int(infraction_object["user"]["user_id"]) - user = self.bot.get_user(user_id) - lines.insert(1, "User: {0}".format(user.mention if user else user_id)) - - return "\n".join(lines) + lines = textwrap.dedent(f""" + {"**===============**" if active else "==============="} + Status: {"__**Active**__" if active else "Inactive"} + User: {self.bot.get_user(user_id)} (`{user_id}`) + Type: **{infraction_object["type"]}** + Reason: {infraction_object["reason"] or "*None*"} + Created: {infraction_object["inserted_at"]} + Expires: {infraction_object["expires_at"] or "*Permanent*"} + Actor: {actor.mention if actor else actor_id} + ID: `{infraction_object["id"]}` + {"**===============**" if active else "==============="} + """) + + return lines.strip() # endregion diff --git a/bot/converters.py b/bot/converters.py index 3def4b07a..c8bc75715 100644 --- a/bot/converters.py +++ b/bot/converters.py @@ -4,7 +4,7 @@ from ssl import CertificateError import discord from aiohttp import AsyncResolver, ClientConnectorError, ClientSession, TCPConnector -from discord.ext.commands import BadArgument, Converter, UserConverter +from discord.ext.commands import BadArgument, Converter from fuzzywuzzy import fuzz from bot.constants import DEBUG_MODE, Keys, URLs @@ -167,11 +167,10 @@ class InfractionSearchQuery(Converter): @staticmethod async def convert(ctx, arg): try: - user_converter = UserConverter() - user = await user_converter.convert(ctx, arg) - except Exception: + maybe_snowflake = arg.strip("<@!>") + return await ctx.bot.get_user_info(maybe_snowflake) + except (discord.NotFound, discord.HTTPException): return arg - return user or arg class Subreddit(Converter): |