Reorganize commands for future opt-in structure

This commit is contained in:
Zeva Rose 2023-01-01 19:05:20 -07:00
parent 0a096e4831
commit fe3ef1ad35
24 changed files with 143 additions and 278 deletions

View file

@ -0,0 +1,11 @@
"""JARVIS Core Cogs."""
from naff import Client
from jarvis.cogs.core import admin, botutil, socials
def setup(bot: Client) -> None:
"""Add core cogs to JARVIS"""
admin.setup(bot)
botutil.setup(bot)
socials.setup(bot)

View file

@ -3,7 +3,8 @@ import logging
from naff import Client from naff import Client
from jarvis.cogs.admin import ( from jarvis.cogs.core.admin import (
autoreact,
ban, ban,
filters, filters,
kick, kick,
@ -13,6 +14,9 @@ from jarvis.cogs.admin import (
mute, mute,
purge, purge,
roleping, roleping,
settings,
temprole,
verify,
warning, warning,
) )
@ -21,8 +25,12 @@ def setup(bot: Client) -> None:
"""Add admin cogs to JARVIS""" """Add admin cogs to JARVIS"""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
msg = "Loaded jarvis.cogs.admin.{}" msg = "Loaded jarvis.cogs.admin.{}"
autoreact.AutoReactCog(bot)
logger.debug(msg.format("autoreact"))
ban.BanCog(bot) ban.BanCog(bot)
logger.debug(msg.format("ban")) logger.debug(msg.format("ban"))
filters.FilterCog(bot)
logger.debug(msg.format("filters"))
kick.KickCog(bot) kick.KickCog(bot)
logger.debug(msg.format("kick")) logger.debug(msg.format("kick"))
lock.LockCog(bot) lock.LockCog(bot)
@ -37,7 +45,11 @@ def setup(bot: Client) -> None:
logger.debug(msg.format("purge")) logger.debug(msg.format("purge"))
roleping.RolepingCog(bot) roleping.RolepingCog(bot)
logger.debug(msg.format("roleping")) logger.debug(msg.format("roleping"))
settings.SettingsCog(bot)
logger.debug(msg.format("settings"))
temprole.TemproleCog(bot)
logger.debug(msg.format("temprole"))
verify.VerifyCog(bot)
logger.debug(msg.format("verify"))
warning.WarningCog(bot) warning.WarningCog(bot)
logger.debug(msg.format("warning")) logger.debug(msg.format("warning"))
filters.FilterCog(bot)
logger.debug(msg.format("filters"))

View file

@ -84,12 +84,8 @@ class AutoReactCog(Extension):
opt_type=OptionTypes.CHANNEL, opt_type=OptionTypes.CHANNEL,
required=True, required=True,
) )
@slash_option( @slash_option(name="thread", description="Create a thread?", opt_type=OptionTypes.BOOLEAN, required=False)
name="thread", description="Create a thread?", opt_type=OptionTypes.BOOLEAN, required=False @slash_option(name="emote", description="Emote to add", opt_type=OptionTypes.STRING, required=False)
)
@slash_option(
name="emote", description="Emote to add", opt_type=OptionTypes.STRING, required=False
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _autoreact_add( async def _autoreact_add(
self, ctx: InteractionContext, channel: GuildText, thread: bool = True, emote: str = None self, ctx: InteractionContext, channel: GuildText, thread: bool = True, emote: str = None
@ -152,9 +148,7 @@ class AutoReactCog(Extension):
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _autoreact_remove( async def _autoreact_remove(self, ctx: InteractionContext, channel: GuildText, emote: str) -> None:
self, ctx: InteractionContext, channel: GuildText, emote: str
) -> None:
autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id)) autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id))
if not autoreact: if not autoreact:
await ctx.send( await ctx.send(
@ -216,9 +210,7 @@ class AutoReactCog(Extension):
return return
message = "" message = ""
if len(exists.reactions) > 0: if len(exists.reactions) > 0:
message = f"Current active autoreacts on {channel.mention}:\n" + "\n".join( message = f"Current active autoreacts on {channel.mention}:\n" + "\n".join(exists.reactions)
exists.reactions
)
else: else:
message = f"No reactions set on {channel.mention}" message = f"No reactions set on {channel.mention}"
await ctx.send(message) await ctx.send(message)

View file

@ -163,6 +163,12 @@ class BanCog(ModcaseCog):
if mtype == "temp": if mtype == "temp":
user_message += f"\nDuration: {duration} hours" user_message += f"\nDuration: {duration} hours"
if btype != "temp":
duration = None
active = True
if btype == "soft":
active = False
user_embed = ban_embed( user_embed = ban_embed(
user=user, user=user,
admin=ctx.author, admin=ctx.author,
@ -186,12 +192,6 @@ class BanCog(ModcaseCog):
if mtype == "soft": if mtype == "soft":
await ctx.guild.unban(user, reason="Ban was softban") await ctx.guild.unban(user, reason="Ban was softban")
if btype != "temp":
duration = None
active = True
if btype == "soft":
active = False
@slash_command(name="unban", description="Unban a user") @slash_command(name="unban", description="Unban a user")
@slash_option(name="user", description="User to unban", opt_type=OptionTypes.STRING, required=True) @slash_option(name="user", description="User to unban", opt_type=OptionTypes.STRING, required=True)
@slash_option(name="reason", description="Unban reason", opt_type=OptionTypes.STRING, required=True) @slash_option(name="reason", description="Unban reason", opt_type=OptionTypes.STRING, required=True)

View file

@ -82,9 +82,7 @@ class FilterCog(Extension):
filter_ = SlashCommand(name="filter", description="Manage keyword filters") filter_ = SlashCommand(name="filter", description="Manage keyword filters")
@filter_.subcommand(sub_cmd_name="create", sub_cmd_description="Create a new filter") @filter_.subcommand(sub_cmd_name="create", sub_cmd_description="Create a new filter")
@slash_option( @slash_option(name="name", description="Name of new filter", required=True, opt_type=OptionTypes.STRING)
name="name", description="Name of new filter", required=True, opt_type=OptionTypes.STRING
)
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _filter_create(self, ctx: InteractionContext, name: str) -> None: async def _filter_create(self, ctx: InteractionContext, name: str) -> None:
return await self._edit_filter(ctx, name) return await self._edit_filter(ctx, name)

View file

@ -19,9 +19,7 @@ class KickCog(ModcaseCog):
@slash_command(name="kick", description="Kick a user") @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", opt_type=OptionTypes.USER, required=True)
@slash_option( @slash_option(name="reason", description="Kick reason", opt_type=OptionTypes.STRING, required=True)
name="reason", description="Kick reason", opt_type=OptionTypes.STRING, required=True
)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _kick(self, ctx: InteractionContext, user: User, reason: str) -> None: async def _kick(self, ctx: InteractionContext, user: User, reason: str) -> None:
if not user or user == ctx.author: if not user or user == ctx.author:

View file

@ -19,9 +19,7 @@ from naff.models.naff.command import check
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
async def lock( async def lock(bot: Client, target: GuildChannel, admin: Member, reason: str, duration: int) -> None:
bot: Client, target: GuildChannel, admin: Member, reason: str, duration: int
) -> None:
""" """
Lock an existing channel Lock an existing channel
@ -110,9 +108,7 @@ class LockdownCog(Extension):
sub_cmd_name="start", sub_cmd_name="start",
sub_cmd_description="Lockdown the server", sub_cmd_description="Lockdown the server",
) )
@slash_option( @slash_option(name="reason", description="Lockdown reason", opt_type=OptionTypes.STRING, required=True)
name="reason", description="Lockdown reason", opt_type=OptionTypes.STRING, required=True
)
@slash_option( @slash_option(
name="duration", name="duration",
description="Duration in minutes", description="Duration in minutes",

View file

@ -114,9 +114,7 @@ class CaseCog(Extension):
note_output = f"```ansi\n{note_output}\n{note_output_extra}\n```" note_output = f"```ansi\n{note_output}\n{note_output_extra}\n```"
fields = ( fields = (
EmbedField( EmbedField(name="Actions", value=action_output if mod_case.actions else "No Actions Found"),
name="Actions", value=action_output if mod_case.actions else "No Actions Found"
),
EmbedField(name="Notes", value=note_output if mod_case.notes else "No Notes Found"), EmbedField(name="Notes", value=note_output if mod_case.notes else "No Notes Found"),
) )
@ -196,9 +194,7 @@ class CaseCog(Extension):
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _cases_list( async def _cases_list(self, ctx: InteractionContext, user: Optional[Member] = None, closed: bool = False) -> None:
self, ctx: InteractionContext, user: Optional[Member] = None, closed: bool = False
) -> None:
query = q(guild=ctx.guild.id) query = q(guild=ctx.guild.id)
if not closed: if not closed:
query.update(q(open=True)) query.update(q(open=True))
@ -274,9 +270,7 @@ class CaseCog(Extension):
@case.subcommand(sub_cmd_name="note", sub_cmd_description="Add a note to a specific case") @case.subcommand(sub_cmd_name="note", sub_cmd_description="Add a note to a specific case")
@slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True) @slash_option(name="cid", description="Case ID", opt_type=OptionTypes.STRING, required=True)
@slash_option( @slash_option(name="note", description="Note to add", opt_type=OptionTypes.STRING, required=True)
name="note", description="Note to add", opt_type=OptionTypes.STRING, required=True
)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None: async def _case_note(self, ctx: InteractionContext, cid: str, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid)) case = await Modlog.find_one(q(guild=ctx.guild.id, nanoid=cid))
@ -302,9 +296,7 @@ class CaseCog(Extension):
@case.subcommand(sub_cmd_name="new", sub_cmd_description="Open a new case") @case.subcommand(sub_cmd_name="new", sub_cmd_description="Open a new case")
@slash_option(name="user", description="Target user", opt_type=OptionTypes.USER, required=True) @slash_option(name="user", description="Target user", opt_type=OptionTypes.USER, required=True)
@slash_option( @slash_option(name="note", description="Note to add", opt_type=OptionTypes.STRING, required=True)
name="note", description="Note to add", opt_type=OptionTypes.STRING, required=True
)
@check(admin_or_permissions(Permissions.BAN_MEMBERS)) @check(admin_or_permissions(Permissions.BAN_MEMBERS))
async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None: async def _case_new(self, ctx: InteractionContext, user: Member, note: str) -> None:
case = await Modlog.find_one(q(guild=ctx.guild.id, user=user.id, open=True)) case = await Modlog.find_one(q(guild=ctx.guild.id, user=user.id, open=True))
@ -322,9 +314,7 @@ class CaseCog(Extension):
note = Note(admin=ctx.author.id, content=note) note = Note(admin=ctx.author.id, content=note)
case = Modlog( case = Modlog(user=user.id, guild=ctx.guild.id, admin=ctx.author.id, notes=[note], actions=[])
user=user.id, guild=ctx.guild.id, admin=ctx.author.id, notes=[note], actions=[]
)
await case.commit() await case.commit()
await case.reload() await case.reload()

View file

@ -27,9 +27,7 @@ from jarvis.utils.permissions import admin_or_permissions
class MuteCog(ModcaseCog): class MuteCog(ModcaseCog):
"""JARVIS MuteCog.""" """JARVIS MuteCog."""
async def _apply_timeout( async def _apply_timeout(self, ctx: InteractionContext, user: Member, reason: str, until: datetime) -> None:
self, ctx: InteractionContext, user: Member, reason: str, until: datetime
) -> None:
await user.timeout(communication_disabled_until=until, reason=reason) await user.timeout(communication_disabled_until=until, reason=reason)
duration = int((until - datetime.now(tz=timezone.utc)).seconds / 60) duration = int((until - datetime.now(tz=timezone.utc)).seconds / 60)
await Mute( await Mute(
@ -44,11 +42,7 @@ class MuteCog(ModcaseCog):
return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild) return mute_embed(user=user, admin=ctx.author, reason=reason, guild=ctx.guild)
@context_menu(name="Mute User", context_type=CommandTypes.USER) @context_menu(name="Mute User", context_type=CommandTypes.USER)
@check( @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS))
admin_or_permissions(
Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS
)
)
async def _timeout_cm(self, ctx: InteractionContext) -> None: async def _timeout_cm(self, ctx: InteractionContext) -> None:
modal = Modal( modal = Modal(
title=f"Muting {ctx.target.mention}", title=f"Muting {ctx.target.mention}",
@ -82,9 +76,7 @@ class MuteCog(ModcaseCog):
"RETURN_AS_TIMEZONE_AWARE": True, "RETURN_AS_TIMEZONE_AWARE": True,
} }
rt_settings = base_settings.copy() rt_settings = base_settings.copy()
rt_settings["PARSERS"] = [ rt_settings["PARSERS"] = [x for x in default_parsers if x not in ["absolute-time", "timestamp"]]
x for x in default_parsers if x not in ["absolute-time", "timestamp"]
]
rt_until = parse(until, settings=rt_settings) rt_until = parse(until, settings=rt_settings)
@ -99,14 +91,10 @@ class MuteCog(ModcaseCog):
until = at_until until = at_until
else: else:
self.logger.debug(f"Failed to parse delay: {until}") self.logger.debug(f"Failed to parse delay: {until}")
await response.send( await response.send(f"`{until}` is not a parsable date, please try again", ephemeral=True)
f"`{until}` is not a parsable date, please try again", ephemeral=True
)
return return
if until < datetime.now(tz=timezone.utc): if until < datetime.now(tz=timezone.utc):
await response.send( await response.send(f"`{old_until}` is in the past, which isn't allowed", ephemeral=True)
f"`{old_until}` is in the past, which isn't allowed", ephemeral=True
)
return return
try: try:
embed = await self._apply_timeout(ctx, ctx.target, reason, until) embed = await self._apply_timeout(ctx, ctx.target, reason, until)
@ -140,11 +128,7 @@ class MuteCog(ModcaseCog):
SlashCommandChoice(name="Week(s)", value=10080), SlashCommandChoice(name="Week(s)", value=10080),
], ],
) )
@check( @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS))
admin_or_permissions(
Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS
)
)
async def _timeout( async def _timeout(
self, ctx: InteractionContext, user: Member, reason: str, time: int = 1, scale: int = 60 self, ctx: InteractionContext, user: Member, reason: str, time: int = 1, scale: int = 60
) -> None: ) -> None:
@ -175,22 +159,13 @@ class MuteCog(ModcaseCog):
await ctx.send("Unable to mute this user", ephemeral=True) await ctx.send("Unable to mute this user", ephemeral=True)
@slash_command(name="unmute", description="Unmute a user") @slash_command(name="unmute", description="Unmute a user")
@slash_option( @slash_option(name="user", description="User to unmute", opt_type=OptionTypes.USER, required=True)
name="user", description="User to unmute", opt_type=OptionTypes.USER, required=True @slash_option(name="reason", description="Reason for unmute", opt_type=OptionTypes.STRING, required=True)
) @check(admin_or_permissions(Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS))
@slash_option(
name="reason", description="Reason for unmute", opt_type=OptionTypes.STRING, required=True
)
@check(
admin_or_permissions(
Permissions.MUTE_MEMBERS, Permissions.BAN_MEMBERS, Permissions.KICK_MEMBERS
)
)
async def _unmute(self, ctx: InteractionContext, user: Member, reason: str) -> None: async def _unmute(self, ctx: InteractionContext, user: Member, reason: str) -> None:
if ( if (
not user.communication_disabled_until not user.communication_disabled_until
or user.communication_disabled_until.timestamp() or user.communication_disabled_until.timestamp() < datetime.now(tz=timezone.utc).timestamp() # noqa: W503
< datetime.now(tz=timezone.utc).timestamp() # noqa: W503
): ):
await ctx.send("User is not muted", ephemeral=True) await ctx.send("User is not muted", ephemeral=True)
return return

View file

@ -47,9 +47,7 @@ class PurgeCog(Extension):
count=amount, count=amount,
).commit() ).commit()
@slash_command( @slash_command(name="autopurge", sub_cmd_name="add", sub_cmd_description="Automatically purge messages")
name="autopurge", sub_cmd_name="add", sub_cmd_description="Automatically purge messages"
)
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to autopurge", description="Channel to autopurge",
@ -63,9 +61,7 @@ class PurgeCog(Extension):
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _autopurge_add( async def _autopurge_add(self, ctx: InteractionContext, channel: GuildText, delay: int = 30) -> None:
self, ctx: InteractionContext, channel: GuildText, delay: int = 30
) -> None:
if not isinstance(channel, GuildText): if not isinstance(channel, GuildText):
await ctx.send("Channel must be a GuildText channel", ephemeral=True) await ctx.send("Channel must be a GuildText channel", ephemeral=True)
return return
@ -90,9 +86,7 @@ class PurgeCog(Extension):
await ctx.send(f"Autopurge set up on {channel.mention}, delay is {delay} seconds") await ctx.send(f"Autopurge set up on {channel.mention}, delay is {delay} seconds")
@slash_command( @slash_command(name="autopurge", sub_cmd_name="remove", sub_cmd_description="Remove an autopurge")
name="autopurge", sub_cmd_name="remove", sub_cmd_description="Remove an autopurge"
)
@slash_option( @slash_option(
name="channel", name="channel",
description="Channel to remove from autopurge", description="Channel to remove from autopurge",
@ -126,9 +120,7 @@ class PurgeCog(Extension):
required=True, required=True,
) )
@check(admin_or_permissions(Permissions.MANAGE_MESSAGES)) @check(admin_or_permissions(Permissions.MANAGE_MESSAGES))
async def _autopurge_update( async def _autopurge_update(self, ctx: InteractionContext, channel: GuildText, delay: int) -> None:
self, ctx: InteractionContext, channel: GuildText, delay: int
) -> None:
autopurge = await Autopurge.find_one(q(guild=ctx.guild.id, channel=channel.id)) autopurge = await Autopurge.find_one(q(guild=ctx.guild.id, channel=channel.id))
if not autopurge: if not autopurge:
await ctx.send("Autopurge does not exist.", ephemeral=True) await ctx.send("Autopurge does not exist.", ephemeral=True)

View file

@ -27,9 +27,7 @@ class RolepingCog(Extension):
self.bot = bot self.bot = bot
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
roleping = SlashCommand( roleping = SlashCommand(name="roleping", description="Set up warnings for pinging specific roles")
name="roleping", description="Set up warnings for pinging specific roles"
)
@roleping.subcommand( @roleping.subcommand(
sub_cmd_name="add", sub_cmd_name="add",
@ -57,9 +55,7 @@ class RolepingCog(Extension):
await ctx.send(f"Role `{role.name}` added to roleping.") await ctx.send(f"Role `{role.name}` added to roleping.")
@roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role") @roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role")
@slash_option( @slash_option(name="role", description="Role to remove", opt_type=OptionTypes.ROLE, required=True)
name="role", description="Role to remove", opt_type=OptionTypes.ROLE, required=True
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None: async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
@ -87,11 +83,10 @@ class RolepingCog(Extension):
if not role: if not role:
await roleping.delete() await roleping.delete()
continue continue
broles = find_all(lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles) broles = find_all(lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles) # noqa: B023
bypass_roles = [r.mention or "||`[redacted]`||" for r in broles] bypass_roles = [r.mention or "||`[redacted]`||" for r in broles]
bypass_users = [ bypass_users = [
(await ctx.guild.fetch_member(u)).mention or "||`[redacted]`||" (await ctx.guild.fetch_member(u)).mention or "||`[redacted]`||" for u in roleping.bypass["users"]
for u in roleping.bypass["users"]
] ]
bypass_roles = bypass_roles or ["None"] bypass_roles = bypass_roles or ["None"]
bypass_users = bypass_users or ["None"] bypass_users = bypass_users or ["None"]
@ -132,24 +127,16 @@ class RolepingCog(Extension):
await paginator.send(ctx) await paginator.send(ctx)
bypass = roleping.group( bypass = roleping.group(name="bypass", description="Allow specific users/roles to ping rolepings")
name="bypass", description="Allow specific users/roles to ping rolepings"
)
@bypass.subcommand( @bypass.subcommand(
sub_cmd_name="user", sub_cmd_name="user",
sub_cmd_description="Add a user as a bypass to a roleping", sub_cmd_description="Add a user as a bypass to a roleping",
) )
@slash_option( @slash_option(name="bypass", description="User to add", opt_type=OptionTypes.USER, required=True)
name="bypass", description="User to add", opt_type=OptionTypes.USER, required=True @slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True)
)
@slash_option(
name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_user( async def _roleping_bypass_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None:
self, ctx: InteractionContext, bypass: Member, role: Role
) -> None:
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
@ -183,16 +170,10 @@ class RolepingCog(Extension):
sub_cmd_name="role", sub_cmd_name="role",
sub_cmd_description="Add a role as a bypass to roleping", sub_cmd_description="Add a role as a bypass to roleping",
) )
@slash_option( @slash_option(name="bypass", description="Role to add", opt_type=OptionTypes.ROLE, required=True)
name="bypass", description="Role to add", opt_type=OptionTypes.ROLE, required=True @slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True)
)
@slash_option(
name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_role( async def _roleping_bypass_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None:
self, ctx: InteractionContext, bypass: Role, role: Role
) -> None:
if bypass.id == ctx.guild.id: if bypass.id == ctx.guild.id:
await ctx.send("Cannot add `@everyone` as a bypass", ephemeral=True) await ctx.send("Cannot add `@everyone` as a bypass", ephemeral=True)
return return
@ -207,8 +188,7 @@ class RolepingCog(Extension):
if len(roleping.bypass["roles"]) == 10: if len(roleping.bypass["roles"]) == 10:
await ctx.send( await ctx.send(
"Already have 10 roles in bypass. " "Already have 10 roles in bypass. " "Please consider consolidating roles for roleping bypass",
"Please consider consolidating roles for roleping bypass",
ephemeral=True, ephemeral=True,
) )
return return
@ -223,16 +203,10 @@ class RolepingCog(Extension):
sub_cmd_name="user", sub_cmd_name="user",
sub_cmd_description="Remove a bypass from a roleping (restoring it)", sub_cmd_description="Remove a bypass from a roleping (restoring it)",
) )
@slash_option( @slash_option(name="bypass", description="User to remove", opt_type=OptionTypes.USER, required=True)
name="bypass", description="User to remove", opt_type=OptionTypes.USER, required=True @slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True)
)
@slash_option(
name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_restore_user( async def _roleping_restore_user(self, ctx: InteractionContext, bypass: Member, role: Role) -> None:
self, ctx: InteractionContext, bypass: Member, role: Role
) -> None:
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
@ -250,16 +224,10 @@ class RolepingCog(Extension):
sub_cmd_name="role", sub_cmd_name="role",
sub_cmd_description="Remove a bypass from a roleping (restoring it)", sub_cmd_description="Remove a bypass from a roleping (restoring it)",
) )
@slash_option( @slash_option(name="bypass", description="Role to remove", opt_type=OptionTypes.ROLE, required=True)
name="bypass", description="Role to remove", opt_type=OptionTypes.ROLE, required=True @slash_option(name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True)
)
@slash_option(
name="role", description="Rolepinged role", opt_type=OptionTypes.ROLE, required=True
)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_restore_role( async def _roleping_restore_role(self, ctx: InteractionContext, bypass: Role, role: Role) -> None:
self, ctx: InteractionContext, bypass: Role, role: Role
) -> None:
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id)) roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)

View file

@ -30,12 +30,8 @@ class TemproleCog(Extension):
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
@slash_command(name="temprole", description="Give a user a temporary role") @slash_command(name="temprole", description="Give a user a temporary role")
@slash_option( @slash_option(name="user", description="User to grant role", opt_type=OptionTypes.USER, required=True)
name="user", description="User to grant role", opt_type=OptionTypes.USER, required=True @slash_option(name="role", description="Role to grant", opt_type=OptionTypes.ROLE, required=True)
)
@slash_option(
name="role", description="Role to grant", opt_type=OptionTypes.ROLE, required=True
)
@slash_option( @slash_option(
name="duration", name="duration",
description="Duration of temp role (i.e. 2 hours)", description="Duration of temp role (i.e. 2 hours)",
@ -74,9 +70,7 @@ class TemproleCog(Extension):
"RETURN_AS_TIMEZONE_AWARE": True, "RETURN_AS_TIMEZONE_AWARE": True,
} }
rt_settings = base_settings.copy() rt_settings = base_settings.copy()
rt_settings["PARSERS"] = [ rt_settings["PARSERS"] = [x for x in default_parsers if x not in ["absolute-time", "timestamp"]]
x for x in default_parsers if x not in ["absolute-time", "timestamp"]
]
rt_duration = parse(duration, settings=rt_settings) rt_duration = parse(duration, settings=rt_settings)
@ -94,9 +88,7 @@ class TemproleCog(Extension):
return return
if duration < datetime.now(tz=timezone.utc): if duration < datetime.now(tz=timezone.utc):
await ctx.send( await ctx.send(f"`{duration}` is in the past. Past durations aren't allowed", ephemeral=True)
f"`{duration}` is in the past. Past durations aren't allowed", ephemeral=True
)
return return
await user.add_role(role, reason=reason) await user.add_role(role, reason=reason)
@ -116,15 +108,6 @@ class TemproleCog(Extension):
description=f"Role temporarily granted to {user.mention}", description=f"Role temporarily granted to {user.mention}",
fields=fields, fields=fields,
) )
embed.set_author( embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=user.display_avatar.url)
name=f"{user.username}#{user.discriminator}", icon_url=user.display_avatar.url components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
)
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
def setup(bot: Client) -> None:
"""Add TemproleCog to JARVIS"""
TemproleCog(bot)

View file

@ -85,9 +85,7 @@ class VerifyCog(Extension):
role = await ctx.guild.fetch_role(setting.value) role = await ctx.guild.fetch_role(setting.value)
await ctx.author.remove_role(role, reason="Verification passed") await ctx.author.remove_role(role, reason="Verification passed")
except AttributeError: except AttributeError:
self.logger.warning( self.logger.warning("Unverified role deleted before verification finished")
"Unverified role deleted before verification finished"
)
await response.context.edit_origin( await response.context.edit_origin(
content=f"Welcome, {ctx.author.mention}. Please enjoy your stay.", content=f"Welcome, {ctx.author.mention}. Please enjoy your stay.",
@ -97,10 +95,7 @@ class VerifyCog(Extension):
self.logger.debug(f"User {ctx.author.id} verified successfully") self.logger.debug(f"User {ctx.author.id} verified successfully")
else: else:
await response.context.edit_origin( await response.context.edit_origin(
content=( content=(f"{ctx.author.mention}, incorrect. " "Please press the button that says `YES`")
f"{ctx.author.mention}, incorrect. "
"Please press the button that says `YES`"
)
) )
except asyncio.TimeoutError: except asyncio.TimeoutError:
await message.delete(delay=2) await message.delete(delay=2)

View file

@ -39,9 +39,7 @@ class WarningCog(ModcaseCog):
required=False, required=False,
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _warn( async def _warn(self, ctx: InteractionContext, user: Member, reason: str, duration: int = 24) -> None:
self, ctx: InteractionContext, user: Member, reason: str, duration: int = 24
) -> None:
if len(reason) > 100: if len(reason) > 100:
await ctx.send("Reason must be < 100 characters", ephemeral=True) await ctx.send("Reason must be < 100 characters", ephemeral=True)
return return
@ -122,9 +120,7 @@ class WarningCog(ModcaseCog):
for i in range(0, len(fields), 5): for i in range(0, len(fields), 5):
embed = build_embed( embed = build_embed(
title="Warnings", title="Warnings",
description=( description=(f"{len(warnings)} total | {len(active_warns)} currently active"),
f"{len(warnings)} total | {len(active_warns)} currently active"
),
fields=fields[i : i + 5], fields=fields[i : i + 5],
) )
embed.set_author( embed.set_author(
@ -153,9 +149,7 @@ class WarningCog(ModcaseCog):
description=(f"{len(warnings)} total | {len(active_warns)} currently active"), description=(f"{len(warnings)} total | {len(active_warns)} currently active"),
fields=fields[i : i + 5], fields=fields[i : i + 5],
) )
embed.set_author( embed.set_author(name=user.username + "#" + user.discriminator, icon_url=user.display_avatar.url)
name=user.username + "#" + user.discriminator, icon_url=user.display_avatar.url
)
embed.set_thumbnail(url=ctx.guild.icon.url) embed.set_thumbnail(url=ctx.guild.icon.url)
pages.append(embed) pages.append(embed)

View file

@ -84,9 +84,7 @@ class BotutilCog(Extension):
) )
embed = build_embed(title="System Info", description="", fields=fields) embed = build_embed(title="System Info", description="", fields=fields)
embed.set_image(url=self.bot.user.avatar.url) embed.set_image(url=self.bot.user.avatar.url)
components = Button( components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
await ctx.send(embeds=embed, components=components) await ctx.send(embeds=embed, components=components)
@prefixed_command(name="update") @prefixed_command(name="update")
@ -113,16 +111,12 @@ class BotutilCog(Extension):
if changed: if changed:
fields.append(EmbedField(name="Changed Modules", value=f"```\n{changed}\n```")) fields.append(EmbedField(name="Changed Modules", value=f"```\n{changed}\n```"))
embed = build_embed( embed = build_embed("Update Status", description="Updates have been applied", fields=fields)
"Update Status", description="Updates have been applied", fields=fields
)
embed.set_thumbnail(url="https://dev.zevaryx.com/git.png") embed.set_thumbnail(url="https://dev.zevaryx.com/git.png")
self.logger.info("Updates applied") self.logger.info("Updates applied")
content = f"```ansi\n{capture.get()}\n```" content = f"```ansi\n{capture.get()}\n```"
components = Button( components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
if len(content) < 3000: if len(content) < 3000:
await ctx.reply(content, embeds=embed, components=components) await ctx.reply(content, embeds=embed, components=components)
else: else:
@ -135,9 +129,7 @@ class BotutilCog(Extension):
else: else:
embed = build_embed(title="Update Status", description="No changes applied", fields=[]) embed = build_embed(title="Update Status", description="No changes applied", fields=[])
embed.set_thumbnail(url="https://dev.zevaryx.com/git.png") embed.set_thumbnail(url="https://dev.zevaryx.com/git.png")
components = Button( components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
await ctx.reply(embeds=embed, components=components) await ctx.reply(embeds=embed, components=components)

View file

@ -0,0 +1,11 @@
"""JARVIS Social Cogs."""
from naff import Client
from jarvis.cogs.core.socials import reddit, twitter
def setup(bot: Client) -> None:
"""Add social cogs to JARVIS"""
reddit.RedditCog(bot)
twitter.TwitterCog(bot)

View file

@ -0,0 +1,11 @@
"""JARVIS guild-specific cogs"""
from naff import Client
from jarvis.cogs.unique import ctc2, dbrand, gl
def setup(bot: Client) -> None:
"""Add guild-specific cogs to JARVIS"""
ctc2.setup(bot)
dbrand.setup(bot)
gl.setup(bot)

View file

@ -46,39 +46,25 @@ class CTCCog(Extension):
@ctc2.subcommand(sub_cmd_name="about") @ctc2.subcommand(sub_cmd_name="about")
@cooldown(bucket=Buckets.USER, rate=1, interval=30) @cooldown(bucket=Buckets.USER, rate=1, interval=30)
async def _about(self, ctx: InteractionContext) -> None: async def _about(self, ctx: InteractionContext) -> None:
components = [ components = [ActionRow(Button(style=ButtonStyles.URL, url="https://completethecode.com", label="More Info"))]
ActionRow( await ctx.send("See https://completethecode.com for more information", components=components)
Button(style=ButtonStyles.URL, url="https://completethecode.com", label="More Info")
)
]
await ctx.send(
"See https://completethecode.com for more information", components=components
)
@ctc2.subcommand( @ctc2.subcommand(
sub_cmd_name="pw", sub_cmd_name="pw",
sub_cmd_description="Guess a password for https://completethecodetwo.cards", sub_cmd_description="Guess a password for https://completethecodetwo.cards",
) )
@slash_option( @slash_option(name="guess", description="Guess a password", opt_type=OptionTypes.STRING, required=True)
name="guess", description="Guess a password", opt_type=OptionTypes.STRING, required=True
)
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)
async def _pw(self, ctx: InteractionContext, guess: str) -> None: async def _pw(self, ctx: InteractionContext, guess: str) -> None:
if len(guess) > 800: if len(guess) > 800:
await ctx.send( await ctx.send(
( ("Listen here, dipshit. Don't be like <@256110768724901889>. " "Make your guesses < 800 characters."),
"Listen here, dipshit. Don't be like <@256110768724901889>. "
"Make your guesses < 800 characters."
),
ephemeral=True, ephemeral=True,
) )
return return
elif not valid.fullmatch(guess): elif not valid.fullmatch(guess):
await ctx.send( await ctx.send(
( ("Listen here, dipshit. Don't be like <@256110768724901889>. " "Make your guesses *readable*."),
"Listen here, dipshit. Don't be like <@256110768724901889>. "
"Make your guesses *readable*."
),
ephemeral=True, ephemeral=True,
) )
return return

View file

@ -63,9 +63,7 @@ async def parse_db_status() -> dict:
else: else:
cell = cell.get_text().strip() cell = cell.get_text().strip()
row_data.append(cell) row_data.append(cell)
data[data_key].append( data[data_key].append({headers[idx]: value for idx, value in enumerate(row_data)})
{headers[idx]: value for idx, value in enumerate(row_data)}
)
return data return data
@ -99,9 +97,7 @@ class DbrandCog(Extension):
self.cache["status"] = status self.cache["status"] = status
status = status.get("operations") status = status.get("operations")
emojies = [x["Status"] for x in status] emojies = [x["Status"] for x in status]
fields = [ fields = [EmbedField(name=f'{x["Status"]} {x["Service"]}', value=x["Detail"]) for x in status]
EmbedField(name=f'{x["Status"]} {x["Service"]}', value=x["Detail"]) for x in status
]
color = "#FBBD1E" color = "#FBBD1E"
if all("green" in x for x in emojies): if all("green" in x for x in emojies):
color = "#38F657" color = "#38F657"
@ -192,17 +188,13 @@ class DbrandCog(Extension):
f"[Be (not) extorted]({self.base_url + 'not-extortion'})", f"[Be (not) extorted]({self.base_url + 'not-extortion'})",
"[Robot Camo Wallpapers](https://db.io/wallpapers)", "[Robot Camo Wallpapers](https://db.io/wallpapers)",
] ]
embed = build_embed( embed = build_embed(title="Useful Links", description="\n\n".join(urls), fields=[], color="#FFBB00")
title="Useful Links", description="\n\n".join(urls), fields=[], color="#FFBB00"
)
embed.set_footer( embed.set_footer(
text="dbrand.com", text="dbrand.com",
icon_url="https://dev.zevaryx.com/db_logo.png", icon_url="https://dev.zevaryx.com/db_logo.png",
) )
embed.set_thumbnail(url="https://dev.zevaryx.com/db_logo.png") embed.set_thumbnail(url="https://dev.zevaryx.com/db_logo.png")
embed.set_author( embed.set_author(name="dbrand", url=self.base_url, icon_url="https://dev.zevaryx.com/db_logo.png")
name="dbrand", url=self.base_url, icon_url="https://dev.zevaryx.com/db_logo.png"
)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@db.subcommand( @db.subcommand(
@ -264,15 +256,11 @@ class DbrandCog(Extension):
for service in data["shipping_services_available"]: for service in data["shipping_services_available"]:
service_data = self.cache.get(f"{dest}-{service}") service_data = self.cache.get(f"{dest}-{service}")
if not service_data or service_data["cache_expiry"] < datetime.now(tz=timezone.utc): if not service_data or service_data["cache_expiry"] < datetime.now(tz=timezone.utc):
service_data = await self._session.get( service_data = await self._session.get(self.api_url + dest + "/" + service["url"])
self.api_url + dest + "/" + service["url"]
)
if service_data.status > 400: if service_data.status > 400:
continue continue
service_data = await service_data.json() service_data = await service_data.json()
service_data["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta( service_data["cache_expiry"] = datetime.now(tz=timezone.utc) + timedelta(hours=24)
hours=24
)
self.cache[f"{dest}-{service}"] = service_data self.cache[f"{dest}-{service}"] = service_data
title = f'{service_data["carrier"]} {service_data["tier-title"]} | {service_data["costs-min"]}' title = f'{service_data["carrier"]} {service_data["tier-title"]} | {service_data["costs-min"]}'
message = service_data["time-title"] message = service_data["time-title"]
@ -296,7 +284,9 @@ class DbrandCog(Extension):
description = "" description = ""
color = "#FFBB00" color = "#FFBB00"
if shipping_info: if shipping_info:
description = f'{shipping_info["Status"]}\u200b \u200b {shipping_info["Est. Delivery Time"].split(":")[0]}' description = (
f'{shipping_info["Status"]}\u200b \u200b {shipping_info["Est. Delivery Time"].split(":")[0]}'
)
created = self.cache.get("status").get("cache_expiry") - timedelta(hours=2) created = self.cache.get("status").get("cache_expiry") - timedelta(hours=2)
ts = int(created.timestamp()) ts = int(created.timestamp())
description += f" \u200b | \u200b Last updated: <t:{ts}:R>\n\u200b" description += f" \u200b | \u200b Last updated: <t:{ts}:R>\n\u200b"
@ -326,8 +316,7 @@ class DbrandCog(Extension):
embed = build_embed( embed = build_embed(
title="Check Shipping Times", title="Check Shipping Times",
description=( description=(
"Country not found.\nYou can [view all shipping " "Country not found.\nYou can [view all shipping " "destinations here](https://dbrand.com/shipping)"
"destinations here](https://dbrand.com/shipping)"
), ),
fields=[], fields=[],
url="https://dbrand.com/shipping", url="https://dbrand.com/shipping",

View file

@ -53,9 +53,7 @@ class GitlabCog(Extension):
else: else:
assignee = "None" assignee = "None"
created_at = datetime.strptime(issue.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( created_at = datetime.strptime(issue.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
"%Y-%m-%d %H:%M:%S UTC"
)
labels = issue.labels labels = issue.labels
if labels: if labels:
@ -73,9 +71,7 @@ class GitlabCog(Extension):
color = self.project.labels.get(issue.labels[0]).color color = self.project.labels.get(issue.labels[0]).color
fields.append(EmbedField(name="Created At", value=created_at)) fields.append(EmbedField(name="Created At", value=created_at))
if issue.state == "closed": if issue.state == "closed":
closed_at = datetime.strptime(issue.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( closed_at = datetime.strptime(issue.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
"%Y-%m-%d %H:%M:%S UTC"
)
fields.append(EmbedField(name="Closed At", value=closed_at)) fields.append(EmbedField(name="Closed At", value=closed_at))
if issue.milestone: if issue.milestone:
fields.append( fields.append(
@ -99,18 +95,14 @@ class GitlabCog(Extension):
icon_url=issue.author["avatar_url"], icon_url=issue.author["avatar_url"],
url=issue.author["web_url"], url=issue.author["web_url"],
) )
embed.set_thumbnail( embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png"
)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@gl.subcommand( @gl.subcommand(
sub_cmd_name="milestone", sub_cmd_name="milestone",
sub_cmd_description="Get a milestone from GitLab", sub_cmd_description="Get a milestone from GitLab",
) )
@slash_option( @slash_option(name="id", description="Milestone ID", opt_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: async def _milestone(self, ctx: InteractionContext, id: int) -> None:
try: try:
milestone = self.project.milestones.get(int(id)) milestone = self.project.milestones.get(int(id))
@ -118,9 +110,7 @@ class GitlabCog(Extension):
await ctx.send("Milestone does not exist.", ephemeral=True) await ctx.send("Milestone does not exist.", ephemeral=True)
return return
created_at = datetime.strptime(milestone.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( created_at = datetime.strptime(milestone.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
"%Y-%m-%d %H:%M:%S UTC"
)
fields = [ fields = [
EmbedField( EmbedField(
@ -153,18 +143,14 @@ class GitlabCog(Extension):
url="https://git.zevaryx.com/jarvis", url="https://git.zevaryx.com/jarvis",
icon_url="https://git.zevaryx.com/uploads/-/system/user/avatar/11/avatar.png", icon_url="https://git.zevaryx.com/uploads/-/system/user/avatar/11/avatar.png",
) )
embed.set_thumbnail( embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png"
)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
@gl.subcommand( @gl.subcommand(
sub_cmd_name="mr", sub_cmd_name="mr",
sub_cmd_description="Get a merge request from GitLab", sub_cmd_description="Get a merge request from GitLab",
) )
@slash_option( @slash_option(name="id", description="Merge Request ID", opt_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: async def _mergerequest(self, ctx: InteractionContext, id: int) -> None:
try: try:
mr = self.project.mergerequests.get(int(id)) mr = self.project.mergerequests.get(int(id))
@ -177,9 +163,7 @@ class GitlabCog(Extension):
else: else:
assignee = "None" assignee = "None"
created_at = datetime.strptime(mr.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( created_at = datetime.strptime(mr.created_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
"%Y-%m-%d %H:%M:%S UTC"
)
labels = mr.labels labels = mr.labels
if labels: if labels:
@ -199,14 +183,10 @@ class GitlabCog(Extension):
color = "#00FFEE" color = "#00FFEE"
fields.append(EmbedField(name="Created At", value=created_at, inline=True)) fields.append(EmbedField(name="Created At", value=created_at, inline=True))
if mr.state == "merged": if mr.state == "merged":
merged_at = datetime.strptime(mr.merged_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( merged_at = datetime.strptime(mr.merged_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
"%Y-%m-%d %H:%M:%S UTC"
)
fields.append(EmbedField(name="Merged At", value=merged_at, inline=True)) fields.append(EmbedField(name="Merged At", value=merged_at, inline=True))
elif mr.state == "closed": elif mr.state == "closed":
closed_at = datetime.strptime(mr.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime( closed_at = datetime.strptime(mr.closed_at, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%Y-%m-%d %H:%M:%S UTC")
"%Y-%m-%d %H:%M:%S UTC"
)
fields.append(EmbedField(name="Closed At", value=closed_at, inline=True)) fields.append(EmbedField(name="Closed At", value=closed_at, inline=True))
if mr.milestone: if mr.milestone:
fields.append( fields.append(
@ -230,9 +210,7 @@ class GitlabCog(Extension):
icon_url=mr.author["avatar_url"], icon_url=mr.author["avatar_url"],
url=mr.author["web_url"], url=mr.author["web_url"],
) )
embed.set_thumbnail( embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png"
)
await ctx.send(embeds=embed) await ctx.send(embeds=embed)
def build_embed_page(self, api_list: list, t_state: str, name: str) -> Embed: def build_embed_page(self, api_list: list, t_state: str, name: str) -> Embed:
@ -263,9 +241,7 @@ class GitlabCog(Extension):
url="https://git.zevaryx.com/jarvis", url="https://git.zevaryx.com/jarvis",
icon_url="https://git.zevaryx.com/uploads/-/system/user/avatar/11/avatar.png", icon_url="https://git.zevaryx.com/uploads/-/system/user/avatar/11/avatar.png",
) )
embed.set_thumbnail( embed.set_thumbnail(url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png")
url="https://about.gitlab.com/images/press/logo/png/gitlab-icon-rgb.png"
)
return embed return embed
@gl.subcommand( @gl.subcommand(
@ -370,9 +346,7 @@ class GitlabCog(Extension):
pages = [] pages = []
t_state = t_state[0].upper() + t_state[1:] t_state = t_state[0].upper() + t_state[1:]
for i in range(0, len(merges), 5): for i in range(0, len(merges), 5):
pages.append( pages.append(self.build_embed_page(merges[i : i + 5], t_state=t_state, name="merge request"))
self.build_embed_page(merges[i : i + 5], t_state=t_state, name="merge request")
)
paginator = Paginator.create_from_embeds(self.bot, *pages, timeout=300) paginator = Paginator.create_from_embeds(self.bot, *pages, timeout=300)
@ -407,9 +381,7 @@ class GitlabCog(Extension):
pages = [] pages = []
for i in range(0, len(milestones), 5): for i in range(0, len(milestones), 5):
pages.append( pages.append(self.build_embed_page(milestones[i : i + 5], t_state=None, name="milestone"))
self.build_embed_page(milestones[i : i + 5], t_state=None, name="milestone")
)
paginator = Paginator.create_from_embeds(self.bot, *pages, timeout=300) paginator = Paginator.create_from_embeds(self.bot, *pages, timeout=300)