jarvis-bot/jarvis/cogs/admin/roleping.py
2021-08-06 20:24:50 -06:00

336 lines
12 KiB
Python

"""J.A.R.V.I.S. RolepingCog."""
from datetime import datetime
from datetime import timedelta
from ButtonPaginator import Paginator
from discord import Member
from discord import Role
from discord.ext.commands import Bot
from discord_slash import cog_ext
from discord_slash import SlashContext
from discord_slash.model import ButtonStyle
from discord_slash.utils.manage_commands import create_option
from jarvis.db.models 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):
"""J.A.R.V.I.S. RolepingCog."""
def __init__(self, bot: 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) -> 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)
return
_ = Roleping(
role=role.id,
guild=ctx.guild.id,
admin=ctx.author.id,
active=True,
bypass={"roles": [], "users": []},
).save()
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) -> None:
roleping = Roleping.objects(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) -> None:
exists = self.check_cache(ctx)
if exists:
await ctx.defer(hidden=True)
await ctx.send(
f"Please use existing interaction: {exists['paginator']._message.jump_url}",
hidden=True,
)
return
rolepings = Roleping.objects(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) -> 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)
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 via {matching_role[0].mention}",
hidden=True,
)
return
roleping.bypass["users"].append(user.id)
roleping.save()
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) -> 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)
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.save()
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) -> 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)
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.save()
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) -> 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)
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.save()
await ctx.send(f"{role.name} role bypass added for `{rping.name}`")