274 lines
10 KiB
Python
274 lines
10 KiB
Python
"""JARVIS RolepingCog."""
|
|
import logging
|
|
|
|
from jarvis_core.db import q
|
|
from jarvis_core.db.models import Roleping
|
|
from naff import Client, Cog, InteractionContext, Permissions
|
|
from naff.client.utils.misc_utils import find_all
|
|
from naff.ext.paginators import Paginator
|
|
from naff.models.discord.embed import EmbedField
|
|
from naff.models.discord.role import Role
|
|
from naff.models.discord.user import Member
|
|
from naff.models.naff.application_commands import (
|
|
OptionTypes,
|
|
SlashCommand,
|
|
slash_option,
|
|
)
|
|
from naff.models.naff.command import check
|
|
|
|
from jarvis.utils import build_embed
|
|
from jarvis.utils.permissions import admin_or_permissions
|
|
|
|
|
|
class RolepingCog(Cog):
|
|
"""JARVIS RolepingCog."""
|
|
|
|
def __init__(self, bot: Client):
|
|
self.bot = bot
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
roleping = SlashCommand(
|
|
name="roleping", description="Set up warnings for pinging specific roles"
|
|
)
|
|
|
|
@roleping.subcommand(
|
|
sub_cmd_name="add",
|
|
sub_cmd_description="Add a role to roleping",
|
|
)
|
|
@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 = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
|
|
if roleping:
|
|
await ctx.send(f"Role `{role.name}` already in roleping.", ephemeral=True)
|
|
return
|
|
|
|
if role.id == ctx.guild.id:
|
|
await ctx.send("Cannot add `@everyone` to roleping", ephemeral=True)
|
|
return
|
|
|
|
_ = await Roleping(
|
|
role=role.id,
|
|
guild=ctx.guild.id,
|
|
admin=ctx.author.id,
|
|
active=True,
|
|
bypass={"roles": [], "users": []},
|
|
).commit()
|
|
await ctx.send(f"Role `{role.name}` added to roleping.")
|
|
|
|
@roleping.subcommand(sub_cmd_name="remove", sub_cmd_description="Remove a role")
|
|
@slash_option(
|
|
name="role", description="Role to remove", opt_type=OptionTypes.ROLE, required=True
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _roleping_remove(self, ctx: InteractionContext, role: Role) -> None:
|
|
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
|
|
if not roleping:
|
|
await ctx.send("Roleping does not exist", ephemeral=True)
|
|
return
|
|
|
|
try:
|
|
await roleping.delete()
|
|
except Exception:
|
|
self.logger.debug("Ignoring deletion error")
|
|
await ctx.send(f"Role `{role.name}` removed from roleping.")
|
|
|
|
@roleping.subcommand(sub_cmd_name="list", sub_cmd_description="Lick all blocklisted roles")
|
|
async def _roleping_list(self, ctx: InteractionContext) -> None:
|
|
|
|
rolepings = await Roleping.find(q(guild=ctx.guild.id)).to_list(None)
|
|
if not rolepings:
|
|
await ctx.send("No rolepings configured", ephemeral=True)
|
|
return
|
|
|
|
embeds = []
|
|
for roleping in rolepings:
|
|
role = await ctx.guild.fetch_role(roleping.role)
|
|
if not role:
|
|
await roleping.delete()
|
|
continue
|
|
broles = find_all(lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles)
|
|
bypass_roles = [r.mention or "||`[redacted]`||" for r in broles]
|
|
bypass_users = [
|
|
(await ctx.guild.fetch_member(u)).mention or "||`[redacted]`||"
|
|
for u in roleping.bypass["users"]
|
|
]
|
|
bypass_roles = bypass_roles or ["None"]
|
|
bypass_users = bypass_users or ["None"]
|
|
embed = build_embed(
|
|
title="Roleping",
|
|
description=role.mention,
|
|
color=str(role.color),
|
|
fields=[
|
|
EmbedField(
|
|
name="Created At",
|
|
value=roleping.created_at.strftime("%a, %b %d, %Y %I:%M %p"),
|
|
inline=False,
|
|
),
|
|
# EmbedField(name="Active", value=str(roleping.active), inline=True),
|
|
EmbedField(
|
|
name="Bypass Users",
|
|
value="\n".join(bypass_users),
|
|
inline=True,
|
|
),
|
|
EmbedField(
|
|
name="Bypass Roles",
|
|
value="\n".join(bypass_roles),
|
|
inline=True,
|
|
),
|
|
],
|
|
)
|
|
|
|
admin = await ctx.guild.fetch_member(roleping.admin)
|
|
if not admin:
|
|
admin = self.bot.user
|
|
|
|
embed.set_author(name=admin.display_name, icon_url=admin.display_avatar.url)
|
|
embed.set_footer(text=f"{admin.username}#{admin.discriminator} | {admin.id}")
|
|
|
|
embeds.append(embed)
|
|
|
|
paginator = Paginator.create_from_embeds(self.bot, *embeds, timeout=300)
|
|
|
|
await paginator.send(ctx)
|
|
|
|
bypass = roleping.group(
|
|
name="bypass", description="Allow specific users/roles to ping rolepings"
|
|
)
|
|
|
|
@bypass.subcommand(
|
|
sub_cmd_name="user",
|
|
sub_cmd_description="Add a user as a bypass to a roleping",
|
|
)
|
|
@slash_option(
|
|
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
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _roleping_bypass_user(
|
|
self, ctx: InteractionContext, bypass: Member, role: Role
|
|
) -> None:
|
|
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
|
|
if not roleping:
|
|
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
|
|
return
|
|
|
|
if bypass.id in roleping.bypass["users"]:
|
|
await ctx.send(f"{bypass.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",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
matching_role = list(filter(lambda x: x.id in roleping.bypass["roles"], bypass.roles))
|
|
|
|
if matching_role:
|
|
await ctx.send(
|
|
f"{bypass.mention} already has bypass via {matching_role[0].mention}",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
roleping.bypass["users"].append(bypass.id)
|
|
await roleping.commit()
|
|
await ctx.send(f"{bypass.display_name} user bypass added for `{role.name}`")
|
|
|
|
@bypass.subcommand(
|
|
sub_cmd_name="role",
|
|
sub_cmd_description="Add a role as a bypass to roleping",
|
|
)
|
|
@slash_option(
|
|
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
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _roleping_bypass_role(
|
|
self, ctx: InteractionContext, bypass: Role, role: Role
|
|
) -> None:
|
|
if bypass.id == ctx.guild.id:
|
|
await ctx.send("Cannot add `@everyone` as a bypass", ephemeral=True)
|
|
return
|
|
roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
|
|
if not roleping:
|
|
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
|
|
return
|
|
|
|
if bypass.id in roleping.bypass["roles"]:
|
|
await ctx.send(f"{bypass.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",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
roleping.bypass["roles"].append(bypass.id)
|
|
await roleping.commit()
|
|
await ctx.send(f"{bypass.name} role bypass added for `{role.name}`")
|
|
|
|
restore = roleping.group(name="restore", description="Remove a roleping bypass")
|
|
|
|
@restore.subcommand(
|
|
sub_cmd_name="user",
|
|
sub_cmd_description="Remove a bypass from a roleping (restoring it)",
|
|
)
|
|
@slash_option(
|
|
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
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _roleping_restore_user(
|
|
self, ctx: InteractionContext, bypass: Member, role: Role
|
|
) -> None:
|
|
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
|
|
if not roleping:
|
|
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
|
|
return
|
|
|
|
if bypass.id not in roleping.bypass.users:
|
|
await ctx.send(f"{bypass.mention} not in bypass", ephemeral=True)
|
|
return
|
|
|
|
roleping.bypass.users.remove(bypass.id)
|
|
await roleping.commit()
|
|
await ctx.send(f"{bypass.display_name} user bypass removed for `{role.name}`")
|
|
|
|
@restore.subcommand(
|
|
sub_cmd_name="role",
|
|
sub_cmd_description="Remove a bypass from a roleping (restoring it)",
|
|
)
|
|
@slash_option(
|
|
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
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _roleping_restore_role(
|
|
self, ctx: InteractionContext, bypass: Role, role: Role
|
|
) -> None:
|
|
roleping: Roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
|
|
if not roleping:
|
|
await ctx.send(f"Roleping not configured for {role.mention}", ephemeral=True)
|
|
return
|
|
|
|
if bypass.id not in roleping.bypass.roles:
|
|
await ctx.send(f"{bypass.mention} not in bypass", ephemeral=True)
|
|
return
|
|
|
|
roleping.bypass.roles.remove(bypass.id)
|
|
await roleping.commit()
|
|
await ctx.send(f"{bypass.display_name} user bypass removed for `{role.name}`")
|