diff --git a/README.md b/README.md index 119bf2a..8f33d87 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@
J.A.R.V.I.S -# Just Another Very Intelligent System (J.A.R.V.I.S.) +# Just AnotheR Very Intelligent System (J.A.R.V.I.S.)
@@ -38,19 +38,17 @@ If you wish to contribute to the J.A.R.V.I.S codebase or documentation, join the Join the [Stark R&D Department Discord server](https://discord.gg/VtgZntXcnZ) to be kept up-to-date on code updates and issues. ## Requirements -- MongoDB 4.4 or higher -- Python 3.8 or higher +- MongoDB 5.0 or higher +- Python 3.10 or higher - [tokei](https://github.com/XAMPPRocky/tokei) 12.1 or higher On top of the above requirements, the following pip packages are also required: -- `discord-py>=1.7, <2` +- `dis-snek>=5.0.0` - `psutil>=5.8, <6` - `GitPython>=3.1, <4` - `PyYaml>=5.4, <6` -- `discord-py-slash-command>=2.3.2, <3` - `pymongo>=3.12.0, <4` - `opencv-python>=4.5, <5` -- `ButtonPaginator>=0.0.3` - `Pillow>=8.2.0, <9` - `python-gitlab>=2.9.0, <3` - `ulid-py>=1.1.0, <2` diff --git a/jarvis/cogs/autoreact.py b/jarvis/cogs/autoreact.py index 6d1263f..06c0ed3 100644 --- a/jarvis/cogs/autoreact.py +++ b/jarvis/cogs/autoreact.py @@ -1,46 +1,44 @@ """J.A.R.V.I.S. Autoreact Cog.""" import re +from typing import Optional, Tuple -from discord import TextChannel -from discord.ext import commands -from discord.utils import find -from discord_slash import SlashContext, cog_ext -from discord_slash.utils.manage_commands import create_option +from dis_snek import InteractionContext, Permissions, Scale, Snek +from dis_snek.models.discord.channel import GuildText +from dis_snek.models.snek.application_commands import ( + OptionTypes, + slash_command, + slash_option, +) from jarvis.data.unicode import emoji_list from jarvis.db.models import Autoreact +from jarvis.utils import find from jarvis.utils.permissions import admin_or_permissions -class AutoReactCog(commands.Cog): +class AutoReactCog(Scale): """J.A.R.V.I.S. Autoreact Cog.""" - def __init__(self, bot: commands.Bot): + def __init__(self, bot: Snek): self.bot = bot self.custom_emote = re.compile(r"^<:\w+:(\d+)>$") - @cog_ext.cog_subcommand( - base="autoreact", - name="create", - description="Add an autoreact to a channel", - options=[ - create_option( - name="channel", - description="Channel to monitor", - option_type=7, - required=True, - ) - ], - ) - @admin_or_permissions(manage_guild=True) - async def _autoreact_create(self, ctx: SlashContext, channel: TextChannel) -> None: - if not isinstance(channel, TextChannel): - await ctx.send("Channel must be a text channel", hidden=True) - return + async def create_autoreact( + self, ctx: InteractionContext, channel: GuildText + ) -> Tuple[bool, Optional[str]]: + """ + Create an autoreact monitor on a channel. + + Args: + ctx: Interaction context of command + channel: Channel to monitor + + Returns: + Tuple of success? and error message + """ exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() if exists: - await ctx.send(f"Autoreact already exists for {channel.mention}.", hidden=True) - return + return False, f"Autoreact already exists for {channel.mention}." _ = Autoreact( guild=ctx.guild.id, @@ -48,50 +46,38 @@ class AutoReactCog(commands.Cog): reactions=[], admin=ctx.author.id, ).save() - await ctx.send(f"Autoreact created for {channel.mention}!") - @cog_ext.cog_subcommand( - base="autoreact", - name="delete", - description="Delete an autoreact from a channel", - options=[ - create_option( - name="channel", - description="Channel to stop monitoring", - option_type=7, - required=True, - ) - ], - ) - @admin_or_permissions(manage_guild=True) - async def _autoreact_delete(self, ctx: SlashContext, channel: TextChannel) -> None: - exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).delete() - if exists: - await ctx.send(f"Autoreact removed from {channel.mention}") - else: - await ctx.send(f"Autoreact not found on {channel.mention}", hidden=True) + return True, None - @cog_ext.cog_subcommand( - base="autoreact", - name="add", - description="Add an autoreact emote to an existing autoreact", - options=[ - create_option( - name="channel", - description="Autoreact channel to add emote to", - option_type=7, - required=True, - ), - create_option( - name="emote", - description="Emote to add", - option_type=3, - required=True, - ), - ], + async def delete_autoreact(self, ctx: InteractionContext, channel: GuildText) -> bool: + """ + Remove an autoreact monitor on a channel. + + Args: + ctx: Interaction context of command + channel: Channel to stop monitoring + + Returns: + Success? + """ + return Autoreact.objects(guild=ctx.guild.id, channel=channel.id).delete() is not None + + @slash_command( + name="autoreact", + sub_cmd_name="add", + sub_cmd_description="Add an autoreact emote to a channel", ) - @admin_or_permissions(manage_guild=True) - async def _autoreact_add(self, ctx: SlashContext, channel: TextChannel, emote: str) -> None: + @slash_option( + name="channel", + description="Autoreact channel to add emote to", + option_type=OptionTypes.CHANNEL, + required=True, + ) + @slash_option( + name="emote", description="Emote to add", option_type=OptionTypes.STRING, required=True + ) + @admin_or_permissions(Permissions.MANAGE_GUILD) + async def _autoreact_add(self, ctx: InteractionContext, channel: GuildText, emote: str) -> None: await ctx.defer() custom_emoji = self.custom_emote.match(emote) standard_emoji = emote in emoji_list @@ -106,85 +92,86 @@ class AutoReactCog(commands.Cog): if not find(lambda x: x.id == emoji_id, ctx.guild.emojis): await ctx.send("Please use a custom emote from this server.", hidden=True) return - exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() - if not exists: - await ctx.send( - f"Please create autoreact first with /autoreact create {channel.mention}" - ) - return - if emote in exists.reactions: + autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() + if not autoreact: + self.create_autoreact(ctx, channel) + autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() + if emote in autoreact.reactions: await ctx.send( f"Emote already added to {channel.mention} autoreactions.", hidden=True, ) return - if len(exists.reactions) >= 5: + if len(autoreact.reactions) >= 5: await ctx.send( "Max number of reactions hit. Remove a different one to add this one", hidden=True, ) return - exists.reactions.append(emote) - exists.save() + autoreact.reactions.append(emote) + autoreact.save() await ctx.send(f"Added {emote} to {channel.mention} autoreact.") - @cog_ext.cog_subcommand( - base="autoreact", - name="remove", - description="Remove an autoreact emote from an existing autoreact", - options=[ - create_option( - name="channel", - description="Autoreact channel to remove emote from", - option_type=7, - required=True, - ), - create_option( - name="emote", - description="Emote to remove", - option_type=3, - required=True, - ), - ], + @slash_command( + name="autoreact", + sub_cmd_name="remove", + sub_cmd_description="Remove an autoreact emote to a channel", ) - @admin_or_permissions(manage_guild=True) - async def _autoreact_remove(self, ctx: SlashContext, channel: TextChannel, emote: str) -> None: - exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() - if not exists: + @slash_option( + name="channel", + description="Autoreact channel to remove emote from", + option_type=OptionTypes.CHANNEL, + required=True, + ) + @slash_option( + name="emote", + description="Emote to remove (use all to delete)", + option_type=OptionTypes.STRING, + required=True, + ) + @admin_or_permissions(Permissions.MANAGE_GUILD) + async def _autoreact_remove( + self, ctx: InteractionContext, channel: GuildText, emote: str + ) -> None: + autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() + if not autoreact: await ctx.send( - f"Please create autoreact first with /autoreact create {channel.mention}", + f"Please create autoreact first with /autoreact add {channel.mention} {emote}", hidden=True, ) return - if emote not in exists.reactions: + if emote.lower() == "all": + self.delete_autoreact(ctx, channel) + await ctx.send(f"Autoreact removed from {channel.mention}") + elif emote not in autoreact.reactions: await ctx.send( f"{emote} not used in {channel.mention} autoreactions.", hidden=True, ) return - exists.reactions.remove(emote) - exists.save() - await ctx.send(f"Removed {emote} from {channel.mention} autoreact.") + else: + autoreact.reactions.remove(emote) + autoreact.save() + if len(autoreact.reactions) == 0: + self.delete_autoreact(ctx, channel) + await ctx.send(f"Removed {emote} from {channel.mention} autoreact.") - @cog_ext.cog_subcommand( - base="autoreact", - name="list", - description="List all autoreacts on a channel", - options=[ - create_option( - name="channel", - description="Autoreact channel to list", - option_type=7, - required=True, - ), - ], + @slash_command( + name="autoreact", + sub_cmd_name="list", + sub_cmd_description="List all autoreacts on a channel", ) - @admin_or_permissions(manage_guild=True) - async def _autoreact_list(self, ctx: SlashContext, channel: TextChannel) -> None: + @slash_option( + name="channel", + description="Autoreact channel to list", + option_type=OptionTypes.CHANNEL, + required=True, + ) + async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None: exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() if not exists: await ctx.send( - f"Please create autoreact first with /autoreact create {channel.mention}", + f"Please create autoreact first with /autoreact add {channel.mention} ", hidden=True, ) return @@ -198,6 +185,6 @@ class AutoReactCog(commands.Cog): await ctx.send(message) -def setup(bot: commands.Bot) -> None: +def setup(bot: Snek) -> None: """Add AutoReactCog to J.A.R.V.I.S.""" bot.add_cog(AutoReactCog(bot))