feat(eventlog): Add eventlog setting.

Also refactors the GeneralSettings to use the new style.
This commit is contained in:
2023-10-10 16:05:57 +03:00
parent 4e8eb366f3
commit fe81945391
7 changed files with 339 additions and 106 deletions

View File

@@ -93,3 +93,12 @@ 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, ...):
...

View File

@@ -6,8 +6,6 @@ babel = LocalBabel('config')
async def setup(bot): async def setup(bot):
from .general import GeneralSettingsCog from .cog import GuildConfigCog
from .cog import DashCog
await bot.add_cog(GeneralSettingsCog(bot)) await bot.add_cog(GuildConfigCog(bot))
await bot.add_cog(DashCog(bot))

View File

@@ -3,22 +3,31 @@ from discord import app_commands as appcmds
from discord.ext import commands as cmds from discord.ext import commands as cmds
from meta import LionBot, LionContext, LionCog from meta import LionBot, LionContext, LionCog
from wards import low_management_ward
from . import babel from . import babel
from .dashboard import GuildDashboard from .dashboard import GuildDashboard
from .settings import GeneralSettings
from .settingui import GeneralSettingUI
_p = babel._p _p = babel._p
class DashCog(LionCog): class GuildConfigCog(LionCog):
depends = {'CoreCog'}
def __init__(self, bot: LionBot): def __init__(self, bot: LionBot):
self.bot = bot self.bot = bot
self.settings = GeneralSettings()
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.Eventlog)
async def cog_unload(self): configcog = self.bot.get_cog('ConfigCog')
... if configcog is None:
raise ValueError("Cannot load GuildConfigCog without ConfigCog")
self.crossload_group(self.configure_group, configcog.configure_group)
@cmds.hybrid_command( @cmds.hybrid_command(
name="dashboard", name="dashboard",
@@ -30,3 +39,72 @@ class DashCog(LionCog):
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 -----
@LionCog.placeholder_group
@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)
# TODO

View File

@@ -26,48 +26,6 @@ from . import babel
_p = babel._p _p = babel._p
class GeneralSettings(SettingGroup):
class Timezone(ModelData, TimezoneSetting):
"""
Guild timezone configuration.
Exposed via `/configure general timezone:`, and the standard interface.
The `timezone` setting acts as the default timezone for all members,
and the timezone used to display guild-wide statistics.
"""
setting_id = 'timezone'
_event = 'guild_setting_update_timezone'
_display_name = _p('guildset:timezone', "timezone")
_desc = _p(
'guildset:timezone|desc',
"Guild timezone for statistics display."
)
_long_desc = _p(
'guildset:timezone|long_desc',
"Guild-wide timezone. "
"Used to determine start of the day for the leaderboards, "
"and as the default statistics timezone for members who have not set one."
)
_default = 'UTC'
_model = CoreData.Guild
_column = CoreData.Guild.timezone.name
@property
def update_message(self):
t = ctx_translator.get().t
return t(_p(
'guildset:timezone|response',
"The guild timezone has been set to `{timezone}`."
)).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 GeneralSettingsCog(LionCog): class GeneralSettingsCog(LionCog):
depends = {'CoreCog'} depends = {'CoreCog'}
@@ -95,16 +53,20 @@ class GeneralSettingsCog(LionCog):
description=_p('cmd:configure_general|desc', "General configuration panel") description=_p('cmd:configure_general|desc', "General configuration panel")
) )
@appcmds.rename( @appcmds.rename(
timezone=GeneralSettings.Timezone._display_name timezone=GeneralSettings.Timezone._display_name,
event_log=GeneralSettings.EventLog._display_name,
) )
@appcmds.describe( @appcmds.describe(
timezone=GeneralSettings.Timezone._desc timezone=GeneralSettings.Timezone._desc,
event_log=GeneralSettings.EventLog._display_name,
) )
@appcmds.guild_only() @appcmds.guild_only()
@appcmds.default_permissions(manage_guild=True) @appcmds.default_permissions(manage_guild=True)
@low_management_ward @low_management_ward
async def cmd_configure_general(self, ctx: LionContext, async def cmd_configure_general(self, ctx: LionContext,
timezone: Optional[str] = None): timezone: Optional[str] = None,
event_log: Optional[discord.TextChannel] = None,
):
t = self.bot.translator.t t = self.bot.translator.t
# Typechecker guards because they don't understand the check ward # Typechecker guards because they don't understand the check ward

View File

@@ -0,0 +1,79 @@
from settings import ModelData
from settings.setting_types import TimezoneSetting, ChannelSetting
from settings.groups import SettingGroup
from core.data import CoreData
from babel.translator import ctx_translator
from . import babel
_p = babel._p
class GeneralSettings(SettingGroup):
class Timezone(ModelData, TimezoneSetting):
"""
Guild timezone configuration.
Exposed via `/configure general timezone:`, and the standard interface.
The `timezone` setting acts as the default timezone for all members,
and the timezone used to display guild-wide statistics.
"""
setting_id = 'timezone'
_event = 'guild_setting_update_timezone'
_display_name = _p('guildset:timezone', "timezone")
_desc = _p(
'guildset:timezone|desc',
"Guild timezone for statistics display."
)
_long_desc = _p(
'guildset:timezone|long_desc',
"Guild-wide timezone. "
"Used to determine start of the day for the leaderboards, "
"and as the default statistics timezone for members who have not set one."
)
_default = 'UTC'
_model = CoreData.Guild
_column = CoreData.Guild.timezone.name
@property
def update_message(self):
t = ctx_translator.get().t
return t(_p(
'guildset:timezone|response',
"The guild timezone has been set to `{timezone}`."
)).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):
"""
Guild event log channel.
"""
setting_id = 'eventlog'
_event = 'guildset_eventlog'
_display_name = _p('guildset:eventlog', "event_log")
_desc = _p(
'guildset:eventlog|desc',
"Channel to which to log server events, such as voice sessions and equipped roles."
)
# TODO: Reword
_long_desc = _p(
'guildset:eventlog|long_desc',
"An audit log for my own systems, "
"I will send most significant actions and events that occur through my interface "
"to this channel. For example, this includes:\n"
"- Member voice activity\n"
"- Roles equipped and expiring from rolemenus\n"
"- Privated rooms rented and expiring\n"
"- Activity ranks earned\n"
"I must have the 'Manage Webhooks' permission in this channel."
)
# TODO: Updatestr

View File

View File

@@ -0,0 +1,107 @@
import asyncio
import discord
from discord.ui.select import select, ChannelSelect
from meta import LionBot
from utils.ui import ConfigUI, DashboardSection
from utils.lib import MessageArgs
from . import babel
from .settings import GeneralSettings
_p = babel._p
class GeneralSettingUI(ConfigUI):
setting_classes = (
GeneralSettings.Timezone,
GeneralSettings.Eventlog,
)
def __init__(self, bot: LionBot, guildid: int, channelid: int, **kwargs):
self.settings = bot.get_cog('GeneralSettingsCog').settings
super().__init__(bot, guildid, channelid, **kwargs)
# ----- UI Components -----
# Event log
@select(
cls=ChannelSelect,
channel_types=[discord.ChannelType.text, discord.ChannelType.voice],
placeholder='EVENT_LOG_PLACEHOLDER',
min_values=0, max_values=1,
)
async def eventlog_menu(self, selection: discord.Interaction, selected: ChannelSelect):
"""
Single channel selector for the event log.
"""
await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(GeneralSettings.Eventlog)
value = selected.values[0] if selected.values else None
if issue := (await setting.check_value(value)):
raise UserInputError(issue)
setting.value = value
await setting.write()
await selection.delete_original_response()
async def eventlog_menu_refresh(self):
menu = self.eventlog_menu
t = self.bot.translator.t
menu.placeholder = t(_p(
'ui:general_config|menu:event_log|placeholder',
"Select Event Log"
))
# ----- UI Flow -----
async def make_message(self) -> MessageArgs:
t = self.bot.translator.t
title = t(_p(
'ui:general_config|embed:title',
"General Configuration"
))
embed = discord.Embed(
title=title,
colour=discord.Colour.orange()
)
for setting in self.instances:
embed.add_field(**setting.embed_field, inline=False)
return MessageArgs(embed=embed)
async def reload(self):
self.instances = [
await setting.get(self.guildid)
for setting in self.setting_classes
]
async def refresh_components(self):
to_refresh = (
self.edit_button_refresh(),
self.close_button_refresh(),
self.reset_button_refresh(),
self.eventlog_menu_refresh(),
)
await asyncio.gather(*to_refresh)
self.set_layout(
(self.eventlog_menu,),
(self.edit_button, self.reset_button, self.close_button,),
)
class GeneralDashboard(DashboardSection):
section_name = _p(
"dash:general|title",
"General Dashboard Settings ({commands[configure general]})"
)
_option_name = _p(
"dash:general|option|name",
"General Configuration Panel"
)
configui = GeneralSettingsUI
setting_classes = configui.setting_classes