"""J.A.R.V.I.S. Settings Management Cog.""" import logging from typing import Any from dis_snek import InteractionContext, Scale, Snake from dis_snek.models.discord.channel import GuildText from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.enums import Permissions from dis_snek.models.discord.role import Role from dis_snek.models.snek.application_commands import ( OptionTypes, SlashCommand, slash_option, ) from dis_snek.models.snek.command import check from jarvis_core.db import q from jarvis_core.db.models import Setting from jarvis.utils import build_embed from jarvis.utils.permissions import admin_or_permissions class SettingsCog(Scale): """J.A.R.V.I.S. Settings Management Cog.""" def __init__(self, bot: Snake): 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: 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: 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") @slash_option( name="role", description="Verified role", opt_type=OptionTypes.ROLE, required=True ) @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 `massmention` 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"]: value = await ctx.guild.fetch_role(value) 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(value) if value: value += "\n" + nvalue.mention else: value += "\n||`[redacted]`||" fields.append(EmbedField(name=setting.setting, value=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: async for setting in Setting.find(q(guild=ctx.guild.id)): await setting.delete() await ctx.send("Guild settings cleared") def setup(bot: Snake) -> None: """Add SettingsCog to J.A.R.V.I.S.""" SettingsCog(bot)