jarvis-bot/jarvis/cogs/admin/roleping.py

378 lines
12 KiB
Python

from datetime import datetime, timedelta
from ButtonPaginator import Paginator
from discord import Member, Role
from discord.ext import commands
from discord_slash import SlashContext, cog_ext
from discord_slash.model import ButtonStyle
from discord_slash.utils.manage_commands import create_option
from jarvis.db.types import Roleping
from jarvis.utils import build_embed
from jarvis.utils.cachecog import CacheCog
from jarvis.utils.field import Field
from jarvis.utils.permissions import admin_or_permissions
class RolepingCog(CacheCog):
def __init__(self, bot):
super().__init__(bot)
@cog_ext.cog_subcommand(
base="roleping",
name="add",
description="Add a role to roleping",
options=[
create_option(
name="role",
description="Role to add to roleping",
option_type=8,
required=True,
)
],
)
@admin_or_permissions(manage_guild=True)
async def _roleping_add(self, ctx: SlashContext, role: Role):
roleping = Roleping.get(guild=ctx.guild.id, role=role.id)
if not roleping:
roleping = Roleping(
role=role.id,
guild=ctx.guild.id,
admin=ctx.author.id,
active=True,
bypass={"roles": [], "users": []},
)
else:
await ctx.send(
f"Role `{role.name}` already in roleping.", hidden=True
)
return
roleping.insert()
await ctx.send(f"Role `{role.name}` added to roleping.")
@cog_ext.cog_subcommand(
base="roleping",
name="remove",
description="Remove a role from the roleping",
options=[
create_option(
name="role",
description="Role to remove from roleping",
option_type=8,
required=True,
)
],
)
@admin_or_permissions(manage_guild=True)
async def _roleping_remove(self, ctx: SlashContext, role: Role):
roleping = Roleping.get(guild=ctx.guild.id, role=role.id)
if not roleping:
await ctx.send("Roleping does not exist", hidden=True)
return
roleping.delete()
await ctx.send(f"Role `{role.name}` removed from roleping.")
@cog_ext.cog_subcommand(
base="roleping",
name="list",
description="List all blocklisted roles",
)
async def _roleping_list(self, ctx: SlashContext):
exists = self.check_cache(ctx)
if exists:
await ctx.defer(hidden=True)
await ctx.send(
"Please use existing interaction: "
+ f"{exists['paginator']._message.jump_url}",
hidden=True,
)
return
rolepings = Roleping.get_many(guild=ctx.guild.id)
if not rolepings:
await ctx.send("No rolepings configured", hidden=True)
return
embeds = []
for roleping in rolepings:
role = ctx.guild.get_role(roleping.role)
bypass_roles = list(
filter(
lambda x: x.id in roleping.bypass["roles"], ctx.guild.roles
)
)
bypass_roles = [
r.mention or "||`[redacted]`||" for r in bypass_roles
]
bypass_users = [
ctx.guild.get_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=[
Field(
name="Created At",
value=roleping.created_at.strftime(
"%a, %b %d, %Y %I:%M %p"
),
inline=False,
),
Field(name="Active", value=str(roleping.active)),
Field(
name="Bypass Users",
value="\n".join(bypass_users),
),
Field(
name="Bypass Roles",
value="\n".join(bypass_roles),
),
],
)
admin = ctx.guild.get_member(roleping.admin)
if not admin:
admin = self.bot.user
embed.set_author(
name=admin.nick or admin.name, icon_url=admin.avatar_url
)
embed.set_footer(
text=f"{admin.name}#{admin.discriminator} | {admin.id}"
)
embeds.append(embed)
paginator = Paginator(
bot=self.bot,
ctx=ctx,
embeds=embeds,
only=ctx.author,
timeout=60 * 5, # 5 minute timeout
disable_after_timeout=True,
use_extend=len(embeds) > 2,
left_button_style=ButtonStyle.grey,
right_button_style=ButtonStyle.grey,
basic_buttons=["", ""],
)
self.cache[hash(paginator)] = {
"user": ctx.author.id,
"guild": ctx.guild.id,
"timeout": datetime.utcnow() + timedelta(minutes=5),
"command": ctx.subcommand_name,
"paginator": paginator,
}
await paginator.start()
@cog_ext.cog_subcommand(
base="roleping",
subcommand_group="bypass",
name="user",
description="Add a user as a bypass to a roleping",
base_desc="Block roles from being pinged",
sub_group_desc="Allow specific users/roles to ping rolepings",
options=[
create_option(
name="user",
description="User to add",
option_type=6,
required=True,
),
create_option(
name="rping",
description="Rolepinged role",
option_type=8,
required=True,
),
],
)
@admin_or_permissions(manage_guild=True)
async def _roleping_bypass_user(
self, ctx: SlashContext, user: Member, rping: Role
):
roleping = Roleping.get(guild=ctx.guild.id, role=rping.id)
if not roleping:
await ctx.send(
f"Roleping not configured for {rping.mention}", hidden=True
)
return
if user.id in roleping.bypass["users"]:
await ctx.send(f"{user.mention} already in bypass", hidden=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,
)
return
matching_role = list(
filter(lambda x: x.id in roleping.bypass["roles"], user.roles)
)
if matching_role:
await ctx.send(
f"{user.mention} already has bypass "
f"via {matching_role[0].mention}",
hidden=True,
)
return
roleping.bypass["users"].append(user.id)
roleping.update()
await ctx.send(
f"{user.nick or user.name} user bypass added for `{rping.name}`"
)
@cog_ext.cog_subcommand(
base="roleping",
subcommand_group="bypass",
name="role",
description="Add a role as a bypass to a roleping",
base_desc="Block roles from being pinged",
sub_group_desc="Allow specific users/roles to ping rolepings",
options=[
create_option(
name="role",
description="Role to add",
option_type=8,
required=True,
),
create_option(
name="rping",
description="Rolepinged role",
option_type=8,
required=True,
),
],
)
@admin_or_permissions(manage_guild=True)
async def _roleping_bypass_role(
self, ctx: SlashContext, role: Role, rping: Role
):
roleping = Roleping.get(guild=ctx.guild.id, role=rping.id)
if not roleping:
await ctx.send(
f"Roleping not configured for {rping.mention}", hidden=True
)
return
if role.id in roleping.bypass["roles"]:
await ctx.send(f"{role.mention} already in bypass", hidden=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,
)
return
roleping.bypass["roles"].append(role.id)
roleping.update()
await ctx.send(f"{role.name} role bypass added for `{rping.name}`")
@cog_ext.cog_subcommand(
base="roleping",
subcommand_group="restore",
name="user",
description="Remove a role bypass",
base_desc="Block roles from being pinged",
sub_group_desc="Remove a bypass from a roleping (restoring it)",
options=[
create_option(
name="user",
description="User to add",
option_type=6,
required=True,
),
create_option(
name="rping",
description="Rolepinged role",
option_type=8,
required=True,
),
],
)
@admin_or_permissions(manage_guild=True)
async def _roleping_restore_user(
self, ctx: SlashContext, user: Member, rping: Role
):
roleping = Roleping.get(guild=ctx.guild.id, role=rping.id)
if not roleping:
await ctx.send(
f"Roleping not configured for {rping.mention}", hidden=True
)
return
if user.id not in roleping.bypass["users"]:
await ctx.send(f"{user.mention} not in bypass", hidden=True)
return
roleping.bypass["users"].delete(user.id)
roleping.update()
await ctx.send(
f"{user.nick or user.name} user bypass removed for `{rping.name}`"
)
@cog_ext.cog_subcommand(
base="roleping",
subcommand_group="restore",
name="role",
description="Remove a role bypass",
base_desc="Block roles from being pinged",
sub_group_desc="Remove a bypass from a roleping (restoring it)",
options=[
create_option(
name="role",
description="Role to add",
option_type=8,
required=True,
),
create_option(
name="rping",
description="Rolepinged role",
option_type=8,
required=True,
),
],
)
@admin_or_permissions(manage_guild=True)
async def _roleping_restore_role(
self, ctx: SlashContext, role: Role, rping: Role
):
roleping = Roleping.get(guild=ctx.guild.id, role=rping.id)
if not roleping:
await ctx.send(
f"Roleping not configured for {rping.mention}", hidden=True
)
return
if role.id in roleping.bypass["roles"]:
await ctx.send(f"{role.mention} already in bypass", hidden=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,
)
return
roleping.bypass["roles"].append(role.id)
roleping.update()
await ctx.send(f"{role.name} role bypass added for `{rping.name}`")