fix(config): Fix general settings UI.
This commit is contained in:
@@ -80,7 +80,7 @@ class LionGuild(Timezoned):
|
|||||||
return GuildMode.StudyGuild
|
return GuildMode.StudyGuild
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def timezone(self) -> pytz.timezone:
|
def timezone(self) -> str:
|
||||||
return self.config.timezone.value
|
return self.config.timezone.value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -94,11 +94,3 @@ class LionGuild(Timezoned):
|
|||||||
if self.data.name != guild.name:
|
if self.data.name != guild.name:
|
||||||
await self.data.update(name=guild.name)
|
await self.data.update(name=guild.name)
|
||||||
|
|
||||||
async def _event_log(self, ...):
|
|
||||||
...
|
|
||||||
|
|
||||||
def event_log(self, **kwargs):
|
|
||||||
asyncio.create_task(self._event_log(**kwargs), name='event-log')
|
|
||||||
|
|
||||||
def error_log(self, ...):
|
|
||||||
...
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord import app_commands as appcmds
|
from discord import app_commands as appcmds
|
||||||
from discord.ext import commands as cmds
|
from discord.ext import commands as cmds
|
||||||
@@ -22,7 +24,7 @@ class GuildConfigCog(LionCog):
|
|||||||
|
|
||||||
async def cog_load(self):
|
async def cog_load(self):
|
||||||
self.bot.core.guild_config.register_model_setting(GeneralSettings.Timezone)
|
self.bot.core.guild_config.register_model_setting(GeneralSettings.Timezone)
|
||||||
self.bot.core.guild_config.register_model_setting(GeneralSettings.Eventlog)
|
self.bot.core.guild_config.register_model_setting(GeneralSettings.EventLog)
|
||||||
|
|
||||||
configcog = self.bot.get_cog('ConfigCog')
|
configcog = self.bot.get_cog('ConfigCog')
|
||||||
if configcog is None:
|
if configcog is None:
|
||||||
@@ -36,43 +38,13 @@ class GuildConfigCog(LionCog):
|
|||||||
@appcmds.guild_only
|
@appcmds.guild_only
|
||||||
@appcmds.default_permissions(manage_guild=True)
|
@appcmds.default_permissions(manage_guild=True)
|
||||||
async def dashboard_cmd(self, ctx: LionContext):
|
async def dashboard_cmd(self, ctx: LionContext):
|
||||||
|
if not ctx.guild or not ctx.interaction:
|
||||||
|
return
|
||||||
|
|
||||||
ui = GuildDashboard(self.bot, ctx.guild, ctx.author.id, ctx.channel.id)
|
ui = GuildDashboard(self.bot, ctx.guild, ctx.author.id, ctx.channel.id)
|
||||||
await ui.run(ctx.interaction)
|
await ui.run(ctx.interaction)
|
||||||
await ui.wait()
|
await ui.wait()
|
||||||
|
|
||||||
@cmds.hybrid_group("configure", with_app_command=False)
|
|
||||||
async def configure_group(self, ctx: LionContext):
|
|
||||||
# Placeholder configure group command.
|
|
||||||
...
|
|
||||||
|
|
||||||
@configure_group.command(
|
|
||||||
name=_p('cmd:configure_general', "general"),
|
|
||||||
description=_p('cmd:configure_general|desc', "General configuration panel")
|
|
||||||
)
|
|
||||||
@appcmds.rename(
|
|
||||||
timezone=GeneralSettings.Timezone._display_name,
|
|
||||||
event_log=GeneralSettings.EventLog._display_name,
|
|
||||||
)
|
|
||||||
@appcmds.describe(
|
|
||||||
timezone=GeneralSettings.Timezone._desc,
|
|
||||||
event_log=GeneralSettings.EventLog._display_name,
|
|
||||||
)
|
|
||||||
@appcmds.guild_only()
|
|
||||||
@appcmds.default_permissions(manage_guild=True)
|
|
||||||
@low_management_ward
|
|
||||||
async def cmd_configure_general(self, ctx: LionContext,
|
|
||||||
timezone: Optional[str] = None,
|
|
||||||
event_log: Optional[discord.TextChannel] = None,
|
|
||||||
):
|
|
||||||
t = self.bot.translator.t
|
|
||||||
|
|
||||||
# Typechecker guards because they don't understand the check ward
|
|
||||||
if not ctx.guild:
|
|
||||||
return
|
|
||||||
if not ctx.interaction:
|
|
||||||
return
|
|
||||||
await ctx.interaction.response.defer(thinking=True)
|
|
||||||
|
|
||||||
# ----- Configuration -----
|
# ----- Configuration -----
|
||||||
@LionCog.placeholder_group
|
@LionCog.placeholder_group
|
||||||
@cmds.hybrid_group("configure", with_app_command=False)
|
@cmds.hybrid_group("configure", with_app_command=False)
|
||||||
@@ -90,7 +62,7 @@ class GuildConfigCog(LionCog):
|
|||||||
)
|
)
|
||||||
@appcmds.describe(
|
@appcmds.describe(
|
||||||
timezone=GeneralSettings.Timezone._desc,
|
timezone=GeneralSettings.Timezone._desc,
|
||||||
event_log=GeneralSettings.EventLog._display_name,
|
event_log=GeneralSettings.EventLog._desc,
|
||||||
)
|
)
|
||||||
@appcmds.guild_only()
|
@appcmds.guild_only()
|
||||||
@appcmds.default_permissions(manage_guild=True)
|
@appcmds.default_permissions(manage_guild=True)
|
||||||
@@ -107,4 +79,34 @@ class GuildConfigCog(LionCog):
|
|||||||
if not ctx.interaction:
|
if not ctx.interaction:
|
||||||
return
|
return
|
||||||
await ctx.interaction.response.defer(thinking=True)
|
await ctx.interaction.response.defer(thinking=True)
|
||||||
# TODO
|
|
||||||
|
modified = []
|
||||||
|
|
||||||
|
if timezone is not None:
|
||||||
|
setting = self.settings.Timezone
|
||||||
|
instance = await setting.from_string(ctx.guild.id, timezone)
|
||||||
|
modified.append(instance)
|
||||||
|
|
||||||
|
if event_log is not None:
|
||||||
|
setting = self.settings.EventLog
|
||||||
|
instance = await setting.from_value(ctx.guild.id, event_log)
|
||||||
|
modified.append(instance)
|
||||||
|
|
||||||
|
if modified:
|
||||||
|
ack_lines = []
|
||||||
|
for instance in modified:
|
||||||
|
await instance.write()
|
||||||
|
ack_lines.append(instance.update_message)
|
||||||
|
|
||||||
|
tick = self.bot.config.emojis.tick
|
||||||
|
embed = discord.Embed(
|
||||||
|
colour=discord.Colour.brand_green(),
|
||||||
|
description='\n'.join(f"{tick} {line}" for line in ack_lines)
|
||||||
|
)
|
||||||
|
await ctx.reply(embed=embed)
|
||||||
|
|
||||||
|
if ctx.channel.id not in GeneralSettingUI._listening or not modified:
|
||||||
|
ui = GeneralSettingUI(self.bot, ctx.guild.id, ctx.channel.id)
|
||||||
|
await ui.run(ctx.interaction)
|
||||||
|
await ui.wait()
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
|
from typing import Optional
|
||||||
|
import discord
|
||||||
|
|
||||||
from settings import ModelData
|
from settings import ModelData
|
||||||
from settings.setting_types import TimezoneSetting, ChannelSetting
|
from settings.setting_types import TimezoneSetting, ChannelSetting
|
||||||
from settings.groups import SettingGroup
|
from settings.groups import SettingGroup
|
||||||
|
|
||||||
|
from meta.context import ctx_bot
|
||||||
|
from meta.errors import UserInputError
|
||||||
from core.data import CoreData
|
from core.data import CoreData
|
||||||
from babel.translator import ctx_translator
|
from babel.translator import ctx_translator
|
||||||
|
|
||||||
@@ -20,7 +25,8 @@ class GeneralSettings(SettingGroup):
|
|||||||
and the timezone used to display guild-wide statistics.
|
and the timezone used to display guild-wide statistics.
|
||||||
"""
|
"""
|
||||||
setting_id = 'timezone'
|
setting_id = 'timezone'
|
||||||
_event = 'guild_setting_update_timezone'
|
_event = 'guildset_timezone'
|
||||||
|
_set_cmd = 'configure general'
|
||||||
|
|
||||||
_display_name = _p('guildset:timezone', "timezone")
|
_display_name = _p('guildset:timezone', "timezone")
|
||||||
_desc = _p(
|
_desc = _p(
|
||||||
@@ -46,29 +52,24 @@ class GeneralSettings(SettingGroup):
|
|||||||
"The guild timezone has been set to `{timezone}`."
|
"The guild timezone has been set to `{timezone}`."
|
||||||
)).format(timezone=self.data)
|
)).format(timezone=self.data)
|
||||||
|
|
||||||
@property
|
|
||||||
def set_str(self):
|
|
||||||
bot = ctx_bot.get()
|
|
||||||
return bot.core.mention_cmd('configure general') if bot else None
|
|
||||||
|
|
||||||
class EventLog(ModelData, ChannelSetting):
|
class EventLog(ModelData, ChannelSetting):
|
||||||
"""
|
"""
|
||||||
Guild event log channel.
|
Guild event log channel.
|
||||||
"""
|
"""
|
||||||
setting_id = 'eventlog'
|
setting_id = 'eventlog'
|
||||||
_event = 'guildset_eventlog'
|
_event = 'guildset_eventlog'
|
||||||
|
_set_cmd = 'configure general'
|
||||||
|
|
||||||
_display_name = _p('guildset:eventlog', "event_log")
|
_display_name = _p('guildset:eventlog', "event_log")
|
||||||
_desc = _p(
|
_desc = _p(
|
||||||
'guildset:eventlog|desc',
|
'guildset:eventlog|desc',
|
||||||
"Channel to which to log server events, such as voice sessions and equipped roles."
|
"My audit log channel where I send server actions and events (e.g. rankgs and expiring roles)."
|
||||||
)
|
)
|
||||||
# TODO: Reword
|
|
||||||
_long_desc = _p(
|
_long_desc = _p(
|
||||||
'guildset:eventlog|long_desc',
|
'guildset:eventlog|long_desc',
|
||||||
"An audit log for my own systems, "
|
"If configured, I will log most significant actions taken "
|
||||||
"I will send most significant actions and events that occur through my interface "
|
"or events which occur through my interface, into this channel. "
|
||||||
"to this channel. For example, this includes:\n"
|
"Logged events include, for example:\n"
|
||||||
"- Member voice activity\n"
|
"- Member voice activity\n"
|
||||||
"- Roles equipped and expiring from rolemenus\n"
|
"- Roles equipped and expiring from rolemenus\n"
|
||||||
"- Privated rooms rented and expiring\n"
|
"- Privated rooms rented and expiring\n"
|
||||||
@@ -76,4 +77,34 @@ class GeneralSettings(SettingGroup):
|
|||||||
"I must have the 'Manage Webhooks' permission in this channel."
|
"I must have the 'Manage Webhooks' permission in this channel."
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: Updatestr
|
_model = CoreData.Guild
|
||||||
|
_column = CoreData.Guild.event_log_channel.name
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def _check_value(cls, parent_id: int, value: Optional[discord.abc.GuildChannel], **kwargs):
|
||||||
|
if value is not None:
|
||||||
|
t = ctx_translator.get().t
|
||||||
|
if not value.permissions_for(value.guild.me).manage_webhooks:
|
||||||
|
raise UserInputError(
|
||||||
|
t(_p(
|
||||||
|
'guildset:eventlog|check_value|error:perms|perm:manage_webhooks',
|
||||||
|
"Cannot set {channel} as an event log! I lack the 'Manage Webhooks' permission there."
|
||||||
|
)).format(channel=value)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def update_message(self):
|
||||||
|
t = ctx_translator.get().t
|
||||||
|
channel = self.value
|
||||||
|
if channel is not None:
|
||||||
|
response = t(_p(
|
||||||
|
'guildset:eventlog|response|set',
|
||||||
|
"Events will now be logged to {channel}"
|
||||||
|
)).format(channel=channel.mention)
|
||||||
|
else:
|
||||||
|
response = t(_p(
|
||||||
|
'guildset:eventlog|response|unset',
|
||||||
|
"Guild events will no longer be logged."
|
||||||
|
))
|
||||||
|
return response
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import discord
|
|||||||
from discord.ui.select import select, ChannelSelect
|
from discord.ui.select import select, ChannelSelect
|
||||||
|
|
||||||
from meta import LionBot
|
from meta import LionBot
|
||||||
|
from meta.errors import UserInputError
|
||||||
|
|
||||||
from utils.ui import ConfigUI, DashboardSection
|
from utils.ui import ConfigUI, DashboardSection
|
||||||
from utils.lib import MessageArgs
|
from utils.lib import MessageArgs
|
||||||
@@ -18,11 +19,11 @@ _p = babel._p
|
|||||||
class GeneralSettingUI(ConfigUI):
|
class GeneralSettingUI(ConfigUI):
|
||||||
setting_classes = (
|
setting_classes = (
|
||||||
GeneralSettings.Timezone,
|
GeneralSettings.Timezone,
|
||||||
GeneralSettings.Eventlog,
|
GeneralSettings.EventLog,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, bot: LionBot, guildid: int, channelid: int, **kwargs):
|
def __init__(self, bot: LionBot, guildid: int, channelid: int, **kwargs):
|
||||||
self.settings = bot.get_cog('GeneralSettingsCog').settings
|
self.settings = bot.get_cog('GuildConfigCog').settings
|
||||||
super().__init__(bot, guildid, channelid, **kwargs)
|
super().__init__(bot, guildid, channelid, **kwargs)
|
||||||
|
|
||||||
# ----- UI Components -----
|
# ----- UI Components -----
|
||||||
@@ -39,13 +40,10 @@ class GeneralSettingUI(ConfigUI):
|
|||||||
"""
|
"""
|
||||||
await selection.response.defer(thinking=True, ephemeral=True)
|
await selection.response.defer(thinking=True, ephemeral=True)
|
||||||
|
|
||||||
setting = self.get_instance(GeneralSettings.Eventlog)
|
setting = self.get_instance(GeneralSettings.EventLog)
|
||||||
|
|
||||||
value = selected.values[0] if selected.values else None
|
value = selected.values[0].resolve() if selected.values else None
|
||||||
if issue := (await setting.check_value(value)):
|
setting = await setting.from_value(self.guildid, value)
|
||||||
raise UserInputError(issue)
|
|
||||||
|
|
||||||
setting.value = value
|
|
||||||
await setting.write()
|
await setting.write()
|
||||||
await selection.delete_original_response()
|
await selection.delete_original_response()
|
||||||
|
|
||||||
@@ -103,5 +101,5 @@ class GeneralDashboard(DashboardSection):
|
|||||||
"dash:general|option|name",
|
"dash:general|option|name",
|
||||||
"General Configuration Panel"
|
"General Configuration Panel"
|
||||||
)
|
)
|
||||||
configui = GeneralSettingsUI
|
configui = GeneralSettingUI
|
||||||
setting_classes = configui.setting_classes
|
setting_classes = configui.setting_classes
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class TimerOptions(SettingGroup):
|
|||||||
_allow_object = False
|
_allow_object = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _check_value(cls, parent_id: int, value: Optional[discord.abc.GuildChannel], **kwargs):
|
async def _check_value(cls, parent_id: int, value, **kwargs):
|
||||||
if value is not None:
|
if value is not None:
|
||||||
# TODO: Check we either have or can create a webhook
|
# TODO: Check we either have or can create a webhook
|
||||||
# TODO: Check we can send messages, embeds, and files
|
# TODO: Check we can send messages, embeds, and files
|
||||||
|
|||||||
@@ -145,9 +145,7 @@ class TimerOptionsUI(MessageUI):
|
|||||||
value = selected.values[0] if selected.values else None
|
value = selected.values[0] if selected.values else None
|
||||||
setting = self.timer.config.get('notification_channel')
|
setting = self.timer.config.get('notification_channel')
|
||||||
|
|
||||||
if issue := await setting._check_value(self.timer.data.channelid, value):
|
await setting._check_value(self.timer.data.channelid, value)
|
||||||
await selection.edit_original_response(embed=error_embed(issue))
|
|
||||||
else:
|
|
||||||
setting.value = value
|
setting.value = value
|
||||||
await setting.write()
|
await setting.write()
|
||||||
await self.timer.send_status()
|
await self.timer.send_status()
|
||||||
|
|||||||
@@ -453,6 +453,12 @@ class InteractiveSetting(BaseSetting[ParentID, SettingData, SettingValue]):
|
|||||||
data = await cls._parse_string(parent_id, userstr, **kwargs)
|
data = await cls._parse_string(parent_id, userstr, **kwargs)
|
||||||
return cls(parent_id, data, **kwargs)
|
return cls(parent_id, data, **kwargs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def from_value(cls, parent_id, value, **kwargs):
|
||||||
|
await cls._check_value(parent_id, value, **kwargs)
|
||||||
|
data = cls._data_from_value(parent_id, value, **kwargs)
|
||||||
|
return cls(parent_id, data, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _parse_string(cls, parent_id, string: str, **kwargs) -> Optional[SettingData]:
|
async def _parse_string(cls, parent_id, string: str, **kwargs) -> Optional[SettingData]:
|
||||||
"""
|
"""
|
||||||
@@ -471,15 +477,14 @@ class InteractiveSetting(BaseSetting[ParentID, SettingData, SettingValue]):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def _check_value(cls, parent_id, value, **kwargs) -> Optional[str]:
|
async def _check_value(cls, parent_id, value, **kwargs):
|
||||||
"""
|
"""
|
||||||
Check the provided value is valid.
|
Check the provided value is valid.
|
||||||
|
|
||||||
Many setting update methods now provide Discord objects instead of raw data or user strings.
|
Many setting update methods now provide Discord objects instead of raw data or user strings.
|
||||||
This method may be used for value-checking such a value.
|
This method may be used for value-checking such a value.
|
||||||
|
|
||||||
Returns `None` if there are no issues, otherwise an error message.
|
Raises UserInputError if the value fails validation.
|
||||||
Subclasses should override this to implement a value checker.
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user