diff --git a/jarvis/cogs/remindme.py b/jarvis/cogs/remindme.py index 70bd916..9639485 100644 --- a/jarvis/cogs/remindme.py +++ b/jarvis/cogs/remindme.py @@ -2,14 +2,16 @@ import asyncio import re from datetime import datetime, timedelta -from typing import List, Optional +from typing import List from bson import ObjectId from dis_snek import InteractionContext, Snake +from dis_snek.models.discord.channel import GuildChannel from dis_snek.models.discord.components import ActionRow, Select, SelectOption from dis_snek.models.discord.embed import Embed, EmbedField from dis_snek.models.snek.application_commands import ( OptionTypes, + SlashCommandChoice, slash_command, slash_option, ) @@ -19,6 +21,7 @@ from jarvis.utils import build_embed from jarvis.utils.cachecog import CacheCog valid = re.compile(r"[\w\s\-\\/.!@#$%^*()+=<>,\u0080-\U000E0FFF]*") +time_pattern = re.compile(r"(\d+\.?\d?[s|m|h|d|w]{1})\s?") invites = re.compile( r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)", # noqa: E501 flags=re.IGNORECASE, @@ -39,35 +42,29 @@ class RemindmeCog(CacheCog): required=True, ) @slash_option( - name="weeks", - description="Number of weeks?", - opt_type=OptionTypes.INTEGER, + name="delay", + description="How long? (i.e. 1w 3d 7h 5m 20s)", + opt_type=OptionTypes.STRING, required=False, ) @slash_option( - name="days", description="Number of days?", opt_type=OptionTypes.INTEGER, required=False - ) - @slash_option( - name="hours", - description="Number of hours?", - opt_type=OptionTypes.INTEGER, - required=False, - ) - @slash_option( - name="minutes", - description="Number of minutes?", - opt_type=OptionTypes.INTEGER, + name="private", + description="Send as DM?", + opt_type=OptionTypes.STRING, required=False, + choices=[ + SlashCommandChoice(name="Yes", value="y"), + SlashCommandChoice(name="No", value="n"), + ], ) async def _remindme( self, ctx: InteractionContext, - message: Optional[str] = None, - weeks: Optional[int] = 0, - days: Optional[int] = 0, - hours: Optional[int] = 0, - minutes: Optional[int] = 0, + message: str, + delay: str, + private: str = "n", ) -> None: + private = private == "y" if len(message) > 100: await ctx.send("Reminder cannot be > 100 characters.", ephemeral=True) return @@ -81,31 +78,22 @@ class RemindmeCog(CacheCog): await ctx.send("Hey, you should probably make this readable", ephemeral=True) return - if not any([weeks, days, hours, minutes]): + units = {"w": "weeks", "d": "days", "h": "hours", "m": "minutes", "s": "seconds"} + delta = {"weeks": 0, "days": 0, "hours": 0, "minutes": 0, "seconds": 0} + + if times := time_pattern.findall(delay, flags=re.I): + for t in times: + delta[units[t[-1]]] += float(t[:-1]) + else: + await ctx.send( + "Invalid time string, please follow example: `1w 3d 7h 5m 20s`", ephemeral=True + ) + return + + if not any(value for value in delta.items()): await ctx.send("At least one time period is required", ephemeral=True) return - weeks = abs(weeks) - days = abs(days) - hours = abs(hours) - minutes = abs(minutes) - - if weeks and weeks > 4: - await ctx.send("Cannot be farther than 4 weeks out!", ephemeral=True) - return - - elif days and days > 6: - await ctx.send("Use weeks instead of 7+ days, please.", ephemeral=True) - return - - elif hours and hours > 23: - await ctx.send("Use days instead of 24+ hours, please.", ephemeral=True) - return - - elif minutes and minutes > 59: - await ctx.send("Use hours instead of 59+ minutes, please.", ephemeral=True) - return - reminders = Reminder.objects(user=ctx.author.id, active=True).count() if reminders >= 5: await ctx.send( @@ -115,12 +103,7 @@ class RemindmeCog(CacheCog): ) return - remind_at = datetime.utcnow() + timedelta( - weeks=weeks, - days=days, - hours=hours, - minutes=minutes, - ) + remind_at = datetime.now() + timedelta(**delta) _ = Reminder( user=ctx.author_id, @@ -128,6 +111,7 @@ class RemindmeCog(CacheCog): guild=ctx.guild.id, message=message, remind_at=remind_at, + private=private, active=True, ).save() @@ -150,7 +134,7 @@ class RemindmeCog(CacheCog): ) embed.set_thumbnail(url=ctx.author.display_avatar.url) - await ctx.send(embed=embed) + await ctx.send(embed=embed, ephemeral=private) async def get_reminders_embed( self, ctx: InteractionContext, reminders: List[Reminder] @@ -158,13 +142,22 @@ class RemindmeCog(CacheCog): """Build embed for paginator.""" fields = [] for reminder in reminders: - fields.append( - EmbedField( - name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"), - value=f"{reminder.message}\n\u200b", - inline=False, + if reminder.private and isinstance(ctx.channel, GuildChannel): + fields.embed( + EmbedField( + name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"), + value="Please DM me this command to view the content of this reminder", + inline=False, + ) + ) + else: + fields.append( + EmbedField( + name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"), + value=f"{reminder.message}\n\u200b", + inline=False, + ) ) - ) embed = build_embed( title=f"{len(reminders)} Active Reminder(s)", @@ -246,13 +239,22 @@ class RemindmeCog(CacheCog): fields = [] for reminder in filter(lambda x: str(x.id) in context.context.values, reminders): - fields.append( - EmbedField( - name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"), - value=reminder.message, - inline=False, + if reminder.private and isinstance(ctx.channel, GuildChannel): + fields.append( + EmbedField( + name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"), + value="Private reminder", + inline=False, + ) + ) + else: + fields.append( + EmbedField( + name=reminder.remind_at.strftime("%Y-%m-%d %H:%M UTC"), + value=reminder.message, + inline=False, + ) ) - ) embed = build_embed( title="Deleted Reminder(s)", description="", @@ -260,7 +262,7 @@ class RemindmeCog(CacheCog): ) embed.set_author( - name=ctx.author.username + "#" + ctx.author.discriminator, + name=ctx.author.display_name + "#" + ctx.author.discriminator, icon_url=ctx.author.display_avatar.url, ) embed.set_thumbnail(url=ctx.author.display_avatar.url) diff --git a/jarvis/db/models.py b/jarvis/db/models.py index a99cb45..5c9b145 100644 --- a/jarvis/db/models.py +++ b/jarvis/db/models.py @@ -155,6 +155,7 @@ class Reminder(Document): message = StringField(max_length=100, required=True) remind_at = DateTimeField(required=True) created_at = DateTimeField(default=datetime.utcnow) + private = BooleanField(default=False) meta = {"db_alias": "main"} diff --git a/jarvis/tasks/reminder.py b/jarvis/tasks/reminder.py index 4c65e8e..b897e8e 100644 --- a/jarvis/tasks/reminder.py +++ b/jarvis/tasks/reminder.py @@ -25,7 +25,7 @@ async def _remind() -> None: fields=[], ) embed.set_author( - name=user.name + "#" + user.discriminator, icon_url=user.display_avatar.url + name=user.username + "#" + user.discriminator, icon_url=user.avatar.url ) embed.set_thumbnail(url=user.display_avatar.url) try: @@ -33,8 +33,13 @@ async def _remind() -> None: except Exception: guild = jarvis.jarvis.fetch_guild(reminder.guild) channel = guild.get_channel(reminder.channel) if guild else None - if channel: + if channel and not reminder.private: await channel.send(f"{user.mention}", embed=embed) + else: + await channel.send( + f"{user.mention}, you had a private reminder set for now, " + "but I couldn't send it to you." + ) finally: reminder.delete() diff --git a/jarvis/utils/__init__.py b/jarvis/utils/__init__.py index 11318e1..c5d8b19 100644 --- a/jarvis/utils/__init__.py +++ b/jarvis/utils/__init__.py @@ -125,11 +125,7 @@ def find_all(predicate: Callable, sequence: Iterable) -> List[Any]: A list of matches """ - matches = [] - for el in sequence: - if predicate(el): - matches.append(el) - return matches + return [el for el in sequence if predicate(el)] def get(sequence: Iterable, **kwargs: Any) -> Optional[Any]: