feat(config): Split mod and admin config.

This commit is contained in:
2023-10-16 21:43:54 +03:00
parent d9c58806cf
commit ab39ceee71
44 changed files with 227 additions and 102 deletions

View File

@@ -41,7 +41,7 @@ class BabelCog(LionCog):
self.bot.core.user_config.register_model_setting(LocaleSettings.UserLocale) self.bot.core.user_config.register_model_setting(LocaleSettings.UserLocale)
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
userconfigcog = self.bot.get_cog('UserConfigCog') userconfigcog = self.bot.get_cog('UserConfigCog')
self.crossload_group(self.userconfig_group, userconfigcog.userconfig_group) self.crossload_group(self.userconfig_group, userconfigcog.userconfig_group)
@@ -114,8 +114,6 @@ class BabelCog(LionCog):
language=LocaleSettings.GuildLocale._display_name, language=LocaleSettings.GuildLocale._display_name,
force_language=LocaleSettings.ForceLocale._display_name force_language=LocaleSettings.ForceLocale._display_name
) )
@appcmds.guild_only() # Can be removed when attached as a subcommand
@appcmds.default_permissions(manage_guild=True)
@low_management_ward @low_management_ward
async def cmd_configure_language(self, ctx: LionContext, async def cmd_configure_language(self, ctx: LionContext,
language: Optional[str] = None, language: Optional[str] = None,

View File

@@ -7,6 +7,7 @@ from settings.groups import SettingGroup
from meta.errors import UserInputError from meta.errors import UserInputError
from meta.context import ctx_bot from meta.context import ctx_bot
from core.data import CoreData from core.data import CoreData
from wards import low_management_iward
from .translator import ctx_translator from .translator import ctx_translator
from . import babel from . import babel
@@ -104,9 +105,10 @@ class LocaleSettings(SettingGroup):
""" """
Guild configuration for whether to force usage of the guild locale. Guild configuration for whether to force usage of the guild locale.
Exposed via `/configure language` command and standard configuration interface. Exposed via `/config language` command and standard configuration interface.
""" """
setting_id = 'force_locale' setting_id = 'force_locale'
_write_ward = low_management_iward
_display_name = _p('guildset:force_locale', 'force_language') _display_name = _p('guildset:force_locale', 'force_language')
_desc = _p('guildset:force_locale|desc', _desc = _p('guildset:force_locale|desc',
@@ -144,15 +146,16 @@ class LocaleSettings(SettingGroup):
def set_str(self): def set_str(self):
bot = ctx_bot.get() bot = ctx_bot.get()
if bot: if bot:
return bot.core.mention_cmd('configure language') return bot.core.mention_cmd('config language')
class GuildLocale(ModelData, LocaleSetting): class GuildLocale(ModelData, LocaleSetting):
""" """
Guild-configured locale. Guild-configured locale.
Exposed via `/configure language` command, and standard configuration interface. Exposed via `/config language` command, and standard configuration interface.
""" """
setting_id = 'guild_locale' setting_id = 'guild_locale'
_write_ward = low_management_iward
_display_name = _p('guildset:locale', 'language') _display_name = _p('guildset:locale', 'language')
_desc = _p('guildset:locale|desc', "Your preferred language for interacting with me.") _desc = _p('guildset:locale|desc', "Your preferred language for interacting with me.")
@@ -180,4 +183,4 @@ class LocaleSettings(SettingGroup):
def set_str(self): def set_str(self):
bot = ctx_bot.get() bot = ctx_bot.get()
if bot: if bot:
return bot.core.mention_cmd('configure language') return bot.core.mention_cmd('config language')

View File

@@ -29,6 +29,7 @@ class LocaleSettingUI(ConfigUI):
async def force_button(self, press: discord.Interaction, pressed: Button): async def force_button(self, press: discord.Interaction, pressed: Button):
await press.response.defer() await press.response.defer()
setting = next(inst for inst in self.instances if inst.setting_id == LocaleSettings.ForceLocale.setting_id) setting = next(inst for inst in self.instances if inst.setting_id == LocaleSettings.ForceLocale.setting_id)
await setting.interaction_check(self.guildid, press)
setting.value = not setting.value setting.value = not setting.value
await setting.write() await setting.write()
@@ -80,7 +81,7 @@ class LocaleSettingUI(ConfigUI):
class LocaleDashboard(DashboardSection): class LocaleDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:locale|title', 'dash:locale|title',
"Server Language Configuration ({commands[configure language]})" "Server Language Configuration ({commands[config language]})"
) )
_option_name = _p( _option_name = _p(
"dash:locale|dropdown|placeholder", "dash:locale|dropdown|placeholder",

View File

@@ -25,12 +25,35 @@ class ConfigCog(LionCog):
... ...
@cmds.hybrid_group( @cmds.hybrid_group(
name=_p('group:configure', "configure"), name=_p('group:config', "config"),
description=_p('group:configure|desc', "View and adjust my configuration options."), description=_p('group:config|desc', "View and adjust moderation-level configuration."),
) )
@appcmds.guild_only @appcmds.guild_only
@appcmds.default_permissions(manage_guild=True) @appcmds.default_permissions(manage_guild=True)
async def configure_group(self, ctx: LionContext): async def config_group(self, ctx: LionContext):
"""
Bare command group, has no function.
"""
return
@cmds.hybrid_group(
name=_p('group:admin', "admin"),
description=_p('group:admin|desc', "Administrative commands."),
)
@appcmds.guild_only
@appcmds.default_permissions(administrator=True)
async def admin_group(self, ctx: LionContext):
"""
Bare command group, has no function.
"""
return
@admin_group.group(
name=_p('group:admin_config', "config"),
description=_p('group:admin_config|desc', "View and adjust admin-level configuration."),
)
@appcmds.guild_only
async def admin_config_group(self, ctx: LionContext):
""" """
Bare command group, has no function. Bare command group, has no function.
""" """

View File

@@ -29,14 +29,14 @@ class GuildConfigCog(LionCog):
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
if configcog is None: if configcog is None:
raise ValueError("Cannot load GuildConfigCog without ConfigCog") raise ValueError("Cannot load GuildConfigCog without ConfigCog")
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
@cmds.hybrid_command( @cmds.hybrid_command(
name="dashboard", name="dashboard",
description="At-a-glance view of the server's configuration." description="At-a-glance view of the server's configuration."
) )
@appcmds.guild_only @appcmds.guild_only
@appcmds.default_permissions(manage_guild=True) @low_management_ward
async def dashboard_cmd(self, ctx: LionContext): async def dashboard_cmd(self, ctx: LionContext):
if not ctx.guild or not ctx.interaction: if not ctx.guild or not ctx.interaction:
return return
@@ -64,8 +64,6 @@ class GuildConfigCog(LionCog):
timezone=GeneralSettings.Timezone._desc, timezone=GeneralSettings.Timezone._desc,
event_log=GeneralSettings.EventLog._desc, event_log=GeneralSettings.EventLog._desc,
) )
@appcmds.guild_only()
@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,

View File

@@ -9,6 +9,7 @@ from meta.context import ctx_bot
from meta.errors import UserInputError 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
from wards import low_management_iward
from . import babel from . import babel
@@ -20,13 +21,14 @@ class GeneralSettings(SettingGroup):
""" """
Guild timezone configuration. Guild timezone configuration.
Exposed via `/configure general timezone:`, and the standard interface. Exposed via `/config general timezone:`, and the standard interface.
The `timezone` setting acts as the default timezone for all members, The `timezone` setting acts as the default timezone for all members,
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 = 'guildset_timezone' _event = 'guildset_timezone'
_set_cmd = 'configure general' _set_cmd = 'config general'
_write_ward = low_management_iward
_display_name = _p('guildset:timezone', "timezone") _display_name = _p('guildset:timezone', "timezone")
_desc = _p( _desc = _p(
@@ -58,7 +60,8 @@ class GeneralSettings(SettingGroup):
""" """
setting_id = 'eventlog' setting_id = 'eventlog'
_event = 'guildset_eventlog' _event = 'guildset_eventlog'
_set_cmd = 'configure general' _set_cmd = 'config general'
_write_ward = low_management_iward
_display_name = _p('guildset:eventlog', "event_log") _display_name = _p('guildset:eventlog', "event_log")
_desc = _p( _desc = _p(

View File

@@ -41,6 +41,7 @@ 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)
await setting.interaction_check(setting.parent_id, selection)
value = selected.values[0].resolve() if selected.values else None value = selected.values[0].resolve() if selected.values else None
setting = await setting.from_value(self.guildid, value) setting = await setting.from_value(self.guildid, value)
@@ -95,7 +96,7 @@ class GeneralSettingUI(ConfigUI):
class GeneralDashboard(DashboardSection): class GeneralDashboard(DashboardSection):
section_name = _p( section_name = _p(
"dash:general|title", "dash:general|title",
"General Configuration ({commands[configure general]})" "General Configuration ({commands[admin config general]})"
) )
_option_name = _p( _option_name = _p(
"dash:general|option|name", "dash:general|option|name",

View File

@@ -64,7 +64,7 @@ class Economy(LionCog):
"Attempting to load the EconomyCog before ConfigCog! Failed to crossload configuration group." "Attempting to load the EconomyCog before ConfigCog! Failed to crossload configuration group."
) )
else: else:
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
# ----- Economy Bonus registration ----- # ----- Economy Bonus registration -----
def register_economy_bonus(self, bonus_coro, name=None): def register_economy_bonus(self, bonus_coro, name=None):
@@ -903,7 +903,6 @@ class Economy(LionCog):
appcmds.Choice(name=EconomySettings.AllowTransfers._outputs[False], value=0), appcmds.Choice(name=EconomySettings.AllowTransfers._outputs[False], value=0),
] ]
) )
@appcmds.default_permissions(manage_guild=True)
@moderator_ward @moderator_ward
async def configure_economy(self, ctx: LionContext, async def configure_economy(self, ctx: LionContext,
allow_transfers: Optional[appcmds.Choice[int]] = None, allow_transfers: Optional[appcmds.Choice[int]] = None,

View File

@@ -17,6 +17,7 @@ from meta.logger import log_wrap
from core.data import CoreData from core.data import CoreData
from core.setting_types import CoinSetting from core.setting_types import CoinSetting
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward
from . import babel, logger from . import babel, logger
from .data import EconomyData from .data import EconomyData
@@ -32,6 +33,7 @@ class EconomySettings(SettingGroup):
""" """
class CoinsPerXP(ModelData, CoinSetting): class CoinsPerXP(ModelData, CoinSetting):
setting_id = 'coins_per_xp' setting_id = 'coins_per_xp'
_write_ward = low_management_iward
_display_name = _p('guildset:coins_per_xp', "coins_per_100xp") _display_name = _p('guildset:coins_per_xp', "coins_per_100xp")
_desc = _p( _desc = _p(
@@ -63,10 +65,11 @@ class EconomySettings(SettingGroup):
@property @property
def set_str(self): def set_str(self):
bot = ctx_bot.get() bot = ctx_bot.get()
return bot.core.mention_cmd('configure economy') if bot else None return bot.core.mention_cmd('config economy') if bot else None
class AllowTransfers(ModelData, BoolSetting): class AllowTransfers(ModelData, BoolSetting):
setting_id = 'allow_transfers' setting_id = 'allow_transfers'
_write_ward = low_management_iward
_display_name = _p('guildset:allow_transfers', "allow_transfers") _display_name = _p('guildset:allow_transfers', "allow_transfers")
_desc = _p( _desc = _p(
@@ -91,7 +94,7 @@ class EconomySettings(SettingGroup):
@property @property
def set_str(self): def set_str(self):
bot = ctx_bot.get() bot = ctx_bot.get()
return bot.core.mention_cmd('configure economy') if bot else None return bot.core.mention_cmd('config economy') if bot else None
@property @property
def update_message(self): def update_message(self):
@@ -115,6 +118,7 @@ class EconomySettings(SettingGroup):
class StartingFunds(ModelData, CoinSetting): class StartingFunds(ModelData, CoinSetting):
setting_id = 'starting_funds' setting_id = 'starting_funds'
_write_ward = low_management_iward
_display_name = _p('guildset:starting_funds', "starting_funds") _display_name = _p('guildset:starting_funds', "starting_funds")
_desc = _p( _desc = _p(

View File

@@ -64,7 +64,7 @@ class EconomyConfigUI(ConfigUI):
class EconomyDashboard(DashboardSection): class EconomyDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:economy|title', 'dash:economy|title',
"Economy Configuration ({commands[configure economy]})" "Economy Configuration ({commands[config economy]})"
) )
_option_name = _p( _option_name = _p(
"dash:economy|dropdown|placeholder", "dash:economy|dropdown|placeholder",

View File

@@ -46,7 +46,7 @@ class MemberAdminCog(LionCog):
"Configuration command cannot be crossloaded." "Configuration command cannot be crossloaded."
) )
else: else:
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
# ----- Cog API ----- # ----- Cog API -----
async def absent_remove_role(self, guildid, userid, roleid): async def absent_remove_role(self, guildid, userid, roleid):

View File

@@ -9,6 +9,7 @@ from settings import ListData, ModelData
from settings.groups import SettingGroup from settings.groups import SettingGroup
from settings.setting_types import BoolSetting, ChannelSetting, RoleListSetting from settings.setting_types import BoolSetting, ChannelSetting, RoleListSetting
from utils.lib import recurse_map, replace_multiple, tabulate from utils.lib import recurse_map, replace_multiple, tabulate
from wards import low_management_iward, high_management_iward
from . import babel from . import babel
from .data import MemberAdminData from .data import MemberAdminData
@@ -36,6 +37,7 @@ _greeting_subkey_desc = {
class MemberAdminSettings(SettingGroup): class MemberAdminSettings(SettingGroup):
class GreetingChannel(ModelData, ChannelSetting): class GreetingChannel(ModelData, ChannelSetting):
setting_id = 'greeting_channel' setting_id = 'greeting_channel'
_write_ward = low_management_iward
_display_name = _p('guildset:greeting_channel', "welcome_channel") _display_name = _p('guildset:greeting_channel', "welcome_channel")
_desc = _p( _desc = _p(
@@ -87,6 +89,7 @@ class MemberAdminSettings(SettingGroup):
class GreetingMessage(ModelData, MessageSetting): class GreetingMessage(ModelData, MessageSetting):
setting_id = 'greeting_message' setting_id = 'greeting_message'
_write_ward = low_management_iward
_display_name = _p( _display_name = _p(
'guildset:greeting_message', "welcome_message" 'guildset:greeting_message', "welcome_message"
@@ -209,6 +212,7 @@ class MemberAdminSettings(SettingGroup):
class ReturningMessage(ModelData, MessageSetting): class ReturningMessage(ModelData, MessageSetting):
setting_id = 'returning_message' setting_id = 'returning_message'
_write_ward = low_management_iward
_display_name = _p( _display_name = _p(
'guildset:returning_message', "returning_message" 'guildset:returning_message', "returning_message"
@@ -335,6 +339,7 @@ class MemberAdminSettings(SettingGroup):
class Autoroles(ListData, RoleListSetting): class Autoroles(ListData, RoleListSetting):
setting_id = 'autoroles' setting_id = 'autoroles'
_write_ward = high_management_iward
_display_name = _p( _display_name = _p(
'guildset:autoroles', "autoroles" 'guildset:autoroles', "autoroles"
@@ -357,6 +362,7 @@ class MemberAdminSettings(SettingGroup):
class BotAutoroles(ListData, RoleListSetting): class BotAutoroles(ListData, RoleListSetting):
setting_id = 'bot_autoroles' setting_id = 'bot_autoroles'
_write_ward = high_management_iward
_display_name = _p( _display_name = _p(
'guildset:bot_autoroles', "bot_autoroles" 'guildset:bot_autoroles', "bot_autoroles"
@@ -379,6 +385,7 @@ class MemberAdminSettings(SettingGroup):
class RolePersistence(ModelData, BoolSetting): class RolePersistence(ModelData, BoolSetting):
setting_id = 'role_persistence' setting_id = 'role_persistence'
_event = 'guildset_role_persistence' _event = 'guildset_role_persistence'
_write_ward = low_management_iward
_display_name = _p('guildset:role_persistence', "role_persistence") _display_name = _p('guildset:role_persistence', "role_persistence")
_desc = _p( _desc = _p(

View File

@@ -45,6 +45,7 @@ class MemberAdminUI(ConfigUI):
""" """
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(Settings.GreetingChannel) setting = self.get_instance(Settings.GreetingChannel)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -73,6 +74,7 @@ class MemberAdminUI(ConfigUI):
await equippable_role(self.bot, role, selection.user) await equippable_role(self.bot, role, selection.user)
setting = self.get_instance(Settings.Autoroles) setting = self.get_instance(Settings.Autoroles)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
# Instance hooks will update the menu # Instance hooks will update the menu
@@ -102,6 +104,7 @@ class MemberAdminUI(ConfigUI):
await equippable_role(self.bot, role, selection.user) await equippable_role(self.bot, role, selection.user)
setting = self.get_instance(Settings.BotAutoroles) setting = self.get_instance(Settings.BotAutoroles)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
# Instance hooks will update the menu # Instance hooks will update the menu
@@ -131,6 +134,7 @@ class MemberAdminUI(ConfigUI):
await press.response.defer(thinking=True, ephemeral=True) await press.response.defer(thinking=True, ephemeral=True)
t = self.bot.translator.t t = self.bot.translator.t
setting = self.get_instance(Settings.GreetingMessage) setting = self.get_instance(Settings.GreetingMessage)
await setting.interaction_check(setting.parent_id, press)
value = setting.value value = setting.value
if value is None: if value is None:
@@ -173,6 +177,7 @@ class MemberAdminUI(ConfigUI):
await press.response.defer(thinking=True, ephemeral=True) await press.response.defer(thinking=True, ephemeral=True)
t = self.bot.translator.t t = self.bot.translator.t
setting = self.get_instance(Settings.ReturningMessage) setting = self.get_instance(Settings.ReturningMessage)
await setting.interaction_check(setting.parent_id, press)
greeting = self.get_instance(Settings.GreetingMessage) greeting = self.get_instance(Settings.GreetingMessage)
value = setting.value value = setting.value
@@ -254,7 +259,7 @@ class MemberAdminUI(ConfigUI):
class MemberAdminDashboard(DashboardSection): class MemberAdminDashboard(DashboardSection):
section_name = _p( section_name = _p(
"dash:member_admin|title", "dash:member_admin|title",
"Greetings and Initial Roles ({commands[configure welcome]})" "Greetings and Initial Roles ({commands[admin config welcome]})"
) )
_option_name = _p( _option_name = _p(
"dash:member_admin|dropdown|placeholder", "dash:member_admin|dropdown|placeholder",
@@ -278,7 +283,7 @@ class MemberAdminDashboard(DashboardSection):
page.add_field( page.add_field(
name=t(_p( name=t(_p(
'dash:member_admin|section:greeting_messages|name', 'dash:member_admin|section:greeting_messages|name',
"Greeting Messages ({commands[configure welcome]})" "Greeting Messages ({commands[admin config welcome]})"
)).format(commands=self.bot.core.mention_cache), )).format(commands=self.bot.core.mention_cache),
value=table, value=table,
inline=False inline=False
@@ -289,7 +294,7 @@ class MemberAdminDashboard(DashboardSection):
page.add_field( page.add_field(
name=t(_p( name=t(_p(
'dash:member_admin|section:initial_roles|name', 'dash:member_admin|section:initial_roles|name',
"Initial Roles ({commands[configure welcome]})" "Initial Roles ({commands[admin config welcome]})"
)).format(commands=self.bot.core.mention_cache), )).format(commands=self.bot.core.mention_cache),
value=table, value=table,
inline=False inline=False

View File

@@ -74,8 +74,8 @@ admin_extra = _p(
Use {cmd_dashboard} to see an overview of the server configuration, \ Use {cmd_dashboard} to see an overview of the server configuration, \
and quickly jump to the feature configuration panels to modify settings. and quickly jump to the feature configuration panels to modify settings.
Configuration panels are also accessible directly through the `/configure` commands \ Most settings may also be directly set through the `/config` and `/admin config` commands, \
and most features may be configured through these commands. depending on whether the settings require moderator (manage server) or admin level permissions, respectively.
Other relevant commands for guild configuration below: Other relevant commands for guild configuration below:
`/editshop`: Add/Edit/Remove colour roles from the {coin} shop. `/editshop`: Add/Edit/Remove colour roles from the {coin} shop.

View File

@@ -51,7 +51,7 @@ class ModerationCog(LionCog):
"Moderation configuration will not crossload." "Moderation configuration will not crossload."
) )
else: else:
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.admin_config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()

View File

@@ -6,6 +6,7 @@ from settings.setting_types import (
from core.data import CoreData from core.data import CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward, high_management_iward
from . import babel from . import babel
@@ -16,6 +17,7 @@ class ModerationSettings(SettingGroup):
class TicketLog(ModelData, ChannelSetting): class TicketLog(ModelData, ChannelSetting):
setting_id = "ticket_log" setting_id = "ticket_log"
_event = 'guildset_ticket_log' _event = 'guildset_ticket_log'
_write_ward = low_management_iward
_display_name = _p('guildset:ticket_log', "ticket_log") _display_name = _p('guildset:ticket_log', "ticket_log")
_desc = _p( _desc = _p(
@@ -66,6 +68,7 @@ class ModerationSettings(SettingGroup):
class AlertChannel(ModelData, ChannelSetting): class AlertChannel(ModelData, ChannelSetting):
setting_id = "alert_channel" setting_id = "alert_channel"
_event = 'guildset_alert_channel' _event = 'guildset_alert_channel'
_write_ward = low_management_iward
_display_name = _p('guildset:alert_channel', "alert_channel") _display_name = _p('guildset:alert_channel', "alert_channel")
_desc = _p( _desc = _p(
@@ -119,18 +122,23 @@ class ModerationSettings(SettingGroup):
class ModRole(ModelData, RoleSetting): class ModRole(ModelData, RoleSetting):
setting_id = "mod_role" setting_id = "mod_role"
_event = 'guildset_mod_role' _event = 'guildset_mod_role'
_write_ward = high_management_iward
_display_name = _p('guildset:mod_role', "mod_role") _display_name = _p('guildset:mod_role', "mod_role")
_desc = _p( _desc = _p(
'guildset:mod_role|desc', 'guildset:mod_role|desc',
"Guild role permitted to view configuration and perform moderation tasks." "Server role permitted to perform moderation and minor bot configuration."
) )
_long_desc = _p( _long_desc = _p(
'guildset:mod_role|long_desc', 'guildset:mod_role|long_desc',
"Members with the set role will be able to access my configuration panels, " "Members with the moderator role are considered moderators,"
"and perform some moderation tasks, such as setting up pomodoro timers. " " and are permitted to use moderator commands,"
"Moderators cannot reconfigure most bot configuration, " " such as viewing and pardoning moderation tickets,"
"or perform operations they do not already have permission for in Discord." " creating moderation notes,"
" and performing minor reconfiguration through the `/config` command.\n"
"Moderators are never permitted to perform actions (such as giving roles)"
" that they do not already have the Discord permissions for.\n"
"Members with the 'Manage Guild' permission are always considered moderators."
) )
_accepts = _p( _accepts = _p(
'guildset:mod_role|accepts', 'guildset:mod_role|accepts',
@@ -149,11 +157,13 @@ class ModerationSettings(SettingGroup):
resp = t(_p( resp = t(_p(
'guildset:mod_role|set_response:set', 'guildset:mod_role|set_response:set',
"Members with {role} will be considered moderators." "Members with {role} will be considered moderators."
" You may need to grant them access to view moderation commands"
" via the server integration settings."
)).format(role=value.mention) )).format(role=value.mention)
else: else:
resp = t(_p( resp = t(_p(
'guildset:mod_role|set_response:unset', 'guildset:mod_role|set_response:unset',
"No members will be given moderation privileges." "Only members with the 'Manage Guild' permission will be considered moderators."
)) ))
return resp return resp
@@ -171,6 +181,7 @@ class ModerationSettings(SettingGroup):
class AdminRole(ModelData, RoleSetting): class AdminRole(ModelData, RoleSetting):
setting_id = "admin_role" setting_id = "admin_role"
_event = 'guildset_admin_role' _event = 'guildset_admin_role'
_write_ward = high_management_iward
_display_name = _p('guildset:admin_role', "admin_role") _display_name = _p('guildset:admin_role', "admin_role")
_desc = _p( _desc = _p(

View File

@@ -42,6 +42,7 @@ class ModerationSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(ModerationSettings.TicketLog) setting = self.get_instance(ModerationSettings.TicketLog)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -67,6 +68,7 @@ class ModerationSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(ModerationSettings.AlertChannel) setting = self.get_instance(ModerationSettings.AlertChannel)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -92,6 +94,7 @@ class ModerationSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(ModerationSettings.ModRole) setting = self.get_instance(ModerationSettings.ModRole)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -117,6 +120,7 @@ class ModerationSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(ModerationSettings.AdminRole) setting = self.get_instance(ModerationSettings.AdminRole)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -175,7 +179,7 @@ class ModerationSettingUI(ConfigUI):
class ModerationDashboard(DashboardSection): class ModerationDashboard(DashboardSection):
section_name = _p( section_name = _p(
"dash:moderation|title", "dash:moderation|title",
"Moderation Settings ({commands[configure moderation]})" "Moderation Settings ({commands[admin config moderation]})"
) )
_option_name = _p( _option_name = _p(
"dash:moderation|dropdown|placeholder", "dash:moderation|dropdown|placeholder",

View File

@@ -90,7 +90,7 @@ class TimerCog(LionCog):
self.bot.core.guild_config.register_model_setting(self.settings.PomodoroChannel) self.bot.core.guild_config.register_model_setting(self.settings.PomodoroChannel)
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()
@@ -977,7 +977,6 @@ class TimerCog(LionCog):
@appcmds.describe( @appcmds.describe(
pomodoro_channel=TimerSettings.PomodoroChannel._desc pomodoro_channel=TimerSettings.PomodoroChannel._desc
) )
@appcmds.default_permissions(manage_guild=True)
@low_management_ward @low_management_ward
async def configure_pomodoro_command(self, ctx: LionContext, async def configure_pomodoro_command(self, ctx: LionContext,
pomodoro_channel: Optional[discord.VoiceChannel | discord.TextChannel] = None): pomodoro_channel: Optional[discord.VoiceChannel | discord.TextChannel] = None):

View File

@@ -4,6 +4,7 @@ from settings.setting_types import ChannelSetting
from core.data import CoreData from core.data import CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward
from . import babel from . import babel
@@ -14,7 +15,8 @@ class TimerSettings(SettingGroup):
class PomodoroChannel(ModelData, ChannelSetting): class PomodoroChannel(ModelData, ChannelSetting):
setting_id = 'pomodoro_channel' setting_id = 'pomodoro_channel'
_event = 'guildset_pomodoro_channel' _event = 'guildset_pomodoro_channel'
_set_cmd = 'configure pomodoro' _set_cmd = 'config pomodoro'
_write_ward = low_management_iward
_display_name = _p('guildset:pomodoro_channel', "pomodoro_channel") _display_name = _p('guildset:pomodoro_channel', "pomodoro_channel")
_desc = _p( _desc = _p(

View File

@@ -30,6 +30,7 @@ class TimerConfigUI(ConfigUI):
async def channel_menu(self, selection: discord.Interaction, selected: ChannelSelect): async def channel_menu(self, selection: discord.Interaction, selected: ChannelSelect):
await selection.response.defer() await selection.response.defer()
setting = self.instances[0] setting = self.instances[0]
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
@@ -78,7 +79,7 @@ class TimerConfigUI(ConfigUI):
class TimerDashboard(DashboardSection): class TimerDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:pomodoro|title', 'dash:pomodoro|title',
"Pomodoro Configuration ({commands[configure pomodoro]})" "Pomodoro Configuration ({commands[admin config pomodoro]})"
) )
_option_name = _p( _option_name = _p(
"dash:stats|dropdown|placeholder", "dash:stats|dropdown|placeholder",

View File

@@ -140,7 +140,7 @@ class RankCog(LionCog):
self.bot.core.guild_config.register_model_setting(self.settings.DMRanks) self.bot.core.guild_config.register_model_setting(self.settings.DMRanks)
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.admin_config_group)
def ranklock(self, guildid): def ranklock(self, guildid):
lock = self._rank_locks.get(guildid, None) lock = self._rank_locks.get(guildid, None)
@@ -926,7 +926,6 @@ class RankCog(LionCog):
dm_ranks=RankSettings.DMRanks._desc, dm_ranks=RankSettings.DMRanks._desc,
rank_channel=RankSettings.RankChannel._desc, rank_channel=RankSettings.RankChannel._desc,
) )
@appcmds.default_permissions(administrator=True)
@high_management_ward @high_management_ward
async def configure_ranks_cmd(self, ctx: LionContext, async def configure_ranks_cmd(self, ctx: LionContext,
rank_type: Optional[Transformed[RankTypeChoice, AppCommandOptionType.string]] = None, rank_type: Optional[Transformed[RankTypeChoice, AppCommandOptionType.string]] = None,

View File

@@ -4,6 +4,7 @@ from settings.setting_types import BoolSetting, ChannelSetting, EnumSetting
from core.data import RankType, CoreData from core.data import RankType, CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import high_management_iward
from . import babel from . import babel
@@ -40,7 +41,8 @@ class RankSettings(SettingGroup):
setting_id = 'rank_type' setting_id = 'rank_type'
_event = 'guildset_rank_type' _event = 'guildset_rank_type'
_set_cmd = 'configure ranks' _set_cmd = 'admin config ranks'
_write_ward = high_management_iward
_display_name = _p('guildset:rank_type', "rank_type") _display_name = _p('guildset:rank_type', "rank_type")
_desc = _p( _desc = _p(
@@ -98,7 +100,8 @@ class RankSettings(SettingGroup):
If DMRanks is set, this will only be used when the target user has disabled DM notifications. If DMRanks is set, this will only be used when the target user has disabled DM notifications.
""" """
setting_id = 'rank_channel' setting_id = 'rank_channel'
_set_cmd = 'configure ranks' _set_cmd = 'admin config ranks'
_write_ward = high_management_iward
_display_name = _p('guildset:rank_channel', "rank_channel") _display_name = _p('guildset:rank_channel', "rank_channel")
_desc = _p( _desc = _p(
@@ -148,7 +151,8 @@ class RankSettings(SettingGroup):
Whether to DM rank notifications. Whether to DM rank notifications.
""" """
setting_id = 'dm_ranks' setting_id = 'dm_ranks'
_set_cmd = 'configure ranks' _set_cmd = 'admin config ranks'
_write_ward = high_management_iward
_display_name = _p('guildset:dm_ranks', "dm_ranks") _display_name = _p('guildset:dm_ranks', "dm_ranks")
_desc = _p( _desc = _p(

View File

@@ -69,6 +69,7 @@ class RankConfigUI(ConfigUI):
async def type_menu(self, selection: discord.Interaction, selected: Select): async def type_menu(self, selection: discord.Interaction, selected: Select):
await selection.response.defer(thinking=True) await selection.response.defer(thinking=True)
setting = self.instances[0] setting = self.instances[0]
await setting.interaction_check(setting.parent_id, selection)
value = selected.values[0] value = selected.values[0]
data = RankType((value,)) data = RankType((value,))
setting.data = data setting.data = data
@@ -117,6 +118,7 @@ class RankConfigUI(ConfigUI):
async def channel_menu(self, selection: discord.Interaction, selected: ChannelSelect): async def channel_menu(self, selection: discord.Interaction, selected: ChannelSelect):
await selection.response.defer() await selection.response.defer()
setting = self.instances[2] setting = self.instances[2]
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
@@ -168,7 +170,7 @@ class RankConfigUI(ConfigUI):
class RankDashboard(DashboardSection): class RankDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:rank|title', 'dash:rank|title',
"Rank Configuration ({commands[configure ranks]})", "Rank Configuration ({commands[admin config ranks]})",
) )
_option_name = _p( _option_name = _p(
"dash:rank|dropdown|placeholder", "dash:rank|dropdown|placeholder",

View File

@@ -430,7 +430,7 @@ class RankOverviewUI(MessageUI):
"Ranks are determined by *all-time* statistics.\n" "Ranks are determined by *all-time* statistics.\n"
"To reward ranks from a later time (e.g. to have monthly/quarterly/yearly ranks) " "To reward ranks from a later time (e.g. to have monthly/quarterly/yearly ranks) "
"set the `season_start` with {stats_cmd}" "set the `season_start` with {stats_cmd}"
)).format(stats_cmd=self.bot.core.mention_cmd('configure statistics')) )).format(stats_cmd=self.bot.core.mention_cmd('admin config statistics'))
if self.rank_type is RankType.VOICE: if self.rank_type is RankType.VOICE:
addendum = t(_p( addendum = t(_p(
'ui:rank_overview|embed|field:note|value|voice_addendum', 'ui:rank_overview|embed|field:note|value|voice_addendum',

View File

@@ -16,7 +16,7 @@ from utils.ui import Confirm
from constants import MAX_COINS from constants import MAX_COINS
from core.data import CoreData from core.data import CoreData
from wards import low_management_ward from wards import high_management_ward
from . import babel, logger from . import babel, logger
from .data import RoomData from .data import RoomData
@@ -47,7 +47,7 @@ class RoomCog(LionCog):
self.bot.core.guild_config.register_model_setting(setting) self.bot.core.guild_config.register_model_setting(setting)
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.admin_config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()
@@ -414,7 +414,7 @@ class RoomCog(LionCog):
t(_p( t(_p(
'cmd:room_rent|error:not_setup', 'cmd:room_rent|error:not_setup',
"The private room system has not been set up! " "The private room system has not been set up! "
"A private room category needs to be set first with `/configure rooms`." "A private room category needs to be set first with `/admin config rooms`."
)) ))
), ephemeral=True ), ephemeral=True
) )
@@ -987,8 +987,7 @@ class RoomCog(LionCog):
@appcmds.describe( @appcmds.describe(
**{setting.setting_id: setting._desc for setting in RoomSettings.model_settings} **{setting.setting_id: setting._desc for setting in RoomSettings.model_settings}
) )
@appcmds.default_permissions(manage_guild=True) @high_management_ward
@low_management_ward
async def configure_rooms_cmd(self, ctx: LionContext, async def configure_rooms_cmd(self, ctx: LionContext,
rooms_category: Optional[discord.CategoryChannel] = None, rooms_category: Optional[discord.CategoryChannel] = None,
rooms_price: Optional[Range[int, 0, MAX_COINS]] = None, rooms_price: Optional[Range[int, 0, MAX_COINS]] = None,

View File

@@ -5,6 +5,7 @@ from settings.setting_types import ChannelSetting, IntegerSetting, BoolSetting
from meta import conf from meta import conf
from core.data import CoreData from core.data import CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward, high_management_iward
from . import babel from . import babel
@@ -15,7 +16,8 @@ class RoomSettings(SettingGroup):
class Category(ModelData, ChannelSetting): class Category(ModelData, ChannelSetting):
setting_id = 'rooms_category' setting_id = 'rooms_category'
_event = 'guildset_rooms_category' _event = 'guildset_rooms_category'
_set_cmd = 'configure rooms' _set_cmd = 'admin config rooms'
_write_ward = high_management_iward
_display_name = _p( _display_name = _p(
'guildset:room_category', "rooms_category" 'guildset:room_category', "rooms_category"
@@ -70,7 +72,8 @@ class RoomSettings(SettingGroup):
class Rent(ModelData, IntegerSetting): class Rent(ModelData, IntegerSetting):
setting_id = 'rooms_price' setting_id = 'rooms_price'
_event = 'guildset_rooms_price' _event = 'guildset_rooms_price'
_set_cmd = 'configure rooms' _set_cmd = 'admin config rooms'
_write_ward = low_management_iward
_display_name = _p( _display_name = _p(
'guildset:rooms_price', "room_rent" 'guildset:rooms_price', "room_rent"
@@ -107,7 +110,8 @@ class RoomSettings(SettingGroup):
class MemberLimit(ModelData, IntegerSetting): class MemberLimit(ModelData, IntegerSetting):
setting_id = 'rooms_slots' setting_id = 'rooms_slots'
_event = 'guildset_rooms_slots' _event = 'guildset_rooms_slots'
_set_cmd = 'configure rooms' _set_cmd = 'admin config rooms'
_write_ward = low_management_iward
_display_name = _p('guildset:rooms_slots', "room_member_cap") _display_name = _p('guildset:rooms_slots', "room_member_cap")
_desc = _p( _desc = _p(
@@ -141,7 +145,8 @@ class RoomSettings(SettingGroup):
class Visible(ModelData, BoolSetting): class Visible(ModelData, BoolSetting):
setting_id = 'rooms_visible' setting_id = 'rooms_visible'
_event = 'guildset_rooms_visible' _event = 'guildset_rooms_visible'
_set_cmd = 'configure rooms' _set_cmd = 'admin config rooms'
_write_ward = high_management_iward
_display_name = _p('guildset:rooms_visible', "room_visibility") _display_name = _p('guildset:rooms_visible', "room_visibility")
_desc = _p( _desc = _p(

View File

@@ -29,6 +29,7 @@ class RoomSettingUI(ConfigUI):
async def category_menu(self, selection: discord.Interaction, selected: ChannelSelect): async def category_menu(self, selection: discord.Interaction, selected: ChannelSelect):
await selection.response.defer() await selection.response.defer()
setting = self.instances[0] setting = self.instances[0]
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
@@ -42,6 +43,7 @@ class RoomSettingUI(ConfigUI):
async def visible_button(self, press: discord.Interaction, pressed: Button): async def visible_button(self, press: discord.Interaction, pressed: Button):
await press.response.defer() await press.response.defer()
setting = next(inst for inst in self.instances if inst.setting_id == RoomSettings.Visible.setting_id) setting = next(inst for inst in self.instances if inst.setting_id == RoomSettings.Visible.setting_id)
await setting.interaction_check(setting.parent_id, press)
setting.value = not setting.value setting.value = not setting.value
await setting.write() await setting.write()
@@ -95,7 +97,7 @@ class RoomSettingUI(ConfigUI):
class RoomDashboard(DashboardSection): class RoomDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:rooms|title', 'dash:rooms|title',
"Private Room Configuration ({commands[configure rooms]})" "Private Room Configuration ({commands[admin config rooms]})"
) )
_option_name = _p( _option_name = _p(
"dash:economy|dropdown|placeholder", "dash:economy|dropdown|placeholder",

View File

@@ -17,7 +17,7 @@ from meta.monitor import ComponentMonitor, ComponentStatus, StatusLevel
from utils.lib import utc_now, error_embed from utils.lib import utc_now, error_embed
from utils.ui import Confirm from utils.ui import Confirm
from utils.data import MULTIVALUE_IN, MEMBERS from utils.data import MULTIVALUE_IN, MEMBERS
from wards import low_management_ward from wards import high_management_ward
from core.data import CoreData from core.data import CoreData
from data import NULL, ORDER from data import NULL, ORDER
from modules.economy.data import TransactionType from modules.economy.data import TransactionType
@@ -118,7 +118,7 @@ class ScheduleCog(LionCog):
await self.settings.SessionChannels.setup(self.bot) await self.settings.SessionChannels.setup(self.bot)
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.admin_config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()
@@ -1090,7 +1090,7 @@ class ScheduleCog(LionCog):
@appcmds.describe( @appcmds.describe(
**{param: option._desc for param, option in config_params.items()} **{param: option._desc for param, option in config_params.items()}
) )
@low_management_ward @high_management_ward
async def configure_schedule_command(self, ctx: LionContext, async def configure_schedule_command(self, ctx: LionContext,
session_lobby: Optional[discord.TextChannel | discord.VoiceChannel] = None, session_lobby: Optional[discord.TextChannel | discord.VoiceChannel] = None,
session_room: Optional[discord.VoiceChannel] = None, session_room: Optional[discord.VoiceChannel] = None,

View File

@@ -11,6 +11,7 @@ from meta import conf
from meta.errors import UserInputError from meta.errors import UserInputError
from meta.sharding import THIS_SHARD from meta.sharding import THIS_SHARD
from meta.logger import log_wrap from meta.logger import log_wrap
from wards import low_management_iward, high_management_iward
from babel.translator import ctx_translator from babel.translator import ctx_translator
@@ -63,7 +64,8 @@ class ScheduleSettings(SettingGroup):
class SessionLobby(ModelData, ChannelSetting): class SessionLobby(ModelData, ChannelSetting):
setting_id = 'session_lobby' setting_id = 'session_lobby'
_event = 'guildset_session_lobby' _event = 'guildset_session_lobby'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = high_management_iward
_display_name = _p('guildset:session_lobby', "session_lobby") _display_name = _p('guildset:session_lobby', "session_lobby")
_desc = _p( _desc = _p(
@@ -119,7 +121,8 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class SessionRoom(ModelData, ChannelSetting): class SessionRoom(ModelData, ChannelSetting):
setting_id = 'session_room' setting_id = 'session_room'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = high_management_iward
_display_name = _p('guildset:session_room', "session_room") _display_name = _p('guildset:session_room', "session_room")
_desc = _p( _desc = _p(
@@ -163,6 +166,7 @@ class ScheduleSettings(SettingGroup):
class SessionChannels(ListData, ChannelListSetting): class SessionChannels(ListData, ChannelListSetting):
setting_id = 'session_channels' setting_id = 'session_channels'
_write_ward = high_management_iward
_display_name = _p('guildset:session_channels', "session_channels") _display_name = _p('guildset:session_channels', "session_channels")
_desc = _p( _desc = _p(
@@ -238,7 +242,8 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class ScheduleCost(ModelData, CoinSetting): class ScheduleCost(ModelData, CoinSetting):
setting_id = 'schedule_cost' setting_id = 'schedule_cost'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = low_management_iward
_display_name = _p('guildset:schedule_cost', "schedule_cost") _display_name = _p('guildset:schedule_cost', "schedule_cost")
_desc = _p( _desc = _p(
@@ -283,7 +288,8 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class AttendanceReward(ModelData, CoinSetting): class AttendanceReward(ModelData, CoinSetting):
setting_id = 'attendance_reward' setting_id = 'attendance_reward'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = low_management_iward
_display_name = _p('guildset:attendance_reward', "attendance_reward") _display_name = _p('guildset:attendance_reward', "attendance_reward")
_desc = _p( _desc = _p(
@@ -327,7 +333,8 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class AttendanceBonus(ModelData, CoinSetting): class AttendanceBonus(ModelData, CoinSetting):
setting_id = 'attendance_bonus' setting_id = 'attendance_bonus'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = low_management_iward
_display_name = _p('guildset:attendance_bonus', "group_attendance_bonus") _display_name = _p('guildset:attendance_bonus', "group_attendance_bonus")
_desc = _p( _desc = _p(
@@ -370,7 +377,8 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class MinAttendance(ModelData, IntegerSetting): class MinAttendance(ModelData, IntegerSetting):
setting_id = 'min_attendance' setting_id = 'min_attendance'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = low_management_iward
_display_name = _p('guildset:min_attendance', "min_attendance") _display_name = _p('guildset:min_attendance', "min_attendance")
_desc = _p( _desc = _p(
@@ -437,8 +445,9 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class BlacklistRole(ModelData, RoleSetting): class BlacklistRole(ModelData, RoleSetting):
setting_id = 'schedule_blacklist_role' setting_id = 'schedule_blacklist_role'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_event = 'guildset_schedule_blacklist_role' _event = 'guildset_schedule_blacklist_role'
_write_ward = high_management_iward
_display_name = _p('guildset:schedule_blacklist_role', "schedule_blacklist_role") _display_name = _p('guildset:schedule_blacklist_role', "schedule_blacklist_role")
_desc = _p( _desc = _p(
@@ -495,7 +504,8 @@ class ScheduleSettings(SettingGroup):
@ScheduleConfig.register_model_setting @ScheduleConfig.register_model_setting
class BlacklistAfter(ModelData, IntegerSetting): class BlacklistAfter(ModelData, IntegerSetting):
setting_id = 'schedule_blacklist_after' setting_id = 'schedule_blacklist_after'
_set_cmd = 'configure schedule' _set_cmd = 'admin config schedule'
_write_ward = low_management_iward
_display_name = _p('guildset:schedule_blacklist_after', "schedule_blacklist_after") _display_name = _p('guildset:schedule_blacklist_after', "schedule_blacklist_after")
_desc = _p( _desc = _p(

View File

@@ -78,6 +78,7 @@ class ScheduleSettingUI(ConfigUI):
# TODO: Setting value checks # TODO: Setting value checks
await selection.response.defer() await selection.response.defer()
setting = self.get_instance(ScheduleSettings.SessionLobby) setting = self.get_instance(ScheduleSettings.SessionLobby)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
@@ -95,6 +96,7 @@ class ScheduleSettingUI(ConfigUI):
async def room_menu(self, selection: discord.Interaction, selected: ChannelSelect): async def room_menu(self, selection: discord.Interaction, selected: ChannelSelect):
await selection.response.defer() await selection.response.defer()
setting = self.get_instance(ScheduleSettings.SessionRoom) setting = self.get_instance(ScheduleSettings.SessionRoom)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
await setting.write() await setting.write()
@@ -113,6 +115,7 @@ class ScheduleSettingUI(ConfigUI):
# TODO: Consider XORing input # TODO: Consider XORing input
await selection.response.defer() await selection.response.defer()
setting = self.get_instance(ScheduleSettings.SessionChannels) setting = self.get_instance(ScheduleSettings.SessionChannels)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
@@ -158,6 +161,7 @@ class ScheduleSettingUI(ConfigUI):
async def blacklist_role_menu(self, selection: discord.Interaction, selected: RoleSelect): async def blacklist_role_menu(self, selection: discord.Interaction, selected: RoleSelect):
await selection.response.defer() await selection.response.defer()
setting = self.get_instance(ScheduleSettings.BlacklistRole) setting = self.get_instance(ScheduleSettings.BlacklistRole)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
# TODO: Warning for insufficient permissions? # TODO: Warning for insufficient permissions?
await setting.write() await setting.write()
@@ -227,7 +231,7 @@ class ScheduleSettingUI(ConfigUI):
class ScheduleDashboard(DashboardSection): class ScheduleDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:schedule|title', 'dash:schedule|title',
"Scheduled Session Configuration ({commands[configure schedule]})" "Scheduled Session Configuration ({commands[admin config schedule]})"
) )
_option_name = _p( _option_name = _p(
"dash:schedule|dropdown|placeholder", "dash:schedule|dropdown|placeholder",
@@ -248,7 +252,7 @@ class ScheduleDashboard(DashboardSection):
page.add_field( page.add_field(
name=t(_p( name=t(_p(
'dash:schedule|section:schedule_channels|name', 'dash:schedule|section:schedule_channels|name',
"Scheduled Session Channels ({commands[configure schedule]})", "Scheduled Session Channels ({commands[admin config schedule]})",
)).format(commands=self.bot.core.mention_cache), )).format(commands=self.bot.core.mention_cache),
value=table, value=table,
inline=False inline=False
@@ -258,7 +262,7 @@ class ScheduleDashboard(DashboardSection):
page.add_field( page.add_field(
name=t(_p( name=t(_p(
'dash:schedule|section:schedule_rewards|name', 'dash:schedule|section:schedule_rewards|name',
"Scheduled Session Rewards ({commands[configure schedule]})", "Scheduled Session Rewards ({commands[admin config schedule]})",
)).format(commands=self.bot.core.mention_cache), )).format(commands=self.bot.core.mention_cache),
value=table, value=table,
inline=False inline=False
@@ -268,7 +272,7 @@ class ScheduleDashboard(DashboardSection):
page.add_field( page.add_field(
name=t(_p( name=t(_p(
'dash:schedule|section:schedule_blacklist|name', 'dash:schedule|section:schedule_blacklist|name',
"Scheduled Session Blacklist ({commands[configure schedule]})", "Scheduled Session Blacklist ({commands[admin config schedule]})",
)).format(commands=self.bot.core.mention_cache), )).format(commands=self.bot.core.mention_cache),
value=table, value=table,
inline=False inline=False

View File

@@ -12,7 +12,7 @@ from core.lion_guild import VoiceMode
from utils.lib import error_embed from utils.lib import error_embed
from utils.ui import LeoUI, AButton, utc_now from utils.ui import LeoUI, AButton, utc_now
from gui.base import CardMode from gui.base import CardMode
from wards import low_management_ward from wards import high_management_ward
from . import babel from . import babel
from .data import StatsData from .data import StatsData
@@ -41,7 +41,7 @@ class StatsCog(LionCog):
self.bot.core.guild_config.register_setting(self.settings.UnrankedRoles) self.bot.core.guild_config.register_setting(self.settings.UnrankedRoles)
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.admin_config_group)
@cmds.hybrid_command( @cmds.hybrid_command(
name=_p('cmd:me', "me"), name=_p('cmd:me', "me"),
@@ -204,8 +204,7 @@ class StatsCog(LionCog):
"Time from which to start counting activity for rank badges and season leaderboards. (YYYY-MM-DD)" "Time from which to start counting activity for rank badges and season leaderboards. (YYYY-MM-DD)"
) )
) )
@appcmds.default_permissions(manage_guild=True) @high_management_ward
@low_management_ward
async def configure_statistics_cmd(self, ctx: LionContext, async def configure_statistics_cmd(self, ctx: LionContext,
season_start: Optional[str] = None): season_start: Optional[str] = None):
t = self.bot.translator.t t = self.bot.translator.t

View File

@@ -21,6 +21,7 @@ from utils.lib import MessageArgs
from core.data import CoreData from core.data import CoreData
from core.lion_guild import VoiceMode from core.lion_guild import VoiceMode
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward, high_management_iward
from . import babel from . import babel
from .data import StatsData, StatisticType from .data import StatsData, StatisticType
@@ -83,7 +84,8 @@ class StatisticsSettings(SettingGroup):
Time is assumed to be in set guild timezone (although supports +00 syntax) Time is assumed to be in set guild timezone (although supports +00 syntax)
""" """
setting_id = 'season_start' setting_id = 'season_start'
_set_cmd = 'configure statistics' _set_cmd = 'admin config statistics'
_write_ward = high_management_iward
_display_name = _p('guildset:season_start', "season_start") _display_name = _p('guildset:season_start', "season_start")
_desc = _p( _desc = _p(
@@ -155,6 +157,7 @@ class StatisticsSettings(SettingGroup):
List of roles not displayed on the leaderboard List of roles not displayed on the leaderboard
""" """
setting_id = 'unranked_roles' setting_id = 'unranked_roles'
_write_ward = high_management_iward
_display_name = _p('guildset:unranked_roles', "unranked_roles") _display_name = _p('guildset:unranked_roles', "unranked_roles")
_desc = _p( _desc = _p(
@@ -211,6 +214,7 @@ class StatisticsSettings(SettingGroup):
Default is determined by current guild mode Default is determined by current guild mode
""" """
setting_id = 'visible_stats' setting_id = 'visible_stats'
_write_ward = high_management_iward
_setting = StatTypeSetting _setting = StatTypeSetting
@@ -263,6 +267,7 @@ class StatisticsSettings(SettingGroup):
Which of the three stats to display by default Which of the three stats to display by default
""" """
setting_id = 'default_stat' setting_id = 'default_stat'
_write_ward = high_management_iward
_display_name = _p('guildset:default_stat', "default_stat") _display_name = _p('guildset:default_stat', "default_stat")
_desc = _p( _desc = _p(
@@ -294,6 +299,7 @@ class StatisticsConfigUI(ConfigUI):
""" """
await selection.response.defer(thinking=True) await selection.response.defer(thinking=True)
setting = self.instances[1] setting = self.instances[1]
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
# Don't need to refresh due to instance hooks # Don't need to refresh due to instance hooks
@@ -314,6 +320,7 @@ class StatisticsConfigUI(ConfigUI):
""" """
await selection.response.defer(thinking=True) await selection.response.defer(thinking=True)
setting = self.instances[2] setting = self.instances[2]
await setting.interaction_check(setting.parent_id, selection)
data = [StatisticType((value,)) for value in selected.values] data = [StatisticType((value,)) for value in selected.values]
setting.data = data setting.data = data
await setting.write() await setting.write()
@@ -405,7 +412,7 @@ class StatisticsConfigUI(ConfigUI):
class StatisticsDashboard(DashboardSection): class StatisticsDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:stats|title', 'dash:stats|title',
"Activity Statistics Configuration ({commands[configure statistics]})" "Activity Statistics Configuration ({commands[admin config statistics]})"
) )
_option_name = _p( _option_name = _p(
"dash:stats|dropdown|placeholder", "dash:stats|dropdown|placeholder",

View File

@@ -139,7 +139,7 @@ class TasklistCog(LionCog):
self.bot.add_view(TasklistCaller(self.bot)) self.bot.add_view(TasklistCaller(self.bot))
configcog = self.bot.get_cog('ConfigCog') configcog = self.bot.get_cog('ConfigCog')
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
@LionCog.listener('on_tasks_completed') @LionCog.listener('on_tasks_completed')
@log_wrap(action="reward tasks completed") @log_wrap(action="reward tasks completed")
@@ -984,7 +984,6 @@ class TasklistCog(LionCog):
reward=TasklistSettings.task_reward._desc, reward=TasklistSettings.task_reward._desc,
reward_limit=TasklistSettings.task_reward_limit._desc reward_limit=TasklistSettings.task_reward_limit._desc
) )
@appcmds.default_permissions(manage_guild=True)
@low_management_ward @low_management_ward
async def configure_tasklist_cmd(self, ctx: LionContext, async def configure_tasklist_cmd(self, ctx: LionContext,
reward: Optional[int] = None, reward: Optional[int] = None,

View File

@@ -13,6 +13,7 @@ from utils.lib import tabulate
from utils.ui import LeoUI, FastModal, error_handler_for, ModalRetryUI, DashboardSection from utils.ui import LeoUI, FastModal, error_handler_for, ModalRetryUI, DashboardSection
from core.data import CoreData from core.data import CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward, high_management_iward
from . import babel from . import babel
from .data import TasklistData from .data import TasklistData
@@ -28,7 +29,8 @@ class TasklistSettings(SettingGroup):
Exposed via `/configure tasklist`, and the standard configuration interface. Exposed via `/configure tasklist`, and the standard configuration interface.
""" """
setting_id = 'task_reward' setting_id = 'task_reward'
_set_cmd = 'configure tasklist' _set_cmd = 'config tasklist'
_write_ward = low_management_iward
_display_name = _p('guildset:task_reward', "task_reward") _display_name = _p('guildset:task_reward', "task_reward")
_desc = _p( _desc = _p(
@@ -68,7 +70,8 @@ class TasklistSettings(SettingGroup):
class task_reward_limit(ModelData, IntegerSetting): class task_reward_limit(ModelData, IntegerSetting):
setting_id = 'task_reward_limit' setting_id = 'task_reward_limit'
_set_cmd = 'configure tasklist' _set_cmd = 'config tasklist'
_write_ward = low_management_iward
_display_name = _p('guildset:task_reward_limit', "task_reward_limit") _display_name = _p('guildset:task_reward_limit', "task_reward_limit")
_desc = _p( _desc = _p(
@@ -109,6 +112,7 @@ class TasklistSettings(SettingGroup):
class tasklist_channels(ListData, ChannelListSetting): class tasklist_channels(ListData, ChannelListSetting):
setting_id = 'tasklist_channels' setting_id = 'tasklist_channels'
_write_ward = low_management_iward
_display_name = _p('guildset:tasklist_channels', "tasklist_channels") _display_name = _p('guildset:tasklist_channels', "tasklist_channels")
_desc = _p( _desc = _p(
@@ -317,7 +321,7 @@ class TasklistConfigUI(LeoUI):
class TasklistDashboard(DashboardSection): class TasklistDashboard(DashboardSection):
section_name = _p('dash:tasklist|name', "Tasklist Configuration ({commands[configure tasklist]})") section_name = _p('dash:tasklist|name', "Tasklist Configuration ({commands[config tasklist]})")
_option_name = _p( _option_name = _p(
"dash:tasklist|dropdown|placeholder", "dash:tasklist|dropdown|placeholder",
"Tasklist Options Panel" "Tasklist Options Panel"

View File

@@ -57,7 +57,7 @@ class VideoCog(LionCog):
"Could not load ConfigCog. VideoCog configuration will not crossload." "Could not load ConfigCog. VideoCog configuration will not crossload."
) )
else: else:
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.admin_config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()
@@ -522,7 +522,7 @@ class VideoCog(LionCog):
video_blacklist_durations=VideoSettings.VideoBlacklistDurations._desc, video_blacklist_durations=VideoSettings.VideoBlacklistDurations._desc,
video_grace_period=VideoSettings.VideoGracePeriod._desc, video_grace_period=VideoSettings.VideoGracePeriod._desc,
) )
@low_management_ward @high_management_ward
async def configure_video(self, ctx: LionContext, async def configure_video(self, ctx: LionContext,
video_blacklist: Optional[discord.Role] = None, video_blacklist: Optional[discord.Role] = None,
video_blacklist_durations: Optional[str] = None, video_blacklist_durations: Optional[str] = None,
@@ -572,4 +572,3 @@ class VideoCog(LionCog):
ui = VideoSettingUI(self.bot, ctx.guild.id, ctx.channel.id) ui = VideoSettingUI(self.bot, ctx.guild.id, ctx.channel.id)
await ui.run(ctx.interaction) await ui.run(ctx.interaction)
await ui.wait() await ui.wait()

View File

@@ -14,6 +14,7 @@ from meta.sharding import THIS_SHARD
from meta.logger import log_wrap from meta.logger import log_wrap
from core.data import CoreData from core.data import CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward, high_management_iward
from . import babel, logger from . import babel, logger
from .data import VideoData from .data import VideoData
@@ -25,6 +26,7 @@ class VideoSettings(SettingGroup):
class VideoChannels(ListData, ChannelListSetting): class VideoChannels(ListData, ChannelListSetting):
setting_id = "video_channels" setting_id = "video_channels"
_event = 'guildset_video_channels' _event = 'guildset_video_channels'
_write_ward = high_management_iward
_display_name = _p('guildset:video_channels', "video_channels") _display_name = _p('guildset:video_channels', "video_channels")
_desc = _p( _desc = _p(
@@ -101,6 +103,7 @@ class VideoSettings(SettingGroup):
class VideoBlacklist(ModelData, RoleSetting): class VideoBlacklist(ModelData, RoleSetting):
setting_id = "video_blacklist" setting_id = "video_blacklist"
_event = 'guildset_video_blacklist' _event = 'guildset_video_blacklist'
_write_ward = high_management_iward
_display_name = _p('guildset:video_blacklist', "video_blacklist") _display_name = _p('guildset:video_blacklist', "video_blacklist")
_desc = _p( _desc = _p(
@@ -158,6 +161,7 @@ class VideoSettings(SettingGroup):
class VideoBlacklistDurations(ListData, ListSetting, InteractiveSetting): class VideoBlacklistDurations(ListData, ListSetting, InteractiveSetting):
setting_id = 'video_durations' setting_id = 'video_durations'
_setting = DurationSetting _setting = DurationSetting
_write_ward = high_management_iward
_display_name = _p('guildset:video_durations', "video_blacklist_durations") _display_name = _p('guildset:video_durations', "video_blacklist_durations")
_desc = _p( _desc = _p(
@@ -217,6 +221,7 @@ class VideoSettings(SettingGroup):
class VideoGracePeriod(ModelData, DurationSetting): class VideoGracePeriod(ModelData, DurationSetting):
setting_id = "video_grace_period" setting_id = "video_grace_period"
_event = 'guildset_video_grace_period' _event = 'guildset_video_grace_period'
_write_ward = high_management_iward
_display_name = _p('guildset:video_grace_period', "video_grace_period") _display_name = _p('guildset:video_grace_period', "video_grace_period")
_desc = _p( _desc = _p(
@@ -252,6 +257,7 @@ class VideoSettings(SettingGroup):
class VideoExempt(ListData, RoleListSetting): class VideoExempt(ListData, RoleListSetting):
setting_id = "video_exempt" setting_id = "video_exempt"
_event = 'guildset_video_exempt' _event = 'guildset_video_exempt'
_write_ward = high_management_iward
_display_name = _p('guildset:video_exempt', "video_exempt") _display_name = _p('guildset:video_exempt', "video_exempt")
_desc = _p( _desc = _p(

View File

@@ -45,6 +45,7 @@ class VideoSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(VideoSettings.VideoChannels) setting = self.get_instance(VideoSettings.VideoChannels)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -70,6 +71,7 @@ class VideoSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(VideoSettings.VideoExempt) setting = self.get_instance(VideoSettings.VideoExempt)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
await selection.delete_original_response() await selection.delete_original_response()
@@ -95,6 +97,7 @@ class VideoSettingUI(ConfigUI):
await selection.response.defer(thinking=True, ephemeral=True) await selection.response.defer(thinking=True, ephemeral=True)
setting = self.get_instance(VideoSettings.VideoBlacklist) setting = self.get_instance(VideoSettings.VideoBlacklist)
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values[0] if selected.values else None setting.value = selected.values[0] if selected.values else None
if setting.value: if setting.value:
await equippable_role(self.bot, setting.value, selection.user) await equippable_role(self.bot, setting.value, selection.user)
@@ -153,7 +156,7 @@ class VideoSettingUI(ConfigUI):
class VideoDashboard(DashboardSection): class VideoDashboard(DashboardSection):
section_name = _p( section_name = _p(
"dash:video|title", "dash:video|title",
"Video Channel Settings ({commands[configure video_channels]})" "Video Channel Settings ({commands[admin config video_channels]})"
) )
_option_name = _p( _option_name = _p(
"dash:video|option|name", "dash:video|option|name",

View File

@@ -7,6 +7,7 @@ from discord import ui
from discord.ui.button import ButtonStyle, Button, button from discord.ui.button import ButtonStyle, Button, button
from discord.ui.modal import Modal from discord.ui.modal import Modal
from discord.ui.text_input import TextInput from discord.ui.text_input import TextInput
from meta.errors import UserInputError
from utils.lib import tabulate, recover_context from utils.lib import tabulate, recover_context
from utils.ui import FastModal from utils.ui import FastModal
@@ -192,6 +193,9 @@ class InteractiveSetting(BaseSetting[ParentID, SettingData, SettingValue]):
# Event handlers should be of the form Callable[ParentID, SettingData] # Event handlers should be of the form Callable[ParentID, SettingData]
_event: Optional[str] = None _event: Optional[str] = None
# Interaction ward that should be validated via interaction_check
_write_ward: Optional[Callable[[discord.Interaction], Coroutine[Any, Any, bool]]] = None
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -488,6 +492,16 @@ class InteractiveSetting(BaseSetting[ParentID, SettingData, SettingValue]):
""" """
pass pass
@classmethod
async def interaction_check(cls, parent_id, interaction: discord.Interaction, **kwargs):
if cls._write_ward is not None and not await cls._write_ward(interaction):
# TODO: Combine the check system so we can do customised errors here
t = ctx_translator.get().t
raise UserInputError(t(_p(
'setting|interaction_check|error',
"You do not have sufficient permissions to do this!"
)))
""" """
command callback for set command? command callback for set command?

View File

@@ -16,7 +16,7 @@ from meta.app import appname
from meta.monitor import ComponentMonitor, ComponentStatus, StatusLevel from meta.monitor import ComponentMonitor, ComponentStatus, StatusLevel
from utils.lib import utc_now, error_embed from utils.lib import utc_now, error_embed
from wards import low_management_ward, sys_admin_ward from wards import low_management_ward, sys_admin_ward, low_management_iward
from . import babel, logger from . import babel, logger
from .data import TextTrackerData from .data import TextTrackerData
@@ -116,7 +116,7 @@ class TextTrackerCog(LionCog):
"Attempting to load the TextTrackerCog before ConfigCog! Failed to crossload configuration group." "Attempting to load the TextTrackerCog before ConfigCog! Failed to crossload configuration group."
) )
else: else:
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()
@@ -318,7 +318,6 @@ class TextTrackerCog(LionCog):
xp_per_period=TextTrackerSettings.XPPerPeriod._desc, xp_per_period=TextTrackerSettings.XPPerPeriod._desc,
word_xp=TextTrackerSettings.WordXP._desc, word_xp=TextTrackerSettings.WordXP._desc,
) )
@appcmds.default_permissions(manage_guild=True)
@low_management_ward @low_management_ward
async def configure_text_tracking_cmd(self, ctx: LionContext, async def configure_text_tracking_cmd(self, ctx: LionContext,
xp_per_period: Optional[appcmds.Range[int, 0, 2**15]] = None, xp_per_period: Optional[appcmds.Range[int, 0, 2**15]] = None,

View File

@@ -11,6 +11,7 @@ from meta.sharding import THIS_SHARD
from meta.logger import log_wrap from meta.logger import log_wrap
from core.data import CoreData from core.data import CoreData
from babel.translator import ctx_translator from babel.translator import ctx_translator
from wards import low_management_iward
from . import babel, logger from . import babel, logger
from .data import TextTrackerData from .data import TextTrackerData
@@ -28,7 +29,8 @@ class TextTrackerSettings(SettingGroup):
""" """
class XPPerPeriod(ModelData, IntegerSetting): class XPPerPeriod(ModelData, IntegerSetting):
setting_id = 'xp_per_period' setting_id = 'xp_per_period'
_set_cmd = 'configure message_exp' _set_cmd = 'config message_exp'
_write_ward = low_management_iward
_display_name = _p('guildset:xp_per_period', "xp_per_5min") _display_name = _p('guildset:xp_per_period', "xp_per_5min")
_desc = _p( _desc = _p(
@@ -60,7 +62,8 @@ class TextTrackerSettings(SettingGroup):
class WordXP(ModelData, IntegerSetting): class WordXP(ModelData, IntegerSetting):
setting_id = 'word_xp' setting_id = 'word_xp'
_set_cmd = 'configure message_exp' _set_cmd = 'config message_exp'
_write_ward = low_management_iward
_display_name = _p('guildset:word_xp', "xp_per_100words") _display_name = _p('guildset:word_xp', "xp_per_100words")
_desc = _p( _desc = _p(
@@ -91,6 +94,7 @@ class TextTrackerSettings(SettingGroup):
class UntrackedTextChannels(ListData, ChannelListSetting): class UntrackedTextChannels(ListData, ChannelListSetting):
setting_id = 'untracked_text_channels' setting_id = 'untracked_text_channels'
_write_ward = low_management_iward
_display_name = _p('guildset:untracked_text_channels', "untracked_text_channels") _display_name = _p('guildset:untracked_text_channels', "untracked_text_channels")
_desc = _p( _desc = _p(

View File

@@ -35,6 +35,7 @@ class TextTrackerConfigUI(ConfigUI):
async def untracked_channels_menu(self, selection: discord.Interaction, selected): async def untracked_channels_menu(self, selection: discord.Interaction, selected):
await selection.response.defer() await selection.response.defer()
setting = self.instances[2] setting = self.instances[2]
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
@@ -86,7 +87,7 @@ class TextTrackerConfigUI(ConfigUI):
class TextTrackerDashboard(DashboardSection): class TextTrackerDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:text_tracking|title', 'dash:text_tracking|title',
"Message XP configuration ({commands[configure message_exp]})", "Message XP configuration ({commands[config message_exp]})",
) )
_option_name = _p( _option_name = _p(
"dash:text_tracking|dropdown|placeholder", "dash:text_tracking|dropdown|placeholder",

View File

@@ -133,7 +133,7 @@ class VoiceTrackerCog(LionCog):
"Attempting to load VoiceTrackerCog before ConfigCog! Cannot crossload configuration group." "Attempting to load VoiceTrackerCog before ConfigCog! Cannot crossload configuration group."
) )
else: else:
self.crossload_group(self.configure_group, configcog.configure_group) self.crossload_group(self.configure_group, configcog.config_group)
if self.bot.is_ready(): if self.bot.is_ready():
await self.initialise() await self.initialise()
@@ -867,7 +867,6 @@ class VoiceTrackerCog(LionCog):
hourly_live_bonus=VoiceTrackerSettings.HourlyLiveBonus._desc, hourly_live_bonus=VoiceTrackerSettings.HourlyLiveBonus._desc,
daily_voice_cap=VoiceTrackerSettings.DailyVoiceCap._desc, daily_voice_cap=VoiceTrackerSettings.DailyVoiceCap._desc,
) )
@appcmds.default_permissions(manage_guild=True)
@low_management_ward @low_management_ward
async def configure_voice_tracking_cmd(self, ctx: LionContext, async def configure_voice_tracking_cmd(self, ctx: LionContext,
hourly_reward: Optional[int] = None, # TODO: Change these to Ranges hourly_reward: Optional[int] = None, # TODO: Change these to Ranges

View File

@@ -14,6 +14,7 @@ from meta.sharding import THIS_SHARD
from meta.logger import log_wrap from meta.logger import log_wrap
from utils.lib import MessageArgs from utils.lib import MessageArgs
from utils.ui import LeoUI, ConfigUI, DashboardSection from utils.ui import LeoUI, ConfigUI, DashboardSection
from wards import low_management_iward
from core.data import CoreData from core.data import CoreData
from core.lion_guild import VoiceMode from core.lion_guild import VoiceMode
@@ -35,7 +36,8 @@ class VoiceTrackerSettings(SettingGroup):
class UntrackedChannels(ListData, ChannelListSetting): class UntrackedChannels(ListData, ChannelListSetting):
setting_id = 'untracked_channels' setting_id = 'untracked_channels'
_event = 'guildset_untracked_channels' _event = 'guildset_untracked_channels'
_set_cmd = 'configure voice_rewards' _set_cmd = 'config voice_rewards'
_write_ward = low_management_iward
_display_name = _p('guildset:untracked_channels', "untracked_channels") _display_name = _p('guildset:untracked_channels', "untracked_channels")
_desc = _p( _desc = _p(
@@ -112,7 +114,8 @@ class VoiceTrackerSettings(SettingGroup):
class HourlyReward(ModelData, IntegerSetting): class HourlyReward(ModelData, IntegerSetting):
setting_id = 'hourly_reward' setting_id = 'hourly_reward'
_event = 'on_guildset_hourly_reward' _event = 'on_guildset_hourly_reward'
_set_cmd = 'configure voice_rewards' _set_cmd = 'config voice_rewards'
_write_ward = low_management_iward
_display_name = _p('guildset:hourly_reward', "hourly_reward") _display_name = _p('guildset:hourly_reward', "hourly_reward")
_desc = _p( _desc = _p(
@@ -192,7 +195,8 @@ class VoiceTrackerSettings(SettingGroup):
""" """
setting_id = 'hourly_live_bonus' setting_id = 'hourly_live_bonus'
_event = 'on_guildset_hourly_live_bonus' _event = 'on_guildset_hourly_live_bonus'
_set_cmd = 'configure voice_rewards' _set_cmd = 'config voice_rewards'
_write_ward = low_management_iward
_display_name = _p('guildset:hourly_live_bonus', "hourly_live_bonus") _display_name = _p('guildset:hourly_live_bonus', "hourly_live_bonus")
_desc = _p( _desc = _p(
@@ -243,7 +247,8 @@ class VoiceTrackerSettings(SettingGroup):
class DailyVoiceCap(ModelData, DurationSetting): class DailyVoiceCap(ModelData, DurationSetting):
setting_id = 'daily_voice_cap' setting_id = 'daily_voice_cap'
_event = 'on_guildset_daily_voice_cap' _event = 'on_guildset_daily_voice_cap'
_set_cmd = 'configure voice_rewards' _set_cmd = 'config voice_rewards'
_write_ward = low_management_iward
_display_name = _p('guildset:daily_voice_cap', "daily_voice_cap") _display_name = _p('guildset:daily_voice_cap', "daily_voice_cap")
_desc = _p( _desc = _p(
@@ -465,6 +470,7 @@ class VoiceTrackerConfigUI(ConfigUI):
async def untracked_channels_menu(self, selection: discord.Interaction, selected): async def untracked_channels_menu(self, selection: discord.Interaction, selected):
await selection.response.defer() await selection.response.defer()
setting = self.instances[3] setting = self.instances[3]
await setting.interaction_check(setting.parent_id, selection)
setting.value = selected.values setting.value = selected.values
await setting.write() await setting.write()
@@ -528,7 +534,7 @@ class VoiceTrackerConfigUI(ConfigUI):
class VoiceTrackerDashboard(DashboardSection): class VoiceTrackerDashboard(DashboardSection):
section_name = _p( section_name = _p(
'dash:voice_tracker|title', 'dash:voice_tracker|title',
"Voice Tracker Configuration ({commands[configure voice_rewards]})" "Voice Tracker Configuration ({commands[config voice_rewards]})"
) )
_option_name = _p( _option_name = _p(
"dash:voice_tracking|dropdown|placeholder", "dash:voice_tracking|dropdown|placeholder",

View File

@@ -126,6 +126,7 @@ class ConfigUI(LeoUI):
new_data = None new_data = None
else: else:
# If this raises a UserInputError, it will be caught and the modal retried # If this raises a UserInputError, it will be caught and the modal retried
await setting.interaction_check(setting.parent_id, interaction)
new_data = await setting._parse_string(setting.parent_id, input_value) new_data = await setting._parse_string(setting.parent_id, input_value)
setting.data = new_data setting.data = new_data
modified.append(setting) modified.append(setting)