feat(aurora): allow for querying moderation history by date (before/after)
This commit is contained in:
parent
7f0bd8c1a8
commit
1a3af342df
5 changed files with 108 additions and 10 deletions
|
@ -13,6 +13,7 @@ from datetime import datetime, timedelta, timezone
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
from dateparser import parse
|
||||||
from discord.ext import tasks
|
from discord.ext import tasks
|
||||||
from redbot.core import app_commands, commands, data_manager
|
from redbot.core import app_commands, commands, data_manager
|
||||||
from redbot.core.app_commands import Choice
|
from redbot.core.app_commands import Choice
|
||||||
|
@ -520,6 +521,8 @@ class Aurora(commands.Cog):
|
||||||
moderator: discord.User | None = None,
|
moderator: discord.User | None = None,
|
||||||
pagesize: app_commands.Range[int, 1, 20] | None = None,
|
pagesize: app_commands.Range[int, 1, 20] | None = None,
|
||||||
page: int = 1,
|
page: int = 1,
|
||||||
|
before: str | None = None,
|
||||||
|
after: str | None = None,
|
||||||
ephemeral: bool | None = None,
|
ephemeral: bool | None = None,
|
||||||
inline: bool | None = None,
|
inline: bool | None = None,
|
||||||
export: bool = False,
|
export: bool = False,
|
||||||
|
@ -536,6 +539,10 @@ class Aurora(commands.Cog):
|
||||||
Amount of infractions to list per page
|
Amount of infractions to list per page
|
||||||
page: int
|
page: int
|
||||||
Page to select
|
Page to select
|
||||||
|
before: str
|
||||||
|
List infractions before a certain date
|
||||||
|
after: str
|
||||||
|
List infractions after a certain date
|
||||||
ephemeral: bool
|
ephemeral: bool
|
||||||
Hide the command response
|
Hide the command response
|
||||||
inline: bool
|
inline: bool
|
||||||
|
@ -570,6 +577,22 @@ class Aurora(commands.Cog):
|
||||||
or 5
|
or 5
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if before:
|
||||||
|
before = parse(before)
|
||||||
|
if before is None:
|
||||||
|
return await interaction.response.send_message(
|
||||||
|
content=error("Invalid date format for `before`."), ephemeral=True
|
||||||
|
)
|
||||||
|
before = before.replace(tzinfo=timezone.utc)
|
||||||
|
|
||||||
|
if after:
|
||||||
|
after = parse(after)
|
||||||
|
if after is None:
|
||||||
|
return await interaction.response.send_message(
|
||||||
|
content=error("Invalid date format for `after`."), ephemeral=True
|
||||||
|
)
|
||||||
|
after = after.replace(tzinfo=timezone.utc)
|
||||||
|
|
||||||
await interaction.response.defer(ephemeral=ephemeral)
|
await interaction.response.defer(ephemeral=ephemeral)
|
||||||
|
|
||||||
permissions = check_permissions(
|
permissions = check_permissions(
|
||||||
|
@ -586,13 +609,13 @@ class Aurora(commands.Cog):
|
||||||
|
|
||||||
if target:
|
if target:
|
||||||
filename = f"moderation_target_{str(target.id)}_{str(interaction.guild.id)}.json"
|
filename = f"moderation_target_{str(target.id)}_{str(interaction.guild.id)}.json"
|
||||||
moderations = await Moderation.find_by_target(interaction.client, interaction.guild.id, target.id)
|
moderations = await Moderation.find_by_target(bot=interaction.client, guild_id=interaction.guild.id, target=target.id, before=before, after=after)
|
||||||
elif moderator:
|
elif moderator:
|
||||||
filename = f"moderation_moderator_{str(moderator.id)}_{str(interaction.guild.id)}.json"
|
filename = f"moderation_moderator_{str(moderator.id)}_{str(interaction.guild.id)}.json"
|
||||||
moderations = await Moderation.find_by_moderator(interaction.client, interaction.guild.id, moderator.id)
|
moderations = await Moderation.find_by_moderator(bot=interaction.client, guild_id=interaction.guild.id, moderator=moderator.id, before=before, after=after)
|
||||||
else:
|
else:
|
||||||
filename = f"moderation_{str(interaction.guild.id)}.json"
|
filename = f"moderation_{str(interaction.guild.id)}.json"
|
||||||
moderations = await Moderation.get_latest(interaction.client, interaction.guild.id)
|
moderations = await Moderation.get_latest(bot=interaction.client, guild_id=interaction.guild.id, before=before, after=after)
|
||||||
|
|
||||||
if export:
|
if export:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"disabled": false,
|
"disabled": false,
|
||||||
"min_bot_version": "3.5.0",
|
"min_bot_version": "3.5.0",
|
||||||
"min_python_version": [3, 10, 0],
|
"min_python_version": [3, 10, 0],
|
||||||
"requirements": ["pydantic", "aiosqlite", "phx-class-registry"],
|
"requirements": ["pydantic", "aiosqlite", "phx-class-registry", "dateparser"],
|
||||||
"tags": [
|
"tags": [
|
||||||
"mod",
|
"mod",
|
||||||
"moderate",
|
"moderate",
|
||||||
|
|
|
@ -307,13 +307,19 @@ class Moderation(AuroraGuildModel):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_latest(cls, bot: Red, guild_id: int, limit: int | None = None, offset: int = 0, types: Iterable[Type] | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
|
async def get_latest(cls, bot: Red, guild_id: int, before: datetime = None, after: datetime = None, limit: int | None = None, offset: int = 0, types: Iterable[Type] | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
|
||||||
params = []
|
params = []
|
||||||
query = f"SELECT * FROM moderation_{guild_id} ORDER BY moderation_id DESC"
|
query = f"SELECT * FROM moderation_{guild_id} ORDER BY moderation_id DESC"
|
||||||
if types:
|
if types:
|
||||||
query += f" WHERE moderation_type IN ({', '.join(['?' for _ in types])})"
|
query += f" WHERE moderation_type IN ({', '.join(['?' for _ in types])})"
|
||||||
for t in types:
|
for t in types:
|
||||||
params.append(t.key)
|
params.append(t.key)
|
||||||
|
if before:
|
||||||
|
query += " WHERE timestamp < ?"
|
||||||
|
params.append(before.timestamp())
|
||||||
|
if after:
|
||||||
|
query += " WHERE timestamp > ?"
|
||||||
|
params.append(after.timestamp())
|
||||||
if limit:
|
if limit:
|
||||||
query += " LIMIT ? OFFSET ?"
|
query += " LIMIT ? OFFSET ?"
|
||||||
params.extend((limit, offset))
|
params.extend((limit, offset))
|
||||||
|
@ -334,22 +340,40 @@ class Moderation(AuroraGuildModel):
|
||||||
raise ValueError(f"Case {moderation_id} not found in moderation_{guild_id}!")
|
raise ValueError(f"Case {moderation_id} not found in moderation_{guild_id}!")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def find_by_target(cls, bot: Red, guild_id: int, target: int, types: Iterable[Type] | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
|
async def find_by_target(cls, bot: Red, guild_id: int, target: int, before: datetime = None, after: datetime = None, types: Iterable[Type] | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
|
||||||
query = f"SELECT * FROM moderation_{guild_id} WHERE target_id = ?"
|
query = f"SELECT * FROM moderation_{guild_id} WHERE target_id = ?"
|
||||||
|
params = [target]
|
||||||
if types:
|
if types:
|
||||||
query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})"
|
query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})"
|
||||||
|
for t in types:
|
||||||
|
params.append(t.key)
|
||||||
|
if before:
|
||||||
|
query += " AND timestamp < ?"
|
||||||
|
params.append(before.timestamp())
|
||||||
|
if after:
|
||||||
|
query += " AND timestamp > ?"
|
||||||
|
params.append(after.timestamp())
|
||||||
query += " ORDER BY moderation_id DESC;"
|
query += " ORDER BY moderation_id DESC;"
|
||||||
|
|
||||||
return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(target, *[t.key for t in types]) if types else (target,), cursor=cursor)
|
return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=params, cursor=cursor)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def find_by_moderator(cls, bot: Red, guild_id: int, moderator: int, types: Iterable[Type] | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
|
async def find_by_moderator(cls, bot: Red, guild_id: int, moderator: int, before: datetime = None, after: datetime = None, types: Iterable[Type] | None = None, cursor: Cursor | None = None) -> Tuple["Moderation"]:
|
||||||
query = f"SELECT * FROM moderation_{guild_id} WHERE moderator_id = ?"
|
query = f"SELECT * FROM moderation_{guild_id} WHERE moderator_id = ?"
|
||||||
|
params = [moderator]
|
||||||
if types:
|
if types:
|
||||||
query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})"
|
query += f" AND moderation_type IN ({', '.join(['?' for _ in types])})"
|
||||||
|
for t in types:
|
||||||
|
params.append(t.key)
|
||||||
|
if before:
|
||||||
|
query += " AND timestamp < ?"
|
||||||
|
params.append(before.timestamp())
|
||||||
|
if after:
|
||||||
|
query += " AND timestamp > ?"
|
||||||
|
params.append(after.timestamp())
|
||||||
query += " ORDER BY moderation_id DESC;"
|
query += " ORDER BY moderation_id DESC;"
|
||||||
|
|
||||||
return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=(moderator, *[t.key for t in types]) if types else (moderator,), cursor=cursor)
|
return await cls.execute(bot=bot, guild_id=guild_id, query=query, parameters=params, cursor=cursor)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def log(
|
async def log(
|
||||||
|
|
52
poetry.lock
generated
52
poetry.lock
generated
|
@ -668,6 +668,28 @@ webencodings = "*"
|
||||||
doc = ["sphinx", "sphinx_rtd_theme"]
|
doc = ["sphinx", "sphinx_rtd_theme"]
|
||||||
test = ["flake8", "isort", "pytest"]
|
test = ["flake8", "isort", "pytest"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dateparser"
|
||||||
|
version = "1.2.0"
|
||||||
|
description = "Date parsing library designed to parse dates from HTML pages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "dateparser-1.2.0-py2.py3-none-any.whl", hash = "sha256:0b21ad96534e562920a0083e97fd45fa959882d4162acc358705144520a35830"},
|
||||||
|
{file = "dateparser-1.2.0.tar.gz", hash = "sha256:7975b43a4222283e0ae15be7b4999d08c9a70e2d378ac87385b1ccf2cffbbb30"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
python-dateutil = "*"
|
||||||
|
pytz = "*"
|
||||||
|
regex = "<2019.02.19 || >2019.02.19,<2021.8.27 || >2021.8.27"
|
||||||
|
tzlocal = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
calendars = ["convertdate", "hijri-converter"]
|
||||||
|
fasttext = ["fasttext"]
|
||||||
|
langdetect = ["langdetect"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "defusedxml"
|
name = "defusedxml"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2373,6 +2395,34 @@ files = [
|
||||||
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
|
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzdata"
|
||||||
|
version = "2024.1"
|
||||||
|
description = "Provider of IANA time zone data"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2"
|
||||||
|
files = [
|
||||||
|
{file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
|
||||||
|
{file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tzlocal"
|
||||||
|
version = "5.2"
|
||||||
|
description = "tzinfo object for the local timezone"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"},
|
||||||
|
{file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
tzdata = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.2.1"
|
version = "2.2.1"
|
||||||
|
@ -2690,4 +2740,4 @@ multidict = ">=4.0"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = ">=3.11,<3.12"
|
python-versions = ">=3.11,<3.12"
|
||||||
content-hash = "6d09969e0ad7adff5aa105915c5c9e0354b4b7aceb80b9c2b3fb800bb08f21d4"
|
content-hash = "bc58f1f72ca73806c414042a78294e73c4119906b57fceb045ab48414928849e"
|
||||||
|
|
|
@ -20,6 +20,7 @@ beautifulsoup4 = "^4.12.3"
|
||||||
markdownify = "^0.12.1"
|
markdownify = "^0.12.1"
|
||||||
aiosqlite = "^0.20.0"
|
aiosqlite = "^0.20.0"
|
||||||
phx-class-registry = "^4.1.0"
|
phx-class-registry = "^4.1.0"
|
||||||
|
dateparser = "^1.2.0"
|
||||||
|
|
||||||
[tool.poetry.group.dev]
|
[tool.poetry.group.dev]
|
||||||
optional = true
|
optional = true
|
||||||
|
|
Loading…
Reference in a new issue