Fix common issues in cogs (ephemeral, opt_type, check)

This commit is contained in:
Zeva Rose 2022-02-04 09:53:06 -07:00
parent fa4785f073
commit 88d596cad7
22 changed files with 310 additions and 396 deletions

View file

@ -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"]

View file

@ -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(

View file

@ -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(
@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(
@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(

View file

@ -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()

View file

@ -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

View file

@ -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(

View file

@ -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} <emote>",
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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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 <t:{timestamp}:f>: {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)

View file

@ -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)

View file

@ -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)