287 lines
12 KiB
Python
287 lines
12 KiB
Python
"""JARVIS Settings Management Cog."""
|
|
import asyncio
|
|
import logging
|
|
from typing import Any
|
|
|
|
from jarvis_core.db import q
|
|
from jarvis_core.db.models import Setting
|
|
from naff import Client, Cog, InteractionContext
|
|
from naff.models.discord.channel import GuildText
|
|
from naff.models.discord.components import ActionRow, Button, ButtonStyles
|
|
from naff.models.discord.embed import EmbedField
|
|
from naff.models.discord.enums import Permissions
|
|
from naff.models.discord.role import Role
|
|
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 SettingsCog(Cog):
|
|
"""JARVIS Settings Management Cog."""
|
|
|
|
def __init__(self, bot: Client):
|
|
self.bot = bot
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
async def update_settings(self, setting: str, value: Any, guild: int) -> bool:
|
|
"""Update a guild setting."""
|
|
existing = await Setting.find_one(q(setting=setting, guild=guild))
|
|
if not existing:
|
|
existing = Setting(setting=setting, guild=guild, value=value)
|
|
existing.value = value
|
|
updated = await existing.commit()
|
|
|
|
return updated is not None
|
|
|
|
async def delete_settings(self, setting: str, guild: int) -> bool:
|
|
"""Delete a guild setting."""
|
|
existing = await Setting.find_one(q(setting=setting, guild=guild))
|
|
if existing:
|
|
return await existing.delete()
|
|
return False
|
|
|
|
settings = SlashCommand(name="settings", description="Control guild settings")
|
|
set_ = settings.group(name="set", description="Set a setting")
|
|
unset = settings.group(name="unset", description="Unset a setting")
|
|
|
|
@set_.subcommand(
|
|
sub_cmd_name="modlog",
|
|
sub_cmd_description="Set Moglod channel",
|
|
)
|
|
@slash_option(
|
|
name="channel", description="ModLog Channel", opt_type=OptionTypes.CHANNEL, required=True
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_modlog(self, ctx: InteractionContext, channel: GuildText) -> None:
|
|
if not isinstance(channel, GuildText):
|
|
await ctx.send("Channel must be a GuildText", ephemeral=True)
|
|
return
|
|
await self.update_settings("modlog", channel.id, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. New modlog channel is {channel.mention}")
|
|
|
|
@set_.subcommand(
|
|
sub_cmd_name="activitylog",
|
|
sub_cmd_description="Set Activitylog channel",
|
|
)
|
|
@slash_option(
|
|
name="channel",
|
|
description="Activitylog Channel",
|
|
opt_type=OptionTypes.CHANNEL,
|
|
required=True,
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_activitylog(self, ctx: InteractionContext, channel: GuildText) -> None:
|
|
if not isinstance(channel, GuildText):
|
|
await ctx.send("Channel must be a GuildText", ephemeral=True)
|
|
return
|
|
await self.update_settings("activitylog", channel.id, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. New activitylog channel is {channel.mention}")
|
|
|
|
@set_.subcommand(sub_cmd_name="massmention", sub_cmd_description="Set massmention output")
|
|
@slash_option(
|
|
name="amount",
|
|
description="Amount of mentions (0 to disable)",
|
|
opt_type=OptionTypes.INTEGER,
|
|
required=True,
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_massmention(self, ctx: InteractionContext, amount: int) -> None:
|
|
await ctx.defer()
|
|
await self.update_settings("massmention", amount, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. New massmention limit is {amount}")
|
|
|
|
@set_.subcommand(sub_cmd_name="verified", sub_cmd_description="Set verified role")
|
|
@slash_option(
|
|
name="role", description="Verified role", opt_type=OptionTypes.ROLE, required=True
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_verified(self, ctx: InteractionContext, role: Role) -> None:
|
|
if role.id == ctx.guild.id:
|
|
await ctx.send("Cannot set verified to `@everyone`", ephemeral=True)
|
|
return
|
|
if role.bot_managed or not role.is_assignable:
|
|
await ctx.send(
|
|
"Cannot assign this role, try lowering it below my role or using a different role",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
await ctx.defer()
|
|
await self.update_settings("verified", role.id, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. New verified role is `{role.name}`")
|
|
|
|
@set_.subcommand(sub_cmd_name="unverified", sub_cmd_description="Set unverified role")
|
|
@slash_option(
|
|
name="role", description="Unverified role", opt_type=OptionTypes.ROLE, required=True
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_unverified(self, ctx: InteractionContext, role: Role) -> None:
|
|
if role.id == ctx.guild.id:
|
|
await ctx.send("Cannot set unverified to `@everyone`", ephemeral=True)
|
|
return
|
|
if role.bot_managed or not role.is_assignable:
|
|
await ctx.send(
|
|
"Cannot assign this role, try lowering it below my role or using a different role",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
await ctx.defer()
|
|
await self.update_settings("unverified", role.id, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. New unverified role is `{role.name}`")
|
|
|
|
@set_.subcommand(
|
|
sub_cmd_name="noinvite", sub_cmd_description="Set if invite deletion should happen"
|
|
)
|
|
@slash_option(name="active", description="Active?", opt_type=OptionTypes.BOOLEAN, required=True)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_invitedel(self, ctx: InteractionContext, active: bool) -> None:
|
|
await ctx.defer()
|
|
await self.update_settings("noinvite", active, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. Automatic invite active: {active}")
|
|
|
|
@set_.subcommand(sub_cmd_name="notify", sub_cmd_description="Notify users of admin action?")
|
|
@slash_option(name="active", description="Notify?", opt_type=OptionTypes.BOOLEAN, required=True)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _set_notify(self, ctx: InteractionContext, active: bool) -> None:
|
|
await ctx.defer()
|
|
await self.update_settings("notify", active, ctx.guild.id)
|
|
await ctx.send(f"Settings applied. Notifications active: {active}")
|
|
|
|
# Unset
|
|
@unset.subcommand(
|
|
sub_cmd_name="modlog",
|
|
sub_cmd_description="Unset Modlog channel",
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_modlog(self, ctx: InteractionContext) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("modlog", ctx.guild.id)
|
|
await ctx.send("Setting `modlog` unset")
|
|
|
|
@unset.subcommand(
|
|
sub_cmd_name="activitylog",
|
|
sub_cmd_description="Unset Activitylog channel",
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_activitylog(self, ctx: InteractionContext) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("activitylog", ctx.guild.id)
|
|
await ctx.send("Setting `activitylog` unset")
|
|
|
|
@unset.subcommand(sub_cmd_name="massmention", sub_cmd_description="Unset massmention output")
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_massmention(self, ctx: InteractionContext) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("massmention", ctx.guild.id)
|
|
await ctx.send("Setting `massmention` unset")
|
|
|
|
@unset.subcommand(sub_cmd_name="verified", sub_cmd_description="Unset verified role")
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_verified(self, ctx: InteractionContext) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("verified", ctx.guild.id)
|
|
await ctx.send("Setting `verified` unset")
|
|
|
|
@unset.subcommand(sub_cmd_name="unverified", sub_cmd_description="Unset unverified role")
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_unverified(self, ctx: InteractionContext) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("unverified", ctx.guild.id)
|
|
await ctx.send("Setting `unverified` unset")
|
|
|
|
@unset.subcommand(
|
|
sub_cmd_name="noinvite", sub_cmd_description="Unset if invite deletion should happen"
|
|
)
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_invitedel(self, ctx: InteractionContext, active: bool) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("noinvite", ctx.guild.id)
|
|
await ctx.send(f"Setting `{active}` unset")
|
|
|
|
@unset.subcommand(sub_cmd_name="notify", sub_cmd_description="Unset admin action notifications")
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _unset_notify(self, ctx: InteractionContext) -> None:
|
|
await ctx.defer()
|
|
await self.delete_settings("notify", ctx.guild.id)
|
|
await ctx.send("Setting `notify` unset")
|
|
|
|
@settings.subcommand(sub_cmd_name="view", sub_cmd_description="View settings")
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _view(self, ctx: InteractionContext) -> None:
|
|
settings = Setting.find(q(guild=ctx.guild.id))
|
|
|
|
fields = []
|
|
async for setting in settings:
|
|
value = setting.value
|
|
if setting.setting in ["unverified", "verified", "mute"]:
|
|
try:
|
|
value = await ctx.guild.fetch_role(value)
|
|
except KeyError:
|
|
await setting.delete()
|
|
value = None
|
|
if value:
|
|
value = value.mention
|
|
else:
|
|
value = "||`[redacted]`||"
|
|
elif setting.setting in ["activitylog", "modlog"]:
|
|
value = await ctx.guild.fetch_channel(value)
|
|
if value:
|
|
value = value.mention
|
|
else:
|
|
value = "||`[redacted]`||"
|
|
elif setting.setting == "rolegiver":
|
|
value = ""
|
|
for _role in setting.value:
|
|
nvalue = await ctx.guild.fetch_role(_role)
|
|
if nvalue:
|
|
value += "\n" + nvalue.mention
|
|
else:
|
|
value += "\n||`[redacted]`||"
|
|
fields.append(EmbedField(name=setting.setting, value=str(value) or "N/A", inline=False))
|
|
|
|
embed = build_embed(title="Current Settings", description="", fields=fields)
|
|
|
|
await ctx.send(embed=embed)
|
|
|
|
@settings.subcommand(sub_cmd_name="clear", sub_cmd_description="Clear all settings")
|
|
@check(admin_or_permissions(Permissions.MANAGE_GUILD))
|
|
async def _clear(self, ctx: InteractionContext) -> None:
|
|
components = [
|
|
ActionRow(
|
|
Button(style=ButtonStyles.RED, emoji="✖️", custom_id="no"),
|
|
Button(style=ButtonStyles.GREEN, emoji="✔️", custom_id="yes"),
|
|
)
|
|
]
|
|
message = await ctx.send("***Are you sure?***", components=components)
|
|
try:
|
|
context = await self.bot.wait_for_component(
|
|
check=lambda x: ctx.author.id == x.context.author.id,
|
|
messages=message,
|
|
timeout=60 * 5,
|
|
)
|
|
content = "***Are you sure?***"
|
|
if context.context.custom_id == "yes":
|
|
async for setting in Setting.find(q(guild=ctx.guild.id)):
|
|
await setting.delete()
|
|
content = "Guild settings cleared"
|
|
else:
|
|
content = "Guild settings not cleared"
|
|
for row in components:
|
|
for component in row.components:
|
|
component.disabled = True
|
|
await context.context.edit_origin(content=content, components=components)
|
|
except asyncio.TimeoutError:
|
|
for row in components:
|
|
for component in row.components:
|
|
component.disabled = True
|
|
await message.edit(content="Guild settings not cleared", components=components)
|
|
|
|
|
|
def setup(bot: Client) -> None:
|
|
"""Add SettingsCog to JARVIS"""
|
|
SettingsCog(bot)
|