From 88d596cad7286257b51530a3241e99ee76434aa1 Mon Sep 17 00:00:00 2001 From: Zevaryx Date: Fri, 4 Feb 2022 09:53:06 -0700 Subject: [PATCH] Fix common issues in cogs (ephemeral, opt_type, check) --- jarvis/cogs/admin/ban.py | 43 +++++++------- jarvis/cogs/admin/kick.py | 15 +++-- jarvis/cogs/admin/mute.py | 35 ++++++----- jarvis/cogs/admin/purge.py | 35 +++++------ jarvis/cogs/admin/roleping.py | 73 +++++++++++------------ jarvis/cogs/admin/warning.py | 29 +++++---- jarvis/cogs/autoreact.py | 31 +++++----- jarvis/cogs/ctc2.py | 16 ++--- jarvis/cogs/dbrand.py | 4 +- jarvis/cogs/dev.py | 24 ++++---- jarvis/cogs/error.py | 8 +-- jarvis/cogs/gitlab.py | 30 +++++----- jarvis/cogs/image.py | 2 +- jarvis/cogs/jokes.py | 6 +- jarvis/cogs/modlog/__init__.py | 6 +- jarvis/cogs/owner.py | 5 +- jarvis/cogs/remindme.py | 70 ++++++---------------- jarvis/cogs/rolegiver.py | 34 +++++------ jarvis/cogs/starboard.py | 55 +++++++++-------- jarvis/cogs/twitter.py | 79 +++++-------------------- jarvis/cogs/util.py | 104 +++++++++++++++++---------------- jarvis/cogs/verify.py | 2 +- 22 files changed, 310 insertions(+), 396 deletions(-) diff --git a/jarvis/cogs/admin/ban.py b/jarvis/cogs/admin/ban.py index 2859530..263239b 100644 --- a/jarvis/cogs/admin/ban.py +++ b/jarvis/cogs/admin/ban.py @@ -12,6 +12,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Ban, Unban from jarvis.utils import build_embed, find @@ -90,16 +91,14 @@ class BanCog(CacheCog): await ctx.send(embed=embed) @slash_command(name="ban", description="Ban a user") + @slash_option(name="user", description="User to ban", opt_type=OptionTypes.USER, required=True) @slash_option( - name="user", description="User to ban", option_type=OptionTypes.USER, required=True - ) - @slash_option( - name="reason", description="Ban reason", option_type=OptionTypes.STRING, required=True + name="reason", description="Ban reason", opt_type=OptionTypes.STRING, required=True ) @slash_option( name="btype", description="Ban type", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, choices=[ SlashCommandChoice(name="Permanent", value="perm"), @@ -107,7 +106,7 @@ class BanCog(CacheCog): SlashCommandChoice(name="Soft", value="soft"), ], ) - @admin_or_permissions(Permissions.BAN_MEMBERS) + @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _ban( self, ctx: InteractionContext, @@ -117,19 +116,19 @@ class BanCog(CacheCog): duration: int = 4, ) -> None: if not user or user == ctx.author: - await ctx.send("You cannot ban yourself.", hidden=True) + await ctx.send("You cannot ban yourself.", ephemeral=True) return if user == self.bot.user: - await ctx.send("I'm afraid I can't let you do that", hidden=True) + await ctx.send("I'm afraid I can't let you do that", ephemeral=True) return if btype == "temp" and duration < 0: - await ctx.send("You cannot set a temp ban to < 0 hours.", hidden=True) + await ctx.send("You cannot set a temp ban to < 0 hours.", ephemeral=True) return elif btype == "temp" and duration > 744: - await ctx.send("You cannot set a temp ban to > 1 month", hidden=True) + await ctx.send("You cannot set a temp ban to > 1 month", ephemeral=True) return if len(reason) > 100: - await ctx.send("Reason must be < 100 characters", hidden=True) + await ctx.send("Reason must be < 100 characters", ephemeral=True) return await ctx.defer() @@ -167,7 +166,7 @@ class BanCog(CacheCog): try: await ctx.guild.ban(user, reason=reason) except Exception as e: - await ctx.send(f"Failed to ban user:\n```\n{e}\n```", hidden=True) + await ctx.send(f"Failed to ban user:\n```\n{e}\n```", ephemeral=True) return send_failed = False if mtype == "soft": @@ -184,12 +183,12 @@ class BanCog(CacheCog): @slash_command(name="unban", description="Unban a user") @slash_option( - name="user", description="User to unban", option_type=OptionTypes.STRING, required=True + name="user", description="User to unban", opt_type=OptionTypes.STRING, required=True ) @slash_option( - name="reason", description="Unban reason", option_type=OptionTypes.STRING, required=True + name="reason", description="Unban reason", opt_type=OptionTypes.STRING, required=True ) - @admin_or_permissions(Permissions.BAN_MEMBERS) + @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _unban( self, ctx: InteractionContext, @@ -197,7 +196,7 @@ class BanCog(CacheCog): reason: str, ) -> None: if len(reason) > 100: - await ctx.send("Reason must be < 100 characters", hidden=True) + await ctx.send("Reason must be < 100 characters", ephemeral=True) return orig_user = user @@ -255,7 +254,7 @@ class BanCog(CacheCog): database_ban_info = Ban.objects(**search).first() if not discord_ban_info and not database_ban_info: - await ctx.send(f"Unable to find user {orig_user}", hidden=True) + await ctx.send(f"Unable to find user {orig_user}", ephemeral=True) elif discord_ban_info: await self.discord_apply_unban(ctx, discord_ban_info.user, reason) @@ -284,7 +283,7 @@ class BanCog(CacheCog): @slash_option( name="btype", description="Ban type", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, choices=[ SlashCommandChoice(name="All", value=0), @@ -296,19 +295,19 @@ class BanCog(CacheCog): @slash_option( name="active", description="Active bans", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, choices=[SlashCommandChoice(name="Yes", value=1), SlashCommandChoice(name="No", value=0)], ) - @admin_or_permissions(Permissions.BAN_MEMBERS) + @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _bans_list(self, ctx: InteractionContext, type: int = 0, active: int = 1) -> None: active = bool(active) exists = self.check_cache(ctx, type=type, active=active) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( f"Please use existing interaction: {exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return types = [0, "perm", "temp", "soft"] diff --git a/jarvis/cogs/admin/kick.py b/jarvis/cogs/admin/kick.py index b7b0a6d..28aaf79 100644 --- a/jarvis/cogs/admin/kick.py +++ b/jarvis/cogs/admin/kick.py @@ -7,6 +7,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Kick from jarvis.utils import build_embed @@ -17,22 +18,20 @@ class KickCog(Scale): """J.A.R.V.I.S. KickCog.""" @slash_command(name="kick", description="Kick a user") + @slash_option(name="user", description="User to kick", opt_type=OptionTypes.USER, required=True) @slash_option( - name="user", description="User to kick", option_type=OptionTypes.USER, required=True + name="reason", description="Kick reason", opt_type=OptionTypes.STRING, required=True ) - @slash_option( - name="reason", description="Kick reason", option_type=OptionTypes.STRING, required=True - ) - @admin_or_permissions(Permissions.BAN_MEMBERS) + @check(admin_or_permissions(Permissions.BAN_MEMBERS)) async def _kick(self, ctx: InteractionContext, user: User, reason: str) -> None: if not user or user == ctx.author: - await ctx.send("You cannot kick yourself.", hidden=True) + await ctx.send("You cannot kick yourself.", ephemeral=True) return if user == self.bot.user: - await ctx.send("I'm afraid I can't let you do that", hidden=True) + await ctx.send("I'm afraid I can't let you do that", ephemeral=True) return if len(reason) > 100: - await ctx.send("Reason must be < 100 characters", hidden=True) + await ctx.send("Reason must be < 100 characters", ephemeral=True) return guild_name = ctx.guild.name embed = build_embed( diff --git a/jarvis/cogs/admin/mute.py b/jarvis/cogs/admin/mute.py index b406fd4..8c36fbb 100644 --- a/jarvis/cogs/admin/mute.py +++ b/jarvis/cogs/admin/mute.py @@ -10,6 +10,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Mute from jarvis.utils import build_embed @@ -23,25 +24,23 @@ class MuteCog(Scale): self.bot = bot @slash_command(name="mute", description="Mute a user") - @slash_option( - name="user", description="User to mute", option_type=OptionTypes.USER, required=True - ) + @slash_option(name="user", description="User to mute", opt_type=OptionTypes.USER, required=True) @slash_option( name="reason", description="Reason for mute", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) @slash_option( name="time", description="Duration of mute, default 1", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) @slash_option( name="scale", description="Time scale, default Hour(s)", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, choices=[ SlashCommandChoice(name="Minute(s)", value=1), @@ -50,26 +49,28 @@ class MuteCog(Scale): SlashCommandChoice(name="Week(s)", value=604800), ], ) - @admin_or_permissions( - Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + @check( + admin_or_permissions( + Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + ) ) async def _timeout( self, ctx: InteractionContext, user: Member, reason: str, time: int = 1, scale: int = 60 ) -> None: if user == ctx.author: - await ctx.send("You cannot mute yourself.", hidden=True) + await ctx.send("You cannot mute yourself.", ephemeral=True) return if user == self.bot.user: - await ctx.send("I'm afraid I can't let you do that", hidden=True) + await ctx.send("I'm afraid I can't let you do that", ephemeral=True) return if len(reason) > 100: - await ctx.send("Reason must be < 100 characters", hidden=True) + await ctx.send("Reason must be < 100 characters", ephemeral=True) return # Max 4 weeks (2419200 seconds) per API duration = time * scale if duration > 2419200: - await ctx.send("Mute must be less than 4 weeks (2419200 seconds)", hidden=True) + await ctx.send("Mute must be less than 4 weeks (2419200 seconds)", ephemeral=True) return await user.timeout(communication_disabled_until=duration, reason=reason) @@ -97,17 +98,19 @@ class MuteCog(Scale): @slash_command(name="unmute", description="Unmute a user") @slash_option( - name="user", description="User to unmute", option_type=OptionTypes.USER, required=True + name="user", description="User to unmute", opt_type=OptionTypes.USER, required=True ) - @admin_or_permissions( - Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + @check( + admin_or_permissions( + Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS + ) ) async def _unmute(self, ctx: InteractionContext, user: Member) -> None: if ( not user.communication_disabled_until or user.communication_disabled_until < datetime.now() # noqa: W503 ): - await ctx.send("User is not muted", hidden=True) + await ctx.send("User is not muted", ephemeral=True) return embed = build_embed( diff --git a/jarvis/cogs/admin/purge.py b/jarvis/cogs/admin/purge.py index 3310416..e86cb1a 100644 --- a/jarvis/cogs/admin/purge.py +++ b/jarvis/cogs/admin/purge.py @@ -6,6 +6,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Autopurge, Purge from jarvis.utils.permissions import admin_or_permissions @@ -21,13 +22,13 @@ class PurgeCog(Scale): @slash_option( name="amount", description="Amount of messages to purge, default 10", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) - @admin_or_permissions(Permissions.MANAGE_MESSAGES) + @check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) async def _purge(self, ctx: InteractionContext, amount: int = 10) -> None: if amount < 1: - await ctx.send("Amount must be >= 1", hidden=True) + await ctx.send("Amount must be >= 1", ephemeral=True) return await ctx.defer() channel = ctx.channel @@ -48,31 +49,31 @@ class PurgeCog(Scale): @slash_option( name="channel", description="Channel to autopurge", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) @slash_option( name="delay", description="Seconds to keep message before purge, default 30", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) - @admin_or_permissions(Permissions.MANAGE_MESSAGES) + @check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) async def _autopurge_add( self, ctx: InteractionContext, channel: GuildText, delay: int = 30 ) -> None: if not isinstance(channel, GuildText): - await ctx.send("Channel must be a GuildText channel", hidden=True) + await ctx.send("Channel must be a GuildText channel", ephemeral=True) return if delay <= 0: - await ctx.send("Delay must be > 0", hidden=True) + await ctx.send("Delay must be > 0", ephemeral=True) return elif delay > 300: - await ctx.send("Delay must be < 5 minutes", hidden=True) + await ctx.send("Delay must be < 5 minutes", ephemeral=True) return autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id).first() if autopurge: - await ctx.send("Autopurge already exists.", hidden=True) + await ctx.send("Autopurge already exists.", ephemeral=True) return _ = Autopurge( guild=ctx.guild.id, @@ -88,14 +89,14 @@ class PurgeCog(Scale): @slash_option( name="channel", description="Channel to remove from autopurge", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) - @admin_or_permissions(Permissions.MANAGE_MESSAGES) + @check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) async def _autopurge_remove(self, ctx: InteractionContext, channel: GuildText) -> None: autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id) if not autopurge: - await ctx.send("Autopurge does not exist.", hidden=True) + await ctx.send("Autopurge does not exist.", ephemeral=True) return autopurge.delete() await ctx.send(f"Autopurge removed from {channel.mention}.") @@ -108,22 +109,22 @@ class PurgeCog(Scale): @slash_option( name="channel", description="Channel to update", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) @slash_option( name="delay", description="New time to save", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=True, ) - @admin_or_permissions(Permissions.MANAGE_MESSAGES) + @check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) async def _autopurge_update( self, ctx: InteractionContext, channel: GuildText, delay: int ) -> None: autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id) if not autopurge: - await ctx.send("Autopurge does not exist.", hidden=True) + await ctx.send("Autopurge does not exist.", ephemeral=True) return autopurge.delay = delay autopurge.save() diff --git a/jarvis/cogs/admin/roleping.py b/jarvis/cogs/admin/roleping.py index 14d2bbd..1dc1561 100644 --- a/jarvis/cogs/admin/roleping.py +++ b/jarvis/cogs/admin/roleping.py @@ -11,6 +11,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Roleping from jarvis.utils import build_embed @@ -27,14 +28,12 @@ class RolepingCog(CacheCog): @slash_command( name="roleping", sub_cmd_name="add", sub_cmd_description="Add a role to roleping" ) - @slash_option( - name="role", description="Role to add", option_type=OptionTypes.ROLE, required=True - ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None: roleping = Roleping.objects(guild=ctx.guild.id, role=role.id).first() if roleping: - await ctx.send(f"Role `{role.name}` already in roleping.", hidden=True) + await ctx.send(f"Role `{role.name}` already in roleping.", ephemeral=True) return _ = Roleping( role=role.id, @@ -47,13 +46,13 @@ class RolepingCog(CacheCog): @slash_command(name="roleping", sub_cmd_name="remove", sub_cmd_description="Remove a role") @slash_option( - name="role", description="Role to remove", option_type=OptionTypes.ROLE, required=True + name="role", description="Role to remove", opt_type=OptionTypes.ROLE, required=True ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None: roleping = Roleping.objects(guild=ctx.guild.id, role=role.id) if not roleping: - await ctx.send("Roleping does not exist", hidden=True) + await ctx.send("Roleping does not exist", ephemeral=True) return roleping.delete() @@ -63,16 +62,16 @@ class RolepingCog(CacheCog): async def _roleping_list(self, ctx: InteractionContext) -> None: exists = self.check_cache(ctx) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( f"Please use existing interaction: {exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return rolepings = Roleping.objects(guild=ctx.guild.id) if not rolepings: - await ctx.send("No rolepings configured", hidden=True) + await ctx.send("No rolepings configured", ephemeral=True) return embeds = [] @@ -137,29 +136,27 @@ class RolepingCog(CacheCog): sub_cmd_name="user", sub_cmd_description="Add a user as a bypass to a roleping", ) + @slash_option(name="user", description="User to add", opt_type=OptionTypes.USER, required=True) @slash_option( - name="user", description="User to add", option_type=OptionTypes.USER, required=True + name="rping", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True ) - @slash_option( - name="rping", description="Rolepinged role", option_type=OptionTypes.ROLE, required=True - ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _roleping_bypass_user( self, ctx: InteractionContext, user: Member, rping: Role ) -> None: roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() if not roleping: - await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True) + await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) return if user.id in roleping.bypass["users"]: - await ctx.send(f"{user.mention} already in bypass", hidden=True) + await ctx.send(f"{user.mention} already in bypass", ephemeral=True) return if len(roleping.bypass["users"]) == 10: await ctx.send( "Already have 10 users in bypass. Please consider using roles for roleping bypass", - hidden=True, + ephemeral=True, ) return @@ -168,7 +165,7 @@ class RolepingCog(CacheCog): if matching_role: await ctx.send( f"{user.mention} already has bypass via {matching_role[0].mention}", - hidden=True, + ephemeral=True, ) return @@ -182,28 +179,26 @@ class RolepingCog(CacheCog): sub_cmd_name="role", description="Add a role as a bypass to roleping", ) + @slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) @slash_option( - name="role", description="Role to add", option_type=OptionTypes.ROLE, required=True + name="rping", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True ) - @slash_option( - name="rping", description="Rolepinged role", option_type=OptionTypes.ROLE, required=True - ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _roleping_bypass_role(self, ctx: InteractionContext, role: Role, rping: Role) -> None: roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() if not roleping: - await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True) + await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) return if role.id in roleping.bypass["roles"]: - await ctx.send(f"{role.mention} already in bypass", hidden=True) + await ctx.send(f"{role.mention} already in bypass", ephemeral=True) return if len(roleping.bypass["roles"]) == 10: await ctx.send( "Already have 10 roles in bypass. " "Please consider consolidating roles for roleping bypass", - hidden=True, + ephemeral=True, ) return @@ -220,22 +215,22 @@ class RolepingCog(CacheCog): sub_cmd_description="Remove a bypass from a roleping (restoring it)", ) @slash_option( - name="user", description="User to remove", option_type=OptionTypes.USER, required=True + name="user", description="User to remove", opt_type=OptionTypes.USER, required=True ) @slash_option( - name="rping", description="Rolepinged role", option_type=OptionTypes.ROLE, required=True + name="rping", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _roleping_restore_user( self, ctx: InteractionContext, user: Member, rping: Role ) -> None: roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() if not roleping: - await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True) + await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) return if user.id not in roleping.bypass["users"]: - await ctx.send(f"{user.mention} not in bypass", hidden=True) + await ctx.send(f"{user.mention} not in bypass", ephemeral=True) return roleping.bypass["users"].delete(user.id) @@ -249,29 +244,29 @@ class RolepingCog(CacheCog): description="Remove a bypass from a roleping (restoring it)", ) @slash_option( - name="role", description="Role to remove", option_type=OptionTypes.ROLE, required=True + name="role", description="Role to remove", opt_type=OptionTypes.ROLE, required=True ) @slash_option( - name="rping", description="Rolepinged role", option_type=OptionTypes.ROLE, required=True + name="rping", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True ) - @admin_or_permissions(manage_guild=True) + @check(admin_or_permissions(manage_guild=True)) async def _roleping_restore_role( self, ctx: InteractionContext, role: Role, rping: Role ) -> None: roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() if not roleping: - await ctx.send(f"Roleping not configured for {rping.mention}", hidden=True) + await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) return if role.id in roleping.bypass["roles"]: - await ctx.send(f"{role.mention} already in bypass", hidden=True) + await ctx.send(f"{role.mention} already in bypass", ephemeral=True) return if len(roleping.bypass["roles"]) == 10: await ctx.send( "Already have 10 roles in bypass. " "Please consider consolidating roles for roleping bypass", - hidden=True, + ephemeral=True, ) return diff --git a/jarvis/cogs/admin/warning.py b/jarvis/cogs/admin/warning.py index f81443f..aa75f70 100644 --- a/jarvis/cogs/admin/warning.py +++ b/jarvis/cogs/admin/warning.py @@ -10,6 +10,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Warning from jarvis.utils import build_embed @@ -25,33 +26,31 @@ class WarningCog(CacheCog): super().__init__(bot) @slash_command(name="warn", description="Warn a user") - @slash_option( - name="user", description="User to warn", option_type=OptionTypes.USER, required=True - ) + @slash_option(name="user", description="User to warn", opt_type=OptionTypes.USER, required=True) @slash_option( name="reason", description="Reason for warning", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) @slash_option( name="duration", description="Duration of warning in hours, default 24", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _warn( self, ctx: InteractionContext, user: User, reason: str, duration: int = 24 ) -> None: if len(reason) > 100: - await ctx.send("Reason must be < 100 characters", hidden=True) + await ctx.send("Reason must be < 100 characters", ephemeral=True) return if duration <= 0: - await ctx.send("Duration must be > 0", hidden=True) + await ctx.send("Duration must be > 0", ephemeral=True) return elif duration >= 120: - await ctx.send("Duration must be < 5 days", hidden=True) + await ctx.send("Duration must be < 5 days", ephemeral=True) return await ctx.defer() _ = Warning( @@ -77,28 +76,26 @@ class WarningCog(CacheCog): await ctx.send(embed=embed) @slash_command(name="warnings", description="Get count of user warnings") - @slash_option( - name="user", description="User to view", option_type=OptionTypes.USER, required=True - ) + @slash_option(name="user", description="User to view", opt_type=OptionTypes.USER, required=True) @slash_option( name="active", description="View active only", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, choices=[ SlashCommandChoice(name="Yes", value=1), SlashCommandChoice(name="No", value=0), ], ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _warnings(self, ctx: InteractionContext, user: User, active: bool = 1) -> None: active = bool(active) exists = self.check_cache(ctx, user_id=user.id, active=active) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( f"Please use existing interaction: {exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return warnings = Warning.objects( diff --git a/jarvis/cogs/autoreact.py b/jarvis/cogs/autoreact.py index 289b3d8..78d403b 100644 --- a/jarvis/cogs/autoreact.py +++ b/jarvis/cogs/autoreact.py @@ -9,6 +9,7 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.data.unicode import emoji_list from jarvis.db.models import Autoreact @@ -70,13 +71,13 @@ class AutoReactCog(Scale): @slash_option( name="channel", description="Autoreact channel to add emote to", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) @slash_option( - name="emote", description="Emote to add", option_type=OptionTypes.STRING, required=True + name="emote", description="Emote to add", opt_type=OptionTypes.STRING, required=True ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(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) @@ -84,13 +85,13 @@ class AutoReactCog(Scale): if not custom_emoji and not standard_emoji: await ctx.send( "Please use either an emote from this server or a unicode emoji.", - hidden=True, + ephemeral=True, ) return if custom_emoji: emoji_id = int(custom_emoji.group(1)) 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) + await ctx.send("Please use a custom emote from this server.", ephemeral=True) return autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() if not autoreact: @@ -99,13 +100,13 @@ class AutoReactCog(Scale): if emote in autoreact.reactions: await ctx.send( f"Emote already added to {channel.mention} autoreactions.", - hidden=True, + ephemeral=True, ) return if len(autoreact.reactions) >= 5: await ctx.send( "Max number of reactions hit. Remove a different one to add this one", - hidden=True, + ephemeral=True, ) return autoreact.reactions.append(emote) @@ -120,16 +121,16 @@ class AutoReactCog(Scale): @slash_option( name="channel", description="Autoreact channel to remove emote from", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) @slash_option( name="emote", description="Emote to remove (use all to delete)", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _autoreact_remove( self, ctx: InteractionContext, channel: GuildText, emote: str ) -> None: @@ -137,7 +138,7 @@ class AutoReactCog(Scale): if not autoreact: await ctx.send( f"Please create autoreact first with /autoreact add {channel.mention} {emote}", - hidden=True, + ephemeral=True, ) return if emote.lower() == "all": @@ -146,7 +147,7 @@ class AutoReactCog(Scale): elif emote not in autoreact.reactions: await ctx.send( f"{emote} not used in {channel.mention} autoreactions.", - hidden=True, + ephemeral=True, ) return else: @@ -164,7 +165,7 @@ class AutoReactCog(Scale): @slash_option( name="channel", description="Autoreact channel to list", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None: @@ -172,7 +173,7 @@ class AutoReactCog(Scale): if not exists: await ctx.send( f"Please create autoreact first with /autoreact add {channel.mention} ", - hidden=True, + ephemeral=True, ) return message = "" @@ -187,4 +188,4 @@ class AutoReactCog(Scale): def setup(bot: Snake) -> None: """Add AutoReactCog to J.A.R.V.I.S.""" - bot.add_cog(AutoReactCog(bot)) + AutoReactCog(bot) diff --git a/jarvis/cogs/ctc2.py b/jarvis/cogs/ctc2.py index 72687eb..d509f0f 100644 --- a/jarvis/cogs/ctc2.py +++ b/jarvis/cogs/ctc2.py @@ -56,7 +56,7 @@ class CTCCog(CacheCog): "Listen here, dipshit. Don't be like <@256110768724901889>. " "Make your guesses < 800 characters." ), - hidden=True, + ephemeral=True, ) return elif not valid.fullmatch(guess): @@ -65,18 +65,18 @@ class CTCCog(CacheCog): "Listen here, dipshit. Don't be like <@256110768724901889>. " "Make your guesses *readable*." ), - hidden=True, + ephemeral=True, ) return elif invites.search(guess): await ctx.send( "Listen here, dipshit. No using this to bypass sending invite links.", - hidden=True, + ephemeral=True, ) return guessed = Guess.objects(guess=guess).first() if guessed: - await ctx.send("Already guessed, dipshit.", hidden=True) + await ctx.send("Already guessed, dipshit.", ephemeral=True) return result = await self._session.post(self.url, data=guess) correct = False @@ -84,7 +84,7 @@ class CTCCog(CacheCog): await ctx.send(f"{ctx.author.mention} got it! Password is {guess}!") correct = True else: - await ctx.send("Nope.", hidden=True) + await ctx.send("Nope.", ephemeral=True) _ = Guess(guess=guess, user=ctx.author.id, correct=correct).save() @slash_command( @@ -97,10 +97,10 @@ class CTCCog(CacheCog): async def _guesses(self, ctx: InteractionContext) -> None: exists = self.check_cache(ctx) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( f"Please use existing interaction: {exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return @@ -153,4 +153,4 @@ class CTCCog(CacheCog): def setup(bot: Snake) -> None: """Add CTCCog to J.A.R.V.I.S.""" - bot.add_cog(CTCCog(bot)) + CTCCog(bot) diff --git a/jarvis/cogs/dbrand.py b/jarvis/cogs/dbrand.py index 4858202..a6f0f41 100644 --- a/jarvis/cogs/dbrand.py +++ b/jarvis/cogs/dbrand.py @@ -156,7 +156,7 @@ class DbrandCog(Scale): @slash_option( name="search", description="Country search query (2 character code, country name, flag emoji)", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) @cooldown(bucket=Buckets.USER, rate=1, interval=2) @@ -266,4 +266,4 @@ class DbrandCog(Scale): def setup(bot: Snake) -> None: """Add dbrandcog to J.A.R.V.I.S.""" - bot.add_cog(DbrandCog(bot)) + DbrandCog(bot) diff --git a/jarvis/cogs/dev.py b/jarvis/cogs/dev.py index 2997901..98f2db2 100644 --- a/jarvis/cogs/dev.py +++ b/jarvis/cogs/dev.py @@ -68,14 +68,14 @@ class DevCog(Scale): @slash_option( name="method", description="Hash method", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, choices=[SlashCommandChoice(name=x, value=x) for x in supported_hashes], ) @slash_option( name="data", description="Data to hash", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) @cooldown(bucket=Buckets.USER, rate=1, interval=2) @@ -83,7 +83,7 @@ class DevCog(Scale): if not data: await ctx.send( "No data to hash", - hidden=True, + ephemeral=True, ) return text = True @@ -105,20 +105,20 @@ class DevCog(Scale): @slash_option( name="version", description="UUID version", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, choices=[SlashCommandChoice(name=x, value=x) for x in ["3", "4", "5"]], ) @slash_option( name="data", description="Data for UUID version 3,5", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=False, ) async def _uuid(self, ctx: InteractionContext, version: str, data: str = None) -> None: version = int(version) if version in [3, 5] and not data: - await ctx.send(f"UUID{version} requires data.", hidden=True) + await ctx.send(f"UUID{version} requires data.", ephemeral=True) return if version == 4: await ctx.send(f"UUID4: `{uuidpy.uuid4()}`") @@ -180,14 +180,14 @@ class DevCog(Scale): @slash_option( name="method", description="Encode method", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods], ) @slash_option( name="data", description="Data to encode", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) async def _encode(self, ctx: InteractionContext, method: str, data: str) -> None: @@ -205,14 +205,14 @@ class DevCog(Scale): @slash_option( name="method", description="Decode method", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, choices=[SlashCommandChoice(name=x, value=x) for x in base64_methods], ) @slash_option( name="data", description="Data to encode", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) async def _decode(self, ctx: InteractionContext, method: str, data: str) -> None: @@ -222,7 +222,7 @@ class DevCog(Scale): if invites.search(decoded): await ctx.send( "Please don't use this to bypass invite restrictions", - hidden=True, + ephemeral=True, ) return fields = [ @@ -243,4 +243,4 @@ class DevCog(Scale): def setup(bot: Snake) -> None: """Add DevCog to J.A.R.V.I.S.""" - bot.add_cog(DevCog(bot)) + DevCog(bot) diff --git a/jarvis/cogs/error.py b/jarvis/cogs/error.py index 3715d03..d245b0c 100644 --- a/jarvis/cogs/error.py +++ b/jarvis/cogs/error.py @@ -33,19 +33,19 @@ class ErrorHandlerCog(commands.Cog): if isinstance(error, commands.errors.MissingPermissions) or isinstance( error, commands.errors.CheckFailure ): - await ctx.send("I'm afraid I can't let you do that.", hidden=True) + await ctx.send("I'm afraid I can't let you do that.", ephemeral=True) elif isinstance(error, commands.errors.CommandNotFound): return elif isinstance(error, commands.errors.CommandOnCooldown): await ctx.send( "Command on cooldown. " f"Please wait {error.retry_after:0.2f}s before trying again", - hidden=True, + ephemeral=True, ) else: await ctx.send( f"Error processing command:\n```{error}```", - hidden=True, + ephemeral=True, ) raise error slash.commands[ctx.command].reset_cooldown(ctx) @@ -53,4 +53,4 @@ class ErrorHandlerCog(commands.Cog): def setup(bot: commands.Bot) -> None: """Add ErrorHandlerCog to J.A.R.V.I.S.""" - bot.add_cog(ErrorHandlerCog(bot)) + ErrorHandlerCog(bot) diff --git a/jarvis/cogs/gitlab.py b/jarvis/cogs/gitlab.py index becc05f..6c769b0 100644 --- a/jarvis/cogs/gitlab.py +++ b/jarvis/cogs/gitlab.py @@ -32,12 +32,12 @@ class GitlabCog(CacheCog): @slash_command( name="gl", sub_cmd_name="issue", description="Get an issue from GitLab", scopes=guild_ids ) - @slash_option(name="id", description="Issue ID", option_type=OptionTypes.INTEGER, required=True) + @slash_option(name="id", description="Issue ID", opt_type=OptionTypes.INTEGER, required=True) async def _issue(self, ctx: InteractionContext, id: int) -> None: try: issue = self.project.issues.get(int(id)) except gitlab.exceptions.GitlabGetError: - await ctx.send("Issue does not exist.", hidden=True) + await ctx.send("Issue does not exist.", ephemeral=True) return assignee = issue.assignee if assignee: @@ -101,13 +101,13 @@ class GitlabCog(CacheCog): scopes=guild_ids, ) @slash_option( - name="id", description="Milestone ID", option_type=OptionTypes.INTEGER, required=True + name="id", description="Milestone ID", opt_type=OptionTypes.INTEGER, required=True ) async def _milestone(self, ctx: InteractionContext, id: int) -> None: try: milestone = self.project.milestones.get(int(id)) except gitlab.exceptions.GitlabGetError: - await ctx.send("Milestone does not exist.", hidden=True) + await ctx.send("Milestone does not exist.", ephemeral=True) return created_at = datetime.strptime(milestone.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( @@ -157,13 +157,13 @@ class GitlabCog(CacheCog): scopes=guild_ids, ) @slash_option( - name="id", description="Merge Request ID", option_type=OptionTypes.INTEGER, required=True + name="id", description="Merge Request ID", opt_type=OptionTypes.INTEGER, required=True ) async def _mergerequest(self, ctx: InteractionContext, id: int) -> None: try: mr = self.project.mergerequests.get(int(id)) except gitlab.exceptions.GitlabGetError: - await ctx.send("Merge request does not exist.", hidden=True) + await ctx.send("Merge request does not exist.", ephemeral=True) return assignee = mr.assignee if assignee: @@ -266,7 +266,7 @@ class GitlabCog(CacheCog): @slash_option( name="state", description="State of issues to get", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=False, choices=[ SlashCommandChoice(name="Open", value="opened"), @@ -277,10 +277,10 @@ class GitlabCog(CacheCog): async def _issues(self, ctx: InteractionContext, state: str = "opened") -> None: exists = self.check_cache(ctx, state=state) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( "Please use existing interaction: " + f"{exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return await ctx.defer() @@ -339,7 +339,7 @@ class GitlabCog(CacheCog): @slash_option( name="state", description="State of merge requests to get", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=False, choices=[ SlashCommandChoice(name="Open", value="opened"), @@ -350,10 +350,10 @@ class GitlabCog(CacheCog): async def _mergerequests(self, ctx: InteractionContext, state: str = "opened") -> None: exists = self.check_cache(ctx, state=state) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( "Please use existing interaction: " + f"{exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return await ctx.defer() @@ -414,10 +414,10 @@ class GitlabCog(CacheCog): async def _milestones(self, ctx: InteractionContext) -> None: exists = self.check_cache(ctx) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( f"Please use existing interaction: {exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return await ctx.defer() @@ -464,4 +464,4 @@ class GitlabCog(CacheCog): def setup(bot: Snake) -> None: """Add GitlabCog to J.A.R.V.I.S. if Gitlab token exists.""" if get_config().gitlab_token: - bot.add_cog(GitlabCog(bot)) + GitlabCog(bot) diff --git a/jarvis/cogs/image.py b/jarvis/cogs/image.py index 45fc0c8..83aff59 100644 --- a/jarvis/cogs/image.py +++ b/jarvis/cogs/image.py @@ -105,4 +105,4 @@ class ImageCog(Scale): def setup(bot: Snake) -> None: """Add ImageCog to J.A.R.V.I.S.""" - bot.add_cog(ImageCog(bot)) + ImageCog(bot) diff --git a/jarvis/cogs/jokes.py b/jarvis/cogs/jokes.py index 2512695..0bf3fcc 100644 --- a/jarvis/cogs/jokes.py +++ b/jarvis/cogs/jokes.py @@ -34,7 +34,7 @@ class JokeCog(Scale): name="joke", description="Hear a joke", ) - @slash_option(name="id", description="Joke ID", required=False, option_type=OptionTypes.INTEGER) + @slash_option(name="id", description="Joke ID", required=False, opt_type=OptionTypes.INTEGER) @cooldown(bucket=Buckets.CHANNEL, rate=1, interval=10) async def _joke(self, ctx: InteractionContext, id: str = None) -> None: """Get a joke from the database.""" @@ -57,7 +57,7 @@ class JokeCog(Scale): result = Joke.objects().aggregate(pipeline).next() if result is None: - await ctx.send("Humor module failed. Please try again later.", hidden=True) + await ctx.send("Humor module failed. Please try again later.", ephemeral=True) return emotes = re.findall(r"(&#x[a-fA-F0-9]*;)", result["body"]) for match in emotes: @@ -118,4 +118,4 @@ class JokeCog(Scale): def setup(bot: Snake) -> None: """Add JokeCog to J.A.R.V.I.S.""" - bot.add_cog(JokeCog(bot)) + JokeCog(bot) diff --git a/jarvis/cogs/modlog/__init__.py b/jarvis/cogs/modlog/__init__.py index 9e72344..63c09e2 100644 --- a/jarvis/cogs/modlog/__init__.py +++ b/jarvis/cogs/modlog/__init__.py @@ -6,6 +6,6 @@ from jarvis.cogs.modlog import command, member, message def setup(bot: Bot) -> None: """Add modlog cogs to J.A.R.V.I.S.""" - bot.add_cog(command.ModlogCommandCog(bot)) - bot.add_cog(member.ModlogMemberCog(bot)) - bot.add_cog(message.ModlogMessageCog(bot)) + command.ModlogCommandCog(bot) + member.ModlogMemberCog(bot) + message.ModlogMessageCog(bot) diff --git a/jarvis/cogs/owner.py b/jarvis/cogs/owner.py index 0e55bde..c00118e 100644 --- a/jarvis/cogs/owner.py +++ b/jarvis/cogs/owner.py @@ -2,6 +2,7 @@ from dis_snek import MessageContext, Scale, Snake, message_command from dis_snek.models.discord.user import User from dis_snek.models.snek.checks import is_owner +from dis_snek.models.snek.command import check from jarvis.config import reload_config from jarvis.db.models import Config @@ -19,7 +20,7 @@ class OwnerCog(Scale): self.admins = Config.objects(key="admins").first() @message_command(name="addadmin") - @is_owner() + @check(is_owner()) async def _add(self, ctx: MessageContext, user: User) -> None: if user.id in self.admins.value: await ctx.send(f"{user.mention} is already an admin.") @@ -43,4 +44,4 @@ class OwnerCog(Scale): def setup(bot: Snake) -> None: """Add OwnerCog to J.A.R.V.I.S.""" - bot.add_cog(OwnerCog(bot)) + OwnerCog(bot) diff --git a/jarvis/cogs/remindme.py b/jarvis/cogs/remindme.py index a5c7ccf..e1973ca 100644 --- a/jarvis/cogs/remindme.py +++ b/jarvis/cogs/remindme.py @@ -6,8 +6,6 @@ from typing import List, Optional from bson import ObjectId from dis_snek import InteractionContext, Snake -from dis_snek.ext.tasks.task import Task -from dis_snek.ext.tasks.triggers import IntervalTrigger 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 ( @@ -32,34 +30,33 @@ class RemindmeCog(CacheCog): def __init__(self, bot: Snake): super().__init__(bot) - self._remind.start() @slash_command(name="remindme", description="Set a reminder") @slash_option( name="message", description="What to remind you of?", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) @slash_option( name="weeks", description="Number of weeks?", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) @slash_option( - name="days", description="Number of days?", option_type=OptionTypes.INTEGER, required=False + name="days", description="Number of days?", opt_type=OptionTypes.INTEGER, required=False ) @slash_option( name="hours", description="Number of hours?", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) @slash_option( name="minutes", description="Number of minutes?", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) async def _remindme( @@ -72,20 +69,20 @@ class RemindmeCog(CacheCog): minutes: Optional[int] = 0, ) -> None: if len(message) > 100: - await ctx.send("Reminder cannot be > 100 characters.", hidden=True) + await ctx.send("Reminder cannot be > 100 characters.", ephemeral=True) return elif invites.search(message): await ctx.send( "Listen, don't use this to try and bypass the rules", - hidden=True, + ephemeral=True, ) return elif not valid.fullmatch(message): - await ctx.send("Hey, you should probably make this readable", hidden=True) + await ctx.send("Hey, you should probably make this readable", ephemeral=True) return if not any([weeks, days, hours, minutes]): - await ctx.send("At least one time period is required", hidden=True) + await ctx.send("At least one time period is required", ephemeral=True) return weeks = abs(weeks) @@ -94,19 +91,19 @@ class RemindmeCog(CacheCog): minutes = abs(minutes) if weeks and weeks > 4: - await ctx.send("Cannot be farther than 4 weeks out!", hidden=True) + 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.", hidden=True) + 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.", hidden=True) + 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.", hidden=True) + await ctx.send("Use hours instead of 59+ minutes, please.", ephemeral=True) return reminders = Reminder.objects(user=ctx.author.id, active=True).count() @@ -114,7 +111,7 @@ class RemindmeCog(CacheCog): await ctx.send( "You already have 5 (or more) active reminders. " "Please either remove an old one, or wait for one to pass", - hidden=True, + ephemeral=True, ) return @@ -187,15 +184,15 @@ class RemindmeCog(CacheCog): async def _list(self, ctx: InteractionContext) -> None: exists = self.check_cache(ctx) if exists: - await ctx.defer(hidden=True) + await ctx.defer(ephemeral=True) await ctx.send( f"Please use existing interaction: {exists['paginator']._message.jump_url}", - hidden=True, + ephemeral=True, ) return reminders = Reminder.objects(user=ctx.author.id, active=True) if not reminders: - await ctx.send("You have no reminders set.", hidden=True) + await ctx.send("You have no reminders set.", ephemeral=True) return embed = await self.get_reminders_embed(ctx, reminders) @@ -206,7 +203,7 @@ class RemindmeCog(CacheCog): async def _delete(self, ctx: InteractionContext) -> None: reminders = Reminder.objects(user=ctx.author.id, active=True) if not reminders: - await ctx.send("You have no reminders set", hidden=True) + await ctx.send("You have no reminders set", ephemeral=True) return options = [] @@ -279,36 +276,7 @@ class RemindmeCog(CacheCog): component["disabled"] = True await message.edit(components=components) - @Task.create(trigger=IntervalTrigger(seconds=15)) - async def _remind(self) -> None: - reminders = Reminder.objects(remind_at__lte=datetime.utcnow() + timedelta(seconds=30)) - for reminder in reminders: - if reminder.remind_at <= datetime.utcnow(): - user = await self.bot.fetch_user(reminder.user) - if not user: - reminder.delete() - continue - embed = build_embed( - title="You have a reminder", - description=reminder.message, - fields=[], - ) - embed.set_author( - name=user.name + "#" + user.discriminator, - icon_url=user.display_avatar, - ) - embed.set_thumbnail(url=user.display_avatar) - try: - await user.send(embed=embed) - except Exception: - guild = self.bot.fetch_guild(reminder.guild) - channel = guild.get_channel(reminder.channel) if guild else None - if channel: - await channel.send(f"{user.mention}", embed=embed) - finally: - reminder.delete() - def setup(bot: Snake) -> None: """Add RemindmeCog to J.A.R.V.I.S.""" - bot.add_cog(RemindmeCog(bot)) + RemindmeCog(bot) diff --git a/jarvis/cogs/rolegiver.py b/jarvis/cogs/rolegiver.py index f4e076c..b8e6b64 100644 --- a/jarvis/cogs/rolegiver.py +++ b/jarvis/cogs/rolegiver.py @@ -2,7 +2,6 @@ import asyncio from dis_snek import InteractionContext, Permissions, Scale, Snake -from dis_snek.client.utils import get from dis_snek.models.discord.components import ActionRow, Select, SelectOption from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.role import Role @@ -11,11 +10,11 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) -from dis_snek.models.snek.command import cooldown +from dis_snek.models.snek.command import check, cooldown from dis_snek.models.snek.cooldowns import Buckets from jarvis.db.models import Rolegiver -from jarvis.utils import build_embed +from jarvis.utils import build_embed, get from jarvis.utils.permissions import admin_or_permissions @@ -28,21 +27,19 @@ class RolegiverCog(Scale): @slash_command( name="rolegiver", sub_cmd_name="add", sub_cmd_description="Add a role to rolegiver" ) - @slash_option( - name="role", description="Role to add", optin_type=OptionTypes.ROLE, required=True - ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None: setting = Rolegiver.objects(guild=ctx.guild.id).first() if setting and role.id in setting.roles: - await ctx.send("Role already in rolegiver", hidden=True) + await ctx.send("Role already in rolegiver", ephemeral=True) return if not setting: setting = Rolegiver(guild=ctx.guild.id, roles=[]) if len(setting.roles) >= 20: - await ctx.send("You can only have 20 roles in the rolegiver", hidden=True) + await ctx.send("You can only have 20 roles in the rolegiver", ephemeral=True) return setting.roles.append(role.id) @@ -84,11 +81,11 @@ class RolegiverCog(Scale): @slash_command( name="rolegiver", sub_cmd_name="remove", sub_cmd_description="Remove a role from rolegiver" ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _rolegiver_remove(self, ctx: InteractionContext) -> None: setting = Rolegiver.objects(guild=ctx.guild.id).first() if not setting or (setting and not setting.roles): - await ctx.send("Rolegiver has no roles", hidden=True) + await ctx.send("Rolegiver has no roles", ephemeral=True) return options = [] @@ -168,7 +165,7 @@ class RolegiverCog(Scale): async def _rolegiver_list(self, ctx: InteractionContext) -> None: setting = Rolegiver.objects(guild=ctx.guild.id).first() if not setting or (setting and not setting.roles): - await ctx.send("Rolegiver has no roles", hidden=True) + await ctx.send("Rolegiver has no roles", ephemeral=True) return roles = [] @@ -204,7 +201,7 @@ class RolegiverCog(Scale): async def _role_get(self, ctx: InteractionContext) -> None: setting = Rolegiver.objects(guild=ctx.guild.id).first() if not setting or (setting and not setting.roles): - await ctx.send("Rolegiver has no roles", hidden=True) + await ctx.send("Rolegiver has no roles", ephemeral=True) return options = [] @@ -283,10 +280,10 @@ class RolegiverCog(Scale): setting = Rolegiver.objects(guild=ctx.guild.id).first() if not setting or (setting and not setting.roles): - await ctx.send("Rolegiver has no roles", hidden=True) + await ctx.send("Rolegiver has no roles", ephemeral=True) return elif not any(x.id in setting.roles for x in user_roles): - await ctx.send("You have no rolegiver roles", hidden=True) + await ctx.send("You have no rolegiver roles", ephemeral=True) return valid = list(filter(lambda x: x.id in setting.roles, user_roles)) @@ -361,11 +358,11 @@ class RolegiverCog(Scale): @slash_command( name="rolegiver", sub_cmd_name="cleanup", description="Removed deleted roles from rolegiver" ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _rolegiver_cleanup(self, ctx: InteractionContext) -> None: setting = Rolegiver.objects(guild=ctx.guild.id).first() if not setting or not setting.roles: - await ctx.send("Rolegiver has no roles", hidden=True) + await ctx.send("Rolegiver has no roles", ephemeral=True) guild_role_ids = [r.id for r in ctx.guild.roles] for role_id in setting.roles: if role_id not in guild_role_ids: @@ -377,5 +374,4 @@ class RolegiverCog(Scale): def setup(bot: Snake) -> None: """Add RolegiverCog to J.A.R.V.I.S.""" - bot.add_cog(RolegiverCog(bot)) - bot.add_cog(RolegiverCog(bot)) + RolegiverCog(bot) diff --git a/jarvis/cogs/starboard.py b/jarvis/cogs/starboard.py index 81747bb..2f39d5f 100644 --- a/jarvis/cogs/starboard.py +++ b/jarvis/cogs/starboard.py @@ -1,6 +1,5 @@ """J.A.R.V.I.S. Starboard Cog.""" from dis_snek import InteractionContext, Permissions, Scale, Snake -from dis_snek.client.utils import find from dis_snek.models.discord.channel import GuildText from dis_snek.models.discord.components import ActionRow, Select, SelectOption from dis_snek.models.discord.message import Message @@ -11,9 +10,10 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.db.models import Star, Starboard -from jarvis.utils import build_embed +from jarvis.utils import build_embed, find from jarvis.utils.permissions import admin_or_permissions supported_images = [ @@ -32,7 +32,7 @@ class StarboardCog(Scale): self.bot = bot @slash_command(name="starboard", sub_cmd_name="list", sub_cmd_description="List all starboards") - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _list(self, ctx: InteractionContext) -> None: starboards = Starboard.objects(guild=ctx.guild.id) if starboards != []: @@ -49,29 +49,29 @@ class StarboardCog(Scale): @slash_option( name="channel", description="Starboard channel", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _create(self, ctx: InteractionContext, channel: GuildText) -> None: if channel not in ctx.guild.channels: await ctx.send( "Channel not in guild. Choose an existing channel.", - hidden=True, + ephemeral=True, ) return if not isinstance(channel, GuildText): - await ctx.send("Channel must be a GuildText", hidden=True) + await ctx.send("Channel must be a GuildText", ephemeral=True) return exists = Starboard.objects(channel=channel.id, guild=ctx.guild.id).first() if exists: - await ctx.send(f"Starboard already exists at {channel.mention}.", hidden=True) + await ctx.send(f"Starboard already exists at {channel.mention}.", ephemeral=True) return count = Starboard.objects(guild=ctx.guild.id).count() if count >= 25: - await ctx.send("25 starboard limit reached", hidden=True) + await ctx.send("25 starboard limit reached", ephemeral=True) return _ = Starboard( @@ -87,33 +87,33 @@ class StarboardCog(Scale): @slash_option( name="channel", description="Starboard channel", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _delete(self, ctx: InteractionContext, channel: GuildText) -> None: deleted = Starboard.objects(channel=channel.id, guild=ctx.guild.id).delete() if deleted: _ = Star.objects(starboard=channel.id).delete() - await ctx.send(f"Starboard deleted from {channel.mention}.", hidden=True) + await ctx.send(f"Starboard deleted from {channel.mention}.", ephemeral=True) else: - await ctx.send(f"Starboard not found in {channel.mention}.", hidden=True) + await ctx.send(f"Starboard not found in {channel.mention}.", ephemeral=True) - @context_menu(name="Star Message", target=CommandTypes.MESSAGE) + @context_menu(name="Star Message", context_type=CommandTypes.MESSAGE) async def _star_message(self, ctx: InteractionContext) -> None: await self._star_add.invoke(ctx, ctx.target_message) @slash_command(name="star", sub_cmd_name="add", description="Star a message") @slash_option( - name="message", description="Message to star", option_type=OptionTypes.STRING, required=True + name="message", description="Message to star", opt_type=OptionTypes.STRING, required=True ) @slash_option( name="channel", description="Channel that has the message, not required if used in same channel", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=False, ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _star_add( self, ctx: InteractionContext, @@ -124,7 +124,7 @@ class StarboardCog(Scale): channel = ctx.channel starboards = Starboard.objects(guild=ctx.guild.id) if not starboards: - await ctx.send("No starboards exist.", hidden=True) + await ctx.send("No starboards exist.", ephemeral=True) return await ctx.defer() @@ -135,7 +135,7 @@ class StarboardCog(Scale): message = await channel.get_message(int(message)) if not message: - await ctx.send("Message not found", hidden=True) + await ctx.send("Message not found", ephemeral=True) return channel_list = [] @@ -174,7 +174,7 @@ class StarboardCog(Scale): if exists: await ctx.send( f"Message already sent to Starboard {starboard.mention}", - hidden=True, + ephemeral=True, ) return @@ -229,15 +229,15 @@ class StarboardCog(Scale): @slash_command(name="star", sub_cmd_name="delete", description="Delete a starred message") @slash_option( - name="message", description="Star to delete", option_type=OptionTypes.INTEGER, required=True + name="message", description="Star to delete", opt_type=OptionTypes.INTEGER, required=True ) @slash_option( name="starboard", description="Starboard to delete star from", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _star_delete( self, ctx: InteractionContext, @@ -245,13 +245,13 @@ class StarboardCog(Scale): starboard: GuildText, ) -> None: if not isinstance(starboard, GuildText): - await ctx.send("Channel must be a GuildText channel", hidden=True) + await ctx.send("Channel must be a GuildText channel", ephemeral=True) return exists = Starboard.objects(channel=starboard.id, guild=ctx.guild.id).first() if not exists: await ctx.send( f"Starboard does not exist in {starboard.mention}. Please create it first", - hidden=True, + ephemeral=True, ) return @@ -262,7 +262,7 @@ class StarboardCog(Scale): active=True, ).first() if not star: - await ctx.send(f"No star exists with id {id}", hidden=True) + await ctx.send(f"No star exists with id {id}", ephemeral=True) return message = await starboard.fetch_message(star.star) @@ -277,5 +277,4 @@ class StarboardCog(Scale): def setup(bot: Snake) -> None: """Add StarboardCog to J.A.R.V.I.S.""" - bot.add_cog(StarboardCog(bot)) - bot.add_cog(StarboardCog(bot)) + StarboardCog(bot) diff --git a/jarvis/cogs/twitter.py b/jarvis/cogs/twitter.py index db40aac..33ed8e6 100644 --- a/jarvis/cogs/twitter.py +++ b/jarvis/cogs/twitter.py @@ -1,12 +1,9 @@ """J.A.R.V.I.S. Twitter Cog.""" import asyncio -import logging import tweepy from bson import ObjectId from dis_snek import InteractionContext, Permissions, Scale, Snake -from dis_snek.ext.tasks.task import Task -from dis_snek.ext.tasks.triggers import IntervalTrigger from dis_snek.models.discord.channel import GuildText from dis_snek.models.discord.components import ActionRow, Select, SelectOption from dis_snek.models.snek.application_commands import ( @@ -15,13 +12,12 @@ from dis_snek.models.snek.application_commands import ( slash_command, slash_option, ) +from dis_snek.models.snek.command import check from jarvis.config import get_config from jarvis.db.models import Twitter from jarvis.utils.permissions import admin_or_permissions -logger = logging.getLogger("discord") - class TwitterCog(Scale): """J.A.R.V.I.S. Twitter Cog.""" @@ -33,102 +29,59 @@ class TwitterCog(Scale): config.twitter["consumer_key"], config.twitter["consumer_secret"] ) self.api = tweepy.API(auth) - self._tweets.start() self._guild_cache = {} self._channel_cache = {} - @Task.create(trigger=IntervalTrigger(minutes=1)) - async def _tweets(self) -> None: - twitters = Twitter.objects(active=True) - handles = Twitter.objects.distinct("handle") - twitter_data = {} - for handle in handles: - try: - data = await asyncio.to_thread(self.api.user_timeline, screen_name=handle) - twitter_data[handle] = data - except Exception as e: - logger.error(f"Error with fetching: {e}") - for twitter in twitters: - try: - tweets = list( - filter(lambda x: x.id > twitter.last_tweet, twitter_data[twitter.handle]) - ) - if tweets: - guild_id = twitter.guild - channel_id = twitter.channel - tweets = sorted(tweets, key=lambda x: x.id) - if guild_id not in self._guild_cache: - self._guild_cache[guild_id] = await self.bot.get_guild(guild_id) - guild = self._guild_cache[twitter.guild] - if channel_id not in self._channel_cache: - self._channel_cache[channel_id] = await guild.fetch_channel(channel_id) - channel = self._channel_cache[channel_id] - for tweet in tweets: - retweet = "retweeted_status" in tweet.__dict__ - if retweet and not twitter.retweets: - continue - timestamp = int(tweet.created_at.timestamp()) - url = f"https://twitter.com/{twitter.handle}/status/{tweet.id}" - verb = "re" if retweet else "" - await channel.send( - f"`@{twitter.handle}` {verb}tweeted this at : {url}" - ) - newest = max(tweets, key=lambda x: x.id) - twitter.last_tweet = newest.id - twitter.save() - except Exception as e: - logger.error(f"Error with tweets: {e}") - @slash_command(name="twitter", sub_cmd_name="follow", description="Follow a Twitter acount") @slash_option( - name="handle", description="Twitter account", option_type=OptionTypes.STRING, required=True + name="handle", description="Twitter account", opt_type=OptionTypes.STRING, required=True ) @slash_option( name="channel", description="Channel to post tweets to", - option_type=OptionTypes.CHANNEL, + opt_type=OptionTypes.CHANNEL, required=True, ) @slash_option( name="retweets", description="Mirror re-tweets?", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=False, choices=[ SlashCommandChoice(name="Yes", value="Yes"), SlashCommandChoice(name="No", value="No"), ], ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _twitter_follow( self, ctx: InteractionContext, handle: str, channel: GuildText, retweets: str = "Yes" ) -> None: handle = handle.lower() retweets = retweets == "Yes" if len(handle) > 15: - await ctx.send("Invalid Twitter handle", hidden=True) + await ctx.send("Invalid Twitter handle", ephemeral=True) return if not isinstance(channel, GuildText): - await ctx.send("Channel must be a text channel", hidden=True) + await ctx.send("Channel must be a text channel", ephemeral=True) return try: latest_tweet = await asyncio.to_thread(self.api.user_timeline, screen_name=handle)[0] except Exception: await ctx.send( - "Unable to get user timeline. Are you sure the handle is correct?", hidden=True + "Unable to get user timeline. Are you sure the handle is correct?", ephemeral=True ) return count = Twitter.objects(guild=ctx.guild.id).count() if count >= 12: - await ctx.send("Cannot follow more than 12 Twitter accounts", hidden=True) + await ctx.send("Cannot follow more than 12 Twitter accounts", ephemeral=True) return exists = Twitter.objects(handle=handle, guild=ctx.guild.id) if exists: - await ctx.send("Twitter handle already being followed in this guild", hidden=True) + await ctx.send("Twitter handle already being followed in this guild", ephemeral=True) return t = Twitter( @@ -145,11 +98,11 @@ class TwitterCog(Scale): await ctx.send(f"Now following `@{handle}` in {channel.mention}") @slash_command(name="twitter", sub_cmd_name="unfollow", description="Unfollow Twitter accounts") - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _twitter_unfollow(self, ctx: InteractionContext) -> None: twitters = Twitter.objects(guild=ctx.guild.id) if not twitters: - await ctx.send("You need to follow a Twitter account first", hidden=True) + await ctx.send("You need to follow a Twitter account first", ephemeral=True) return options = [] @@ -198,19 +151,19 @@ class TwitterCog(Scale): @slash_option( name="retweets", description="Mirror re-tweets?", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=False, choices=[ SlashCommandChoice(name="Yes", value="Yes"), SlashCommandChoice(name="No", value="No"), ], ) - @admin_or_permissions(Permissions.MANAGE_GUILD) + @check(admin_or_permissions(Permissions.MANAGE_GUILD)) async def _twitter_modify(self, ctx: InteractionContext, retweets: str) -> None: retweets = retweets == "Yes" twitters = Twitter.objects(guild=ctx.guild.id) if not twitters: - await ctx.send("You need to follow a Twitter account first", hidden=True) + await ctx.send("You need to follow a Twitter account first", ephemeral=True) return options = [] @@ -265,4 +218,4 @@ class TwitterCog(Scale): def setup(bot: Snake) -> None: """Add TwitterCog to J.A.R.V.I.S.""" - bot.add_cog(TwitterCog(bot)) + TwitterCog(bot) diff --git a/jarvis/cogs/util.py b/jarvis/cogs/util.py index eb829bc..0d18689 100644 --- a/jarvis/cogs/util.py +++ b/jarvis/cogs/util.py @@ -6,7 +6,8 @@ from io import BytesIO import numpy as np from dis_snek import InteractionContext, Scale, Snake, const -from dis_snek.models.discord.embed import Color, EmbedField +from dis_snek.models.discord.channel import GuildCategory, GuildText, GuildVoice +from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.file import File from dis_snek.models.discord.guild import Guild from dis_snek.models.discord.role import Role @@ -41,7 +42,7 @@ class UtilCog(Scale): self.bot = bot self.config = get_config() - @slash_command(name="Status", description="Retrieve J.A.R.V.I.S. status") + @slash_command(name="status", description="Retrieve J.A.R.V.I.S. status") @cooldown(bucket=Buckets.CHANNEL, rate=1, interval=30) async def _status(self, ctx: InteractionContext) -> None: title = "J.A.R.V.I.S. Status" @@ -49,7 +50,7 @@ class UtilCog(Scale): color = "#3498db" fields = [] - fields.append(EmbedField(name="discord.py", value=const.__version__)) + fields.append(EmbedField(name="dis-snek", value=const.__version__)) fields.append(EmbedField(name="Version", value=jarvis.__version__, inline=False)) fields.append(EmbedField(name="Git Hash", value=get_repo_hash()[:7], inline=False)) embed = build_embed(title=title, description=desc, fields=fields, color=color) @@ -64,7 +65,7 @@ class UtilCog(Scale): with BytesIO() as image_bytes: JARVIS_LOGO.save(image_bytes, "PNG") image_bytes.seek(0) - logo = File(image_bytes, filename="logo.png") + logo = File(image_bytes, file_name="logo.png") await ctx.send(file=logo) @slash_command(name="rchk", description="Robot Camo HK416") @@ -78,13 +79,13 @@ class UtilCog(Scale): @slash_option( name="text", description="Text to camo-ify", - option_type=OptionTypes.STRING, + opt_type=OptionTypes.STRING, required=True, ) async def _rcauto(self, ctx: InteractionContext, text: str) -> None: to_send = "" if len(text) == 1 and not re.match(r"^[A-Z0-9-()$@!?^'#. ]$", text.upper()): - await ctx.send("Please use ASCII characters.", hidden=True) + await ctx.send("Please use ASCII characters.", ephemeral=True) return for letter in text.upper(): if letter == " ": @@ -96,7 +97,7 @@ class UtilCog(Scale): else: to_send += f"<:{names[id]}:{id}>" if len(to_send) > 2000: - await ctx.send("Too long.", hidden=True) + await ctx.send("Too long.", ephemeral=True) else: await ctx.send(to_send) @@ -104,7 +105,7 @@ class UtilCog(Scale): @slash_option( name="user", description="User to view avatar of", - option_type=OptionTypes.USER, + opt_type=OptionTypes.USER, required=False, ) @cooldown(bucket=Buckets.USER, rate=1, interval=5) @@ -112,7 +113,7 @@ class UtilCog(Scale): if not user: user = ctx.author - avatar = user.display_avatar + avatar = user.display_avatar.url embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE") embed.set_image(url=avatar) embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=avatar) @@ -125,25 +126,25 @@ class UtilCog(Scale): @slash_option( name="role", description="Role to get info of", - option_type=OptionTypes.ROLE, + opt_type=OptionTypes.ROLE, required=True, ) async def _roleinfo(self, ctx: InteractionContext, role: Role) -> None: fields = [ - EmbedField(name="ID", value=role.id), - EmbedField(name="Name", value=role.name), - EmbedField(name="Color", value=str(role.color)), - EmbedField(name="Mention", value=f"`{role.mention}`"), - EmbedField(name="Hoisted", value="Yes" if role.hoist else "No"), - EmbedField(name="Position", value=str(role.position)), - EmbedField(name="Mentionable", value="Yes" if role.mentionable else "No"), - EmbedField(name="Member Count", value=role.members), + EmbedField(name="ID", value=str(role.id), inline=True), + EmbedField(name="Name", value=role.name, inline=True), + EmbedField(name="Color", value=str(role.color.hex), inline=True), + EmbedField(name="Mention", value=f"`{role.mention}`", inline=True), + EmbedField(name="Hoisted", value="Yes" if role.hoist else "No", inline=True), + EmbedField(name="Position", value=str(role.position), inline=True), + EmbedField(name="Mentionable", value="Yes" if role.mentionable else "No", inline=True), + EmbedField(name="Member Count", value=str(len(role.members)), inline=True), ] embed = build_embed( title="", description="", fields=fields, - color=Color.from_hex(role.color), + color=role.color, timestamp=role.created_at, ) embed.set_footer(text="Role Created") @@ -154,14 +155,14 @@ class UtilCog(Scale): fill = a > 0 - data[..., :-1][fill.T] = list(role.color.to_rgb()) + data[..., :-1][fill.T] = list(role.color.rgb) im = Image.fromarray(data) with BytesIO() as image_bytes: im.save(image_bytes, "PNG") image_bytes.seek(0) - color_show = File(image_bytes, filename="color_show.png") + color_show = File(image_bytes, file_name="color_show.png") await ctx.send(embed=embed, file=color_show) @@ -172,7 +173,7 @@ class UtilCog(Scale): @slash_option( name="user", description="User to get info of", - option_type=OptionTypes.USER, + opt_type=OptionTypes.USER, required=False, ) async def _userinfo(self, ctx: InteractionContext, user: User = None) -> None: @@ -181,15 +182,15 @@ class UtilCog(Scale): user_roles = user.roles if user_roles: user_roles = sorted(user.roles, key=lambda x: -x.position) - _ = user_roles.pop(-1) + fields = [ EmbedField( name="Joined", - value=user.joined_at.strftime("%a, %b %-d, %Y %-I:%M %p"), + value=user.joined_at.strftime("%a, %b %#d, %Y %#I:%M %p"), ), EmbedField( name="Registered", - value=user.created_at.strftime("%a, %b %-d, %Y %-I:%M %p"), + value=user.created_at.strftime("%a, %b %#d, %Y %#I:%M %p"), ), EmbedField( name=f"Roles [{len(user_roles)}]", @@ -202,13 +203,13 @@ class UtilCog(Scale): title="", description=user.mention, fields=fields, - color=Color.from_hex(str(user_roles[0].color) if user_roles else "#3498db"), + color=str(user_roles[0].color) if user_roles else "#3498db", ) embed.set_author( - name=f"{user.display_name}#{user.discriminator}", icon_url=user.display_avatar + name=f"{user.display_name}#{user.discriminator}", icon_url=user.display_avatar.url ) - embed.set_thumbnail(url=user.display_avatar) + embed.set_thumbnail(url=user.display_avatar.url) embed.set_footer(text=f"ID: {user.id}") await ctx.send(embed=embed) @@ -217,34 +218,35 @@ class UtilCog(Scale): async def _server_info(self, ctx: InteractionContext) -> None: guild: Guild = ctx.guild - owner = ( - f"{guild.owner.display_name}#{guild.owner.discriminator}" - if guild.owner - else "||`[redacted]`||" - ) + owner = await guild.get_owner() - categories = len(guild.categories) - text_channels = len(guild.text_channels) - voice_channels = len(guild.voice_channels) + owner = f"{owner.username}#{owner.discriminator}" if owner else "||`[redacted]`||" + + categories = len([x for x in guild.channels if isinstance(x, GuildCategory)]) + text_channels = len([x for x in guild.channels if isinstance(x, GuildText)]) + voice_channels = len([x for x in guild.channels if isinstance(x, GuildVoice)]) + threads = len(guild.threads) members = guild.member_count roles = len(guild.roles) - role_list = ", ".join(role.name for role in guild.roles) + role_list = sorted(guild.roles, key=lambda x: x.position, reverse=True) + role_list = ", ".join(role.mention for role in role_list) fields = [ - EmbedField(name="Owner", value=owner), - EmbedField(name="Channel Categories", value=categories), - EmbedField(name="Text Channels", value=text_channels), - EmbedField(name="Voice Channels", value=voice_channels), - EmbedField(name="Members", value=members), - EmbedField(name="Roles", value=roles), + EmbedField(name="Owner", value=owner, inline=True), + EmbedField(name="Channel Categories", value=str(categories), inline=True), + EmbedField(name="Text Channels", value=str(text_channels), inline=True), + EmbedField(name="Voice Channels", value=str(voice_channels), inline=True), + EmbedField(name="Threads", value=str(threads), inline=True), + EmbedField(name="Members", value=str(members), inline=True), + EmbedField(name="Roles", value=str(roles), inline=True), ] if len(role_list) < 1024: fields.append(EmbedField(name="Role List", value=role_list, inline=False)) embed = build_embed(title="", description="", fields=fields, timestamp=guild.created_at) - embed.set_author(name=guild.name, icon_url=guild.icon_url) - embed.set_thumbnail(url=guild.icon_url) + embed.set_author(name=guild.name, icon_url=guild.icon.url) + embed.set_thumbnail(url=guild.icon.url) embed.set_footer(text=f"ID: {guild.id} | Server Created") await ctx.send(embed=embed) @@ -258,13 +260,13 @@ class UtilCog(Scale): @slash_option( name="length", description="Password length (default 32)", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, ) @slash_option( name="chars", description="Characters to include (default last option)", - option_type=OptionTypes.INTEGER, + opt_type=OptionTypes.INTEGER, required=False, choices=[ SlashCommandChoice(name="A-Za-z", value=0), @@ -276,7 +278,7 @@ class UtilCog(Scale): @cooldown(bucket=Buckets.USER, rate=1, interval=15) async def _pw_gen(self, ctx: InteractionContext, length: int = 32, chars: int = 3) -> None: if length > 256: - await ctx.send("Please limit password to 256 characters", hidden=True) + await ctx.send("Please limit password to 256 characters", ephemeral=True) return choices = [ string.ascii_letters, @@ -290,12 +292,12 @@ class UtilCog(Scale): f"Generated password:\n`{pw}`\n\n" '**WARNING: Once you press "Dismiss Message", ' "*the password is lost forever***", - hidden=True, + ephemeral=True, ) @slash_command(name="pigpen", description="Encode a string into pigpen") @slash_option( - name="text", description="Text to encode", option_type=OptionTypes.STRING, required=True + name="text", description="Text to encode", opt_type=OptionTypes.STRING, required=True ) async def _pigpen(self, ctx: InteractionContext, text: str) -> None: outp = "`" @@ -314,4 +316,4 @@ class UtilCog(Scale): def setup(bot: Snake) -> None: """Add UtilCog to J.A.R.V.I.S.""" - bot.add_cog(UtilCog(bot)) + UtilCog(bot) diff --git a/jarvis/cogs/verify.py b/jarvis/cogs/verify.py index 9c2af3e..28e3b89 100644 --- a/jarvis/cogs/verify.py +++ b/jarvis/cogs/verify.py @@ -89,4 +89,4 @@ class VerifyCog(Scale): def setup(bot: Snake) -> None: """Add VerifyCog to J.A.R.V.I.S.""" - bot.add_cog(VerifyCog(bot)) + VerifyCog(bot)