aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bot/cogs/moderation.py160
-rw-r--r--bot/converters.py9
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):