diff --git a/aurora/aurora.py b/aurora/aurora.py index 1f946f4..0688d6b 100644 --- a/aurora/aurora.py +++ b/aurora/aurora.py @@ -15,12 +15,11 @@ from math import ceil import discord import humanize from discord.ext import tasks -from pytimeparse2 import disable_dateutil, parse from redbot.core import app_commands, commands, data_manager from redbot.core.app_commands import Choice from redbot.core.bot import Red -from redbot.core.utils.chat_formatting import (box, error, humanize_list, - warning) +from redbot.core.commands.converter import parse_relativedelta, parse_timedelta +from redbot.core.utils.chat_formatting import box, error, humanize_list, warning from aurora.importers.aurora import ImportAuroraView from aurora.importers.galacticbot import ImportGalacticBotView @@ -29,17 +28,10 @@ from aurora.menus.guild import Guild from aurora.menus.immune import Immune from aurora.menus.overrides import Overrides from aurora.utilities.config import config, register_config -from aurora.utilities.database import (connect, create_guild_table, fetch_case, - mysql_log) -from aurora.utilities.factory import (addrole_embed, case_factory, - changes_factory, evidenceformat_factory, - guild_embed, immune_embed, - message_factory, overrides_embed) +from aurora.utilities.database import connect, create_guild_table, fetch_case, mysql_log +from aurora.utilities.factory import addrole_embed, case_factory, changes_factory, evidenceformat_factory, guild_embed, immune_embed, message_factory, overrides_embed from aurora.utilities.logger import logger -from aurora.utilities.utils import (check_moddable, check_permissions, - convert_timedelta_to_str, - fetch_channel_dict, fetch_user_dict, - generate_dict, log, send_evidenceformat) +from aurora.utilities.utils import check_moddable, check_permissions, convert_timedelta_to_str, fetch_channel_dict, fetch_user_dict, generate_dict, log, send_evidenceformat, timedelta_from_relativedelta class Aurora(commands.Cog): @@ -84,7 +76,6 @@ class Aurora(commands.Cog): super().__init__() self.bot = bot register_config(config) - disable_dateutil() self.handle_expiry.start() def format_help_for_context(self, ctx: commands.Context) -> str: @@ -332,13 +323,10 @@ class Aurora(commands.Cog): return if duration is not None: - try: - parsed_time = parse( - sval=duration, as_timedelta=True, raise_exception=True - ) - except ValueError: + parsed_time = parse_timedelta(duration) + if parsed_time is None: await interaction.response.send_message( - error("Please provide a valid duration!"), ephemeral=True + content=error("Please provide a valid duration!"), ephemeral=True ) return else: @@ -440,16 +428,15 @@ class Aurora(commands.Cog): return try: - parsed_time = parse(sval=duration, as_timedelta=True, raise_exception=True) - except ValueError: + parsed_time = parse_timedelta(duration, maximum=timedelta(days=28)) + if parsed_time is None: + await interaction.response.send_message( + error("Please provide a valid duration!"), ephemeral=True + ) + return + except commands.BadArgument: await interaction.response.send_message( - error("Please provide a valid duration!"), ephemeral=True - ) - return - - if parsed_time.total_seconds() / 1000 > 2419200000: - await interaction.response.send_message( - error("Please provide a duration that is less than 28 days.") + error("Please provide a duration that is less than 28 days."), ephemeral=True ) return @@ -684,15 +671,13 @@ class Aurora(commands.Cog): pass if duration: - try: - parsed_time = parse( - sval=duration, as_timedelta=True, raise_exception=True - ) - except ValueError: + parsed_time = parse_relativedelta(duration) + if parsed_time is None: await interaction.response.send_message( - error("Please provide a valid duration!"), ephemeral=True + content=error("Please provide a valid duration!"), ephemeral=True ) return + parsed_time = timedelta_from_relativedelta(parsed_time) await interaction.response.send_message( content=f"{target.mention} has been banned for {humanize.precisedelta(parsed_time)}!\n**Reason** - `{reason}`" @@ -1380,11 +1365,8 @@ class Aurora(commands.Cog): case_dict = await fetch_case(case, interaction.guild.id) if case_dict: if duration: - try: - parsed_time = parse( - sval=duration, as_timedelta=True, raise_exception=True - ) - except ValueError: + parsed_time = parse_timedelta(duration) + if parsed_time is None: await interaction.response.send_message( error("Please provide a valid duration!"), ephemeral=True ) @@ -1700,15 +1682,28 @@ class Aurora(commands.Cog): ) @aurora.command(aliases=["tdc", "td", "timedeltaconvert"]) - async def timedelta(self, ctx: commands.Context, *, duration: str): + async def timedelta(self, ctx: commands.Context, *, duration: str) -> None: """This command converts a duration to a [`timedelta`](https://docs.python.org/3/library/datetime.html#datetime.timedelta) Python object. + You cannot convert years or months as they are not fixed units. Use `[p]aurora relativedelta` for that. **Example usage** `[p]aurora timedelta 1 day 15hr 82 minutes 52s` **Output** `1 day, 16:22:52`""" - try: - parsed_time = parse(duration, as_timedelta=True, raise_exception=True) - await ctx.send(f"`{str(parsed_time)}`") - except ValueError: + parsed_time = parse_timedelta(duration) + if parsed_time is None: await ctx.send(error("Please provide a convertible value!")) + await ctx.send(f"`{parsed_time}`") + + @aurora.command(aliases=["rdc", "rd", "relativedeltaconvert"]) + async def relativedelta(self, ctx: commands.Context, *, duration: str) -> None: + """This command converts a duration to a [`relativedelta`](https://dateutil.readthedocs.io/en/stable/relativedelta.html) Python object. + + **Example usage** + `[p]aurora relativedelta 3 years 1 day 15hr 82 minutes 52s` + **Output** + `relativedelta(years=+3, days=+1, hours=+15, minutes=+82, seconds=+52)`""" + parsed_time = parse_relativedelta(duration) + if parsed_time is None: + await ctx.send(error("Please provide a convertible value!")) + await ctx.send(f"`{parsed_time}`") diff --git a/aurora/info.json b/aurora/info.json index 0d6d417..800d998 100644 --- a/aurora/info.json +++ b/aurora/info.json @@ -5,7 +5,7 @@ "short" : "A full replacement for Red's core Mod cogs.", "description" : "Aurora is a fully-featured moderation system. It is heavily inspired by GalacticBot, and is designed to be a more user-friendly alternative to Red's core Mod cogs. This cog stores all of its data in an SQLite database.", "end_user_data_statement" : "This cog stores the following information:\n- User IDs of accounts who moderate users or are moderated\n- Guild IDs of guilds with the cog enabled\n- Timestamps of moderations\n- Other information relating to moderations", - "requirements": ["humanize", "pytimeparse2"], + "requirements": ["humanize"], "hidden": false, "disabled": false, "min_bot_version": "3.5.0", diff --git a/aurora/utilities/utils.py b/aurora/utilities/utils.py index 12c8400..6f77cca 100644 --- a/aurora/utilities/utils.py +++ b/aurora/utilities/utils.py @@ -1,8 +1,10 @@ # pylint: disable=cyclic-import import json +from datetime import datetime from datetime import timedelta as td from typing import Union +from dateutil.relativedelta import relativedelta as rd from discord import Guild, Interaction, Member, SelectOption, User from discord.errors import Forbidden, NotFound from redbot.core import commands @@ -283,3 +285,9 @@ def create_pagesize_options() -> list[SelectOption]: ) ) return options + +def timedelta_from_relativedelta(relativedelta: rd) -> td: + """Converts a relativedelta object to a timedelta object.""" + now = datetime.now() + then = now - relativedelta + return now - then diff --git a/poetry.lock b/poetry.lock index 98b0681..737233a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1677,20 +1677,6 @@ files = [ [package.dependencies] six = ">=1.5" -[[package]] -name = "pytimeparse2" -version = "1.7.1" -description = "Time expression parser." -optional = false -python-versions = ">=3.6" -files = [ - {file = "pytimeparse2-1.7.1-py3-none-any.whl", hash = "sha256:a162ea6a7707fd0bb82dd99556efb783935f51885c8bdced0fce3fffe85ab002"}, - {file = "pytimeparse2-1.7.1.tar.gz", hash = "sha256:98668cdcba4890e1789e432e8ea0059ccf72402f13f5d52be15bdfaeb3a8b253"}, -] - -[package.extras] -dateutil = ["python-dateutil (>=2.8.2,<2.9.0)"] - [[package]] name = "pytz" version = "2023.3.post1" @@ -2536,4 +2522,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "a32cda21d6b46347f4432a29a4f4b7b030b36406e030c839a55112670fa335e5" +content-hash = "b10a8c8d11a74351402e4663ba61655905a1939aa72701f9905c8a63bfd8f1ed" diff --git a/pyproject.toml b/pyproject.toml index db39969..6b66b54 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,6 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.11,<3.12" Red-DiscordBot = "^3.5.5" -pytimeparse2 = "^1.7.1" humanize = "^4.8.0" py-dactyl = "^2.0.4" websockets = "^12.0"