rewrite: Setting input strings and localisation.

This commit is contained in:
2023-06-06 12:57:29 +03:00
parent 809cada228
commit e1a23695ee
29 changed files with 823 additions and 236 deletions

View File

@@ -141,7 +141,10 @@ class GuildDashboard(BasePager):
for i, page in enumerate(self.pages):
for j, section in enumerate(page):
option = SelectOption(
label=t(section.section_name),
label=t(section.section_name).format(
bot=self.bot,
commands=self.bot.core.mention_cache
),
value=str(i * 10 + j)
)
options.append(option)

View File

@@ -11,7 +11,7 @@ import discord
from discord.ext import commands as cmds
from discord import app_commands as appcmds
from meta import LionBot, LionCog, LionContext
from meta import LionBot, LionCog, LionContext, ctx_bot
from meta.errors import UserInputError
from wards import low_management
from settings import ModelData
@@ -57,7 +57,6 @@ class GeneralSettings(SettingGroup):
@property
def update_message(self):
t = ctx_translator.get().t
# TODO: update_message can state time in current timezone
return t(_p(
'guildset:timezone|response',
"The guild timezone has been set to `{timezone}`."
@@ -65,8 +64,8 @@ class GeneralSettings(SettingGroup):
@property
def set_str(self):
# TODO
return '</configure general:1038560947666694144>'
bot = ctx_bot.get()
return bot.core.mention_cmd('configure general') if bot else None
class GeneralSettingsCog(LionCog):

View File

@@ -787,9 +787,23 @@ class Economy(LionCog):
"Configure LionCoin Economy"
)
)
@appcmds.rename(
allow_transfers=EconomySettings.AllowTransfers._display_name,
coins_per_xp=EconomySettings.CoinsPerXP._display_name
)
@appcmds.describe(
allow_transfers=EconomySettings.AllowTransfers._desc,
coins_per_xp=EconomySettings.CoinsPerXP._desc
)
@appcmds.choices(
allow_transfers=[
appcmds.Choice(name=EconomySettings.AllowTransfers._outputs[True], value=1),
appcmds.Choice(name=EconomySettings.AllowTransfers._outputs[False], value=0),
]
)
@cmds.check(low_management)
async def configure_economy(self, ctx: LionContext,
allow_transfers: Optional[bool] = None,
allow_transfers: Optional[appcmds.Choice[int]] = None,
coins_per_xp: Optional[appcmds.Range[int, 0, 2**15]] = None):
t = self.bot.translator.t
if not ctx.interaction:
@@ -802,7 +816,7 @@ class Economy(LionCog):
modified = []
if allow_transfers is not None:
setting_allow_transfers.data = allow_transfers
setting_allow_transfers.data = bool(allow_transfers.value)
await setting_allow_transfers.write()
modified.append(setting_allow_transfers)
if coins_per_xp is not None:

View File

@@ -10,6 +10,7 @@ from settings.groups import SettingGroup
from settings.data import ModelData, ListData
from settings.setting_types import ChannelListSetting, IntegerSetting, BoolSetting
from meta.context import ctx_bot
from meta.config import conf
from meta.sharding import THIS_SHARD
from meta.logger import log_wrap
@@ -40,6 +41,10 @@ class EconomySettings(SettingGroup):
'guildset:coins_per_xp|long_desc',
"Members will be rewarded with this many LionCoins for every 100 XP they earn."
)
_accepts = _p(
'guildset:coins_per_xp|long_desc',
"The number of coins to reward per 100 XP."
)
# This default needs to dynamically depend on the guild mode!
_default = 50
@@ -54,6 +59,11 @@ class EconomySettings(SettingGroup):
"For every **100** XP they earn, members will now be given {coin}**{amount}**."
)).format(amount=self.value, coin=conf.emojis.coin)
@property
def set_str(self):
bot = ctx_bot.get()
return bot.core.mention_cmd('configure economy') if bot else None
class AllowTransfers(ModelData, BoolSetting):
setting_id = 'allow_transfers'
@@ -64,9 +74,40 @@ class EconomySettings(SettingGroup):
)
_long_desc = _p(
'guildset:allow_transfers|long_desc',
"If disabled, members will not be able to use `/sendcoins` to transfer LionCoinds."
"If disabled, members will not be able to transfer LionCoins to each other."
)
_default = True
_model = CoreData.Guild
_column = CoreData.Guild.allow_transfers.name
_outputs = {
True: _p('guildset:allow_transfers|outputs:true', "Enabled (Coin transfers allowed.)"),
False: _p('guildset:allow_transfers|outputs:false', "Disabled (Coin transfers not allowed.)"),
}
_outputs[None] = _outputs[_default]
@property
def set_str(self):
bot = ctx_bot.get()
return bot.core.mention_cmd('configure economy') if bot else None
@property
def update_message(self):
t = ctx_translator.get().t
bot = ctx_bot.get()
if self.value:
formatted = t(_p(
'guildset:allow_transfers|set_response|set:true',
"Members will now be able to use {send_cmd} to transfer {coin}"
))
else:
formatted = t(_p(
'guildset:allow_transfers|set_response|set:false',
"Members will not be able to use {send_cmd} to transfer {coin}"
))
formatted = formatted.format(
send_cmd=bot.core.mention_cmd('send'),
coin=conf.emojis.coin
)
return formatted

View File

@@ -65,7 +65,7 @@ class EconomyConfigUI(ConfigUI):
class EconomyDashboard(DashboardSection):
section_name = _p(
'dash:economy|title',
"Economy Configuration"
"Economy Configuration ({commands[configure economy]})"
)
configui = EconomyConfigUI
setting_classes = EconomyConfigUI.setting_classes

View File

@@ -304,8 +304,8 @@ class TimerCog(LionCog):
# ----- Timer Commands -----
@cmds.hybrid_group(
name=_p('cmd:pomodoro', "pomodoro"),
desc=_p('cmd:pomodoro|desc', "Base group for all pomodoro timer commands.")
name=_p('cmd:pomodoro', "timers"),
description=_p('cmd:pomodoro|desc', "Base group for all pomodoro timer commands.")
)
@cmds.guild_only()
async def pomodoro_group(self, ctx: LionContext):
@@ -787,7 +787,7 @@ class TimerCog(LionCog):
await timer.update_status_card()
# Show the config UI
ui = TimerOptionsUI(self.bot, timer, timer_role)
ui = TimerOptionsUI(self.bot, timer, timer_role, callerid=ctx.author.id)
await ui.run(ctx.interaction)
await ui.wait()

View File

@@ -14,6 +14,7 @@ class TimerSettings(SettingGroup):
class PomodoroChannel(ModelData, ChannelSetting):
setting_id = 'pomodoro_channel'
_event = 'guildset_pomodoro_channel'
_set_cmd = 'configure pomodoro'
_display_name = _p('guildset:pomodoro_channel', "pomodoro_channel")
_desc = _p(
@@ -27,6 +28,15 @@ class TimerSettings(SettingGroup):
"If this setting is not set, pomodoro notifications will default to the "
"timer voice channel itself."
)
_notset_str = _p(
'guildset:pomodoro_channel|formatted|notset',
"Not Set (Will use timer voice channel.)"
)
_accepts = _p(
'guildset:pomodoro_channel|accepts',
"Timer notification channel name or id."
)
_model = CoreData.Guild
_column = CoreData.Guild.pomodoro_channel.name
@@ -45,3 +55,12 @@ class TimerSettings(SettingGroup):
"Pomodoro timer notifications will now default to their voice channel."
))
return resp
@property
def set_str(self) -> str:
cmdstr = super().set_str
t = ctx_translator.get().t
return t(_p(
'guildset:pomdoro_channel|set_using',
"{cmd} or channel selector below."
)).format(cmd=cmdstr)

View File

@@ -78,7 +78,7 @@ class TimerConfigUI(ConfigUI):
class TimerDashboard(DashboardSection):
section_name = _p(
'dash:pomodoro|title',
"Pomodoro Configuration"
"Pomodoro Configuration ({commands[configure pomodoro]})"
)
configui = TimerConfigUI
setting_classes = TimerConfigUI.setting_classes

View File

@@ -23,22 +23,24 @@ class RankSettings(SettingGroup):
_enum = RankType
_default = RankType.VOICE
_outputs = {
RankType.VOICE: '`Voice`',
RankType.XP: '`Exp`',
RankType.MESSAGE: '`Messages`'
RankType.VOICE: _p('guildset:rank_type|output:voice', '`Voice`'),
RankType.XP: _p('guildset:rank_type|output:xp', '`Exp`'),
RankType.MESSAGE: _p('guildset:rank_type|output:message', '`Messages`'),
}
_inputs = {
'voice': RankType.VOICE,
'study': RankType.VOICE,
'text': RankType.MESSAGE,
'message': RankType.MESSAGE,
'messages': RankType.MESSAGE,
'xp': RankType.XP,
'exp': RankType.XP
_input_formatted = {
RankType.VOICE: _p('guildset:rank_type|input_format:voice', 'Voice'),
RankType.XP: _p('guildset:rank_type|input_format:xp', 'Exp'),
RankType.MESSAGE: _p('guildset:rank_type|input_format:message', 'Messages'),
}
_input_patterns = {
RankType.VOICE: _p('guildset:rank_type|input_pattern:voice', 'voice|study'),
RankType.MESSAGE: _p('guildset:rank_type|input_pattern:voice', 'text|message|messages'),
RankType.XP: _p('guildset:rank_type|input_pattern:xp', 'xp|exp|experience'),
}
setting_id = 'rank_type'
_event = 'guildset_rank_type'
_set_cmd = 'configure ranks'
_display_name = _p('guildset:rank_type', "rank_type")
_desc = _p(
@@ -52,6 +54,10 @@ class RankSettings(SettingGroup):
"`Exp` is a measure of message activity, and "
"`Message` is a simple count of messages sent."
)
_accepts = _p(
'guildset:rank_type|accepts',
"Voice/Exp/Messages"
)
_model = CoreData.Guild
_column = CoreData.Guild.rank_type.name
@@ -76,6 +82,15 @@ class RankSettings(SettingGroup):
))
return resp
@property
def set_str(self) -> str:
cmdstr = super().set_str
t = ctx_translator.get().t
return t(_p(
'guildset:rank_channel|set_using',
"{cmd} or option menu below."
)).format(cmd=cmdstr)
class RankChannel(ModelData, ChannelSetting):
"""
Channel to send Rank notifications.
@@ -83,6 +98,7 @@ class RankSettings(SettingGroup):
If DMRanks is set, this will only be used when the target user has disabled DM notifications.
"""
setting_id = 'rank_channel'
_set_cmd = 'configure ranks'
_display_name = _p('guildset:rank_channel', "rank_channel")
_desc = _p(
@@ -95,14 +111,44 @@ class RankSettings(SettingGroup):
"If `dm_ranks` is enabled, this channel will only be used when the user has opted not to receive "
"DM notifications, or is otherwise unreachable."
)
_accepts = _p(
'guildset:rank_channel|accepts',
"Rank notification channel name or id."
)
_model = CoreData.Guild
_column = CoreData.Guild.rank_channel.name
@property
def update_message(self) -> str:
t = ctx_translator.get().t
value = self.value
if value is not None:
resp = t(_p(
'guildset:rank_channel|set_response|set',
"Rank update messages will be sent to {channel}."
)).format(channel=value.mention)
else:
resp = t(_p(
'guildset:rank_channel|set_response|unset',
"Rank update messages will be ignored or sent via DM (if `dm_ranks` is enabled)."
))
return resp
@property
def set_str(self) -> str:
cmdstr = super().set_str
t = ctx_translator.get().t
return t(_p(
'guildset:rank_channel|set_using',
"{cmd} or channel selector below."
)).format(cmd=cmdstr)
class DMRanks(ModelData, BoolSetting):
"""
Whether to DM rank notifications.
"""
setting_id = 'dm_ranks'
_set_cmd = 'configure ranks'
_display_name = _p('guildset:dm_ranks', "dm_ranks")
_desc = _p(
@@ -114,6 +160,21 @@ class RankSettings(SettingGroup):
"If enabled, congratulatory messages for rank advancement will be direct messaged to the user, "
"instead of being sent to the configured `rank_channel`."
)
_default = True
_model = CoreData.Guild
_column = CoreData.Guild.dm_ranks.name
@property
def update_message(self):
t = ctx_translator.get().t
if self.data:
return t(_p(
'guildset:dm_ranks|response:true',
"I will direct message members upon rank advancement."
))
else:
return t(_p(
'guildset:dm_ranks|response:false',
"I will never direct message members upon rank advancement."
))

View File

@@ -155,7 +155,7 @@ class RankConfigUI(ConfigUI):
class RankDashboard(DashboardSection):
section_name = _p(
'dash:rank|title',
"Rank Configuration",
"Rank Configuration ({commands[configure ranks]})",
)
configui = RankConfigUI
setting_classes = RankConfigUI.setting_classes

View File

@@ -15,6 +15,7 @@ class RoomSettings(SettingGroup):
class Category(ModelData, ChannelSetting):
setting_id = 'rooms_category'
_event = 'guildset_rooms_category'
_set_cmd = 'configure rooms'
_display_name = _p(
'guildset:room_category', "rooms_category"
@@ -31,6 +32,10 @@ class RoomSettings(SettingGroup):
"I must have permission to create new channels in this category, "
"as well as to manage permissions."
)
_accepts = _p(
'guildset:room_category|accepts',
"Private room category name or id."
)
_model = CoreData.Guild
_column = CoreData.Guild.renting_category.name
@@ -53,9 +58,19 @@ class RoomSettings(SettingGroup):
)).format(channel=self.value.mention)
return resp
@property
def set_str(self) -> str:
cmdstr = super().set_str
t = ctx_translator.get().t
return t(_p(
'guildset:room_category|set_using',
"{cmd} or category selector below."
)).format(cmd=cmdstr)
class Rent(ModelData, IntegerSetting):
setting_id = 'rooms_price'
_event = 'guildset_rooms_price'
_set_cmd = 'configure rooms'
_display_name = _p(
'guildset:rooms_price', "room_rent"
@@ -68,6 +83,10 @@ class RoomSettings(SettingGroup):
'guildset:rooms_rent|long_desc',
"Members will be charged this many LionCoins for each day they rent a private room."
)
_accepts = _p(
'guildset:rooms_rent|accepts',
"Number of LionCoins charged per day for a private room."
)
_default = 1000
_model = CoreData.Guild
@@ -88,6 +107,7 @@ class RoomSettings(SettingGroup):
class MemberLimit(ModelData, IntegerSetting):
setting_id = 'rooms_slots'
_event = 'guildset_rooms_slots'
_set_cmd = 'configure rooms'
_display_name = _p('guildset:rooms_slots', "room_member_cap")
_desc = _p(
@@ -100,6 +120,10 @@ class RoomSettings(SettingGroup):
"or through the `/room invite` command. "
"This setting limits the maximum number of members a private room may hold."
)
_accepts = _p(
'guildset:rooms_slots|accepts',
"Maximum number of members allowed per private room."
)
_default = 25
_model = CoreData.Guild
@@ -117,6 +141,7 @@ class RoomSettings(SettingGroup):
class Visible(ModelData, BoolSetting):
setting_id = 'rooms_visible'
_event = 'guildset_rooms_visible'
_set_cmd = 'configure rooms'
_display_name = _p('guildset:rooms_visible', "room_visibility")
_desc = _p(
@@ -129,6 +154,21 @@ class RoomSettings(SettingGroup):
"enabled for the `@everyone` role."
)
_default = False
_accepts = _p('guildset:rooms_visible|accepts', "Visible/Invisible")
_outputs = {
True: _p('guildset:rooms_visible|output:true', "Visible"),
False: _p('guildset:rooms_visible|output:false', "Invisible"),
}
_outputs[None] = _outputs[_default]
_truthy = _p(
'guildset:rooms_visible|parse:truthy_values',
"visible|enabled|yes|true|on|enable|1"
)
_falsey = _p(
'guildset:rooms_visible|parse:falsey_values',
'invisible|disabled|no|false|off|disable|0'
)
_model = CoreData.Guild
_column = CoreData.Guild.renting_visible.name
@@ -148,6 +188,15 @@ class RoomSettings(SettingGroup):
))
return resp
@property
def set_str(self) -> str:
cmdstr = super().set_str
t = ctx_translator.get().t
return t(_p(
'guildset:rooms_visible|set_using',
"{cmd} or toggle below."
)).format(cmd=cmdstr)
model_settings = (
Category,
Rent,

View File

@@ -95,7 +95,7 @@ class RoomSettingUI(ConfigUI):
class RoomDashboard(DashboardSection):
section_name = _p(
'dash:rooms|title',
"Private Room Configuration"
"Private Room Configuration ({commands[configure rooms]})"
)
configui = RoomSettingUI
setting_classes = RoomSettingUI.setting_classes

View File

@@ -14,7 +14,8 @@ from settings.groups import SettingGroup
from meta import conf, LionBot
from meta.context import ctx_bot
from utils.lib import tabulate
from meta.errors import UserInputError
from utils.lib import tabulate, utc_now
from utils.ui import ConfigUI, FastModal, error_handler_for, ModalRetryUI
from utils.lib import MessageArgs
from core.data import CoreData
@@ -33,16 +34,24 @@ class StatTypeSetting(EnumSetting):
"""
_enum = StatisticType
_outputs = {
StatisticType.VOICE: '`Voice`',
StatisticType.TEXT: '`Text`',
StatisticType.ANKI: '`Anki`'
StatisticType.VOICE: _p('settype:stat|output:voice', "`Voice`"),
StatisticType.TEXT: _p('settype:stat|output:text', "`Text`"),
StatisticType.ANKI: _p('settype:stat|output:anki', "`Anki`"),
}
_inputs = {
'voice': StatisticType.VOICE,
'study': StatisticType.VOICE,
'text': StatisticType.TEXT,
'anki': StatisticType.ANKI
_input_formatted = {
StatisticType.VOICE: _p('settype:stat|input_format:voice', "Voice"),
StatisticType.TEXT: _p('settype:stat|input_format:text', "Text"),
StatisticType.ANKI: _p('settype:stat|input_format:anki', "Anki"),
}
_input_patterns = {
StatisticType.VOICE: _p('settype:stat|input_pattern:voice', "voice|study"),
StatisticType.TEXT: _p('settype:stat|input_pattern:text', "text|messages"),
StatisticType.ANKI: _p('settype:stat|input_pattern:anki', "anki"),
}
_accepts = _p(
'settype:state|accepts',
'Voice/Text/Anki'
)
class StatisticsSettings(SettingGroup):
@@ -74,6 +83,7 @@ class StatisticsSettings(SettingGroup):
Time is assumed to be in set guild timezone (although supports +00 syntax)
"""
setting_id = 'season_start'
_set_cmd = 'configure statistics'
_display_name = _p('guildset:season_start', "season_start")
_desc = _p(
@@ -86,11 +96,17 @@ class StatisticsSettings(SettingGroup):
"and the leaderboard will display activity since this time by default. "
"Unset to disable seasons and use all-time statistics instead."
)
_accepts = _p(
'guildset:season_start|accepts',
"The season start time in the form YYYY-MM-DD HH:MM"
)
_notset_str = _p(
'guildset:season_start|notset',
"Not Set (Using all-time statistics)"
)
_model = CoreData.Guild
_column = CoreData.Guild.season_start.name
# TODO: Offer to update badge ranks when this changes?
# TODO: Don't allow future times?
@classmethod
async def _timezone_from_id(cls, guildid, **kwargs):
@@ -98,6 +114,38 @@ class StatisticsSettings(SettingGroup):
lguild = await bot.core.lions.fetch_guild(guildid)
return lguild.timezone
@classmethod
async def _parse_string(cls, parent_id, string, **kwargs):
parsed = await super()._parse_string(parent_id, string, **kwargs)
if parsed is not None and parsed > utc_now():
t = ctx_translator.get().t
raise UserInputError(t(_p(
'guildset:season_start|parse|error:future_time',
"Provided season start time {timestamp} is in the future!"
)).format(timestamp=f"<t:{int(parsed.timestamp())}>"))
@property
def update_message(self) -> str:
t = ctx_translator.get().t
bot = ctx_bot.get()
value = self.value
if value is not None:
resp = t(_p(
'guildset:season_start|set_response|set',
"The leaderboard season and activity ranks will now count from {timestamp}. "
"Member ranks will update when they are next active. Use {rank_cmd} to refresh immediately."
)).format(
timestamp=self.formatted,
rank_cmd=bot.core.mention_cmd('ranks')
)
else:
resp = t(_p(
'guildset:season_start|set_response|unset',
"The leaderboard and activity ranks will now count all-time statistics. "
"Member ranks will update when they are next active. Use {rank_cmd} to refresh immediately."
)).format(rank_cmd=bot.core.mention_cmd('ranks'))
return resp
class UnrankedRoles(ListData, RoleListSetting):
"""
List of roles not displayed on the leaderboard
@@ -113,6 +161,10 @@ class StatisticsSettings(SettingGroup):
'guildset:unranked_roles|long_desc',
"When set, members with *any* of these roles will not appear on the /leaderboard ranking list."
)
_accepts = _p(
'guildset:unranked_roles|accepts',
"Comma separated list of unranked role names or ids."
)
_default = None
_table_interface = StatsData.unranked_roles
@@ -124,7 +176,29 @@ class StatisticsSettings(SettingGroup):
@property
def set_str(self):
return "Role selector below"
t = ctx_translator.get().t
return t(_p(
'guildset:unranked_roles|set_using',
"Role selector below."
))
@property
def update_message(self) -> str:
t = ctx_translator.get().t
value = self.value
if value is not None:
resp = t(_p(
'guildset:unranked_roles|set_response|set',
"Members of the following roles will not appear on the leaderboard: {roles}"
)).format(
roles=self.formatted
)
else:
resp = t(_p(
'guildset:unranked_roles|set_response|unset',
"You have cleared the unranked role list."
))
return resp
class VisibleStats(ListData, ListSetting, InteractiveSetting):
"""
@@ -145,6 +219,10 @@ class StatisticsSettings(SettingGroup):
'guildset:visible_stats|desc',
"Choose which statistics types to display in the leaderboard and statistics commands."
)
_accepts = _p(
'guildset:visible_stats|accepts',
"Voice, Text, Anki"
)
# TODO: Format VOICE as STUDY when possible?
_default = [
@@ -159,6 +237,23 @@ class StatisticsSettings(SettingGroup):
_cache = {}
@property
def set_str(self):
t = ctx_translator.get().t
return t(_p(
'guildset:visible_stats|set_using',
"Option menu below."
))
@property
def update_message(self) -> str:
t = ctx_translator.get().t
resp = t(_p(
'guildset:visible_stats|set_response',
"Members will be able to view the following statistics types: {types}"
)).format(types=self.formatted)
return resp
class DefaultStat(ModelData, StatTypeSetting):
"""
Which of the three stats to display by default

View File

@@ -1,12 +1,14 @@
from .exec_cog import Exec
from .blacklists import Blacklists
from .guild_log import GuildLog
from .presence import PresenceCtrl
from .dash import LeoSettings
from babel.translator import LocalBabel
babel = LocalBabel('sysadmin')
async def setup(bot):
from .exec_cog import Exec
from .blacklists import Blacklists
from .guild_log import GuildLog
from .presence import PresenceCtrl
from .dash import LeoSettings
await bot.add_cog(LeoSettings(bot))
await bot.add_cog(Blacklists(bot))

View File

@@ -23,6 +23,10 @@ from settings.groups import SettingGroup
from wards import sys_admin
from . import babel
_p = babel._p
logger = logging.getLogger(__name__)
@@ -104,49 +108,93 @@ class PresenceSettings(SettingGroup):
"""
Control the bot status and activity.
"""
_title = "Presence Settings ({bot.core.cmd_name_cache[presence].mention})"
_title = "Presence Settings ({bot.core.mention_cache[presence]})"
class PresenceStatus(ModelData, EnumSetting[str, AppStatus]):
setting_id = 'presence_status'
display_name = 'online_status'
desc = "Bot status indicator"
long_desc = "Whether the bot account displays as online, idle, dnd, or offline."
accepts = "One of 'online', 'idle', 'dnd', or 'offline'."
_display_name = _p('botset:presence_status', 'online_status')
_desc = _p('botset:presence_status|desc', "Bot status indicator")
_long_desc = _p(
'botset:presence_status|long_desc',
"Whether the bot account displays as online, idle, dnd, or offline."
)
_accepts = _p(
'botset:presence_status|accepts',
"Online/Idle/Dnd/Offline"
)
_model = PresenceData.AppPresence
_column = PresenceData.AppPresence.online_status.name
_create_row = True
_enum = AppStatus
_outputs = {item: item.value[1] for item in _enum}
_inputs = {item.name: item for item in _enum}
_outputs = {
AppStatus.online: _p('botset:presence_status|output:online', "**Online**"),
AppStatus.idle: _p('botset:presence_status|output:idle', "**Idle**"),
AppStatus.dnd: _p('botset:presence_status|output:dnd', "**Do Not Disturb**"),
AppStatus.offline: _p('botset:presence_status|output:offline', "**Offline**"),
}
_input_formatted = {
AppStatus.online: _p('botset:presence_status|input_format:online', "Online"),
AppStatus.idle: _p('botset:presence_status|input_format:idle', "Idle"),
AppStatus.dnd: _p('botset:presence_status|input_format:dnd', "DND"),
AppStatus.offline: _p('botset:presence_status|input_format:offline', "Offline"),
}
_input_patterns = {
AppStatus.online: _p('botset:presence_status|input_pattern:online', "on|online"),
AppStatus.idle: _p('botset:presence_status|input_pattern:idle', "idle"),
AppStatus.dnd: _p('botset:presence_status|input_pattern:dnd', "do not disturb|dnd"),
AppStatus.offline: _p('botset:presence_status|input_pattern:offline', "off|offline|invisible"),
}
_default = AppStatus.online
class PresenceType(ModelData, EnumSetting[str, AppActivityType]):
setting_id = 'presence_type'
display_name = 'activity_type'
desc = "Type of presence activity"
long_desc = "Whether the bot activity is shown as 'Listening', 'Playing', or 'Watching'."
accepts = "One of 'listening', 'playing', 'watching', or 'streaming'."
_display_name = _p('botset:presence_type', 'activity_type')
_desc = _p('botset:presence_type|desc', "Type of presence activity")
_long_desc = _p(
'botset:presence_type|long_desc',
"Whether the bot activity is shown as 'Listening', 'Playing', or 'Watching'."
)
_accepts = _p(
'botset:presence_type|accepts',
"Listening/Playing/Watching/Streaming"
)
_model = PresenceData.AppPresence
_column = PresenceData.AppPresence.activity_type.name
_create_row = True
_enum = AppActivityType
_outputs = {item: item.value[1] for item in _enum}
_inputs = {item.name: item for item in _enum}
_outputs = {
AppActivityType.watching: _p('botset:presence_type|output:watching', "**Watching**"),
AppActivityType.listening: _p('botset:presence_type|output:listening', "**Listening**"),
AppActivityType.playing: _p('botset:presence_type|output:playing', "**Playing**"),
AppActivityType.streaming: _p('botset:presence_type|output:streaming', "**Streaming**"),
}
_input_formats = {
AppActivityType.watching: _p('botset:presence_type|input_format:watching', "Watching"),
AppActivityType.listening: _p('botset:presence_type|input_format:listening', "Listening"),
AppActivityType.playing: _p('botset:presence_type|input_format:playing', "Playing"),
AppActivityType.streaming: _p('botset:presence_type|input_format:streaming', "Streaming"),
}
_input_patterns = {
AppActivityType.watching: _p('botset:presence_type|input_pattern:watching', "watching"),
AppActivityType.listening: _p('botset:presence_type|input_pattern:listening', "listening"),
AppActivityType.playing: _p('botset:presence_type|input_pattern:playing', "playing"),
AppActivityType.streaming: _p('botset:presence_type|input_pattern:streaming', "streaming"),
}
_default = AppActivityType.watching
class PresenceName(ModelData, StringSetting[str]):
setting_id = 'presence_name'
display_name = 'activity_name'
desc = "Name of the presence activity"
long_desc = "Presence activity name."
accepts = "Any string."
_display_name = _p('botset:presence_name', 'activity_name')
_desc = _p("botset:presence_name|desc", "Name of the presence activity")
_long_desc = _p("botset:presence_name|long_desc", "Presence activity name.")
_accepts = _p('botset:presence_name|accepts', "The name of the activity to show.")
_model = PresenceData.AppPresence
_column = PresenceData.AppPresence.activity_name.name

View File

@@ -8,7 +8,7 @@ from settings import ListData, ModelData
from settings.setting_types import StringSetting, BoolSetting, ChannelListSetting, IntegerSetting
from settings.groups import SettingGroup
from meta import conf, LionBot
from meta import conf, LionBot, ctx_bot
from utils.lib import tabulate
from utils.ui import LeoUI, FastModal, error_handler_for, ModalRetryUI, DashboardSection
from core.data import CoreData
@@ -28,6 +28,7 @@ class TasklistSettings(SettingGroup):
Exposed via `/configure tasklist`, and the standard configuration interface.
"""
setting_id = 'task_reward'
_set_cmd = 'configure tasklist'
_display_name = _p('guildset:task_reward', "task_reward")
_desc = _p(
@@ -38,6 +39,10 @@ class TasklistSettings(SettingGroup):
'guildset:task_reward|long_desc',
"The number of coins members will be rewarded each time they complete a task on their tasklist."
)
_accepts = _p(
'guildset:task_reward|accepts',
"The number of LionCoins to reward per task."
)
_default = 50
_model = CoreData.Guild
@@ -51,20 +56,19 @@ class TasklistSettings(SettingGroup):
"Members will now be rewarded {coin}**{amount}** for each completed task."
)).format(coin=conf.emojis.coin, amount=self.data)
@property
def set_str(self):
return '</configure tasklist:1038560947666694144>'
@classmethod
def _format_data(cls, parent_id, data, **kwargs):
if data is not None:
return "{coin}**{amount}** per task.".format(
coin=conf.emojis.coin,
amount=data
)
t = ctx_translator.get().t
formatted = t(_p(
'guildset:task_reward|formatted',
"{coin}**{amount}** per task."
)).format(coin=conf.emojis.coin, amount=data)
return formatted
class task_reward_limit(ModelData, IntegerSetting):
setting_id = 'task_reward_limit'
_set_cmd = 'configure tasklist'
_display_name = _p('guildset:task_reward_limit', "task_reward_limit")
_desc = _p(
@@ -76,6 +80,10 @@ class TasklistSettings(SettingGroup):
"Maximum number of times in each 24h period that members will be rewarded "
"for completing a task."
)
_accepts = _p(
'guildset:task_reward_limit|accepts',
"The maximum number of tasks to reward LC for per 24h."
)
_default = 10
_model = CoreData.Guild
@@ -89,16 +97,15 @@ class TasklistSettings(SettingGroup):
"Members will now be rewarded for task completion at most **{amount}** times per 24h."
)).format(amount=self.data)
@property
def set_str(self):
return '</configure tasklist:1038560947666694144>'
@classmethod
def _format_data(cls, parent_id, data, **kwargs):
if data is not None:
return "`{number}` per 24 hours.".format(
number=data
)
t = ctx_translator.get().t
formatted = t(_p(
'guildset:task_reward_limit|formatted',
"`{number}` per 24 hours."
)).format(number=data)
return formatted
class tasklist_channels(ListData, ChannelListSetting):
setting_id = 'tasklist_channels'
@@ -113,6 +120,10 @@ class TasklistSettings(SettingGroup):
"If set, members will only be able to open their tasklist in these channels.\n"
"If a category is selected, this will allow all channels under that category."
)
_accepts = _p(
'guildset:tasklist_channels|accepts',
"Comma separated list of tasklist channel names or ids."
)
_default = None
_table_interface = TasklistData.channels
@@ -122,14 +133,32 @@ class TasklistSettings(SettingGroup):
_cache = {}
@property
def update_message(self):
t = ctx_translator.get().t
if self.data:
resp = t(_p(
'guildset:tasklist_channels|set_response|set',
"Members may now open their tasklist in the following channels: {channels}"
)).format(channels=self.formatted)
else:
resp = t(_p(
'guildset:tasklist_channels|set_response|unset',
"Members may now open their tasklist in any channel."
))
return resp
@property
def set_str(self):
return "Channel selector below."
t = ctx_translator.get().t
return t(_p(
'guildset:tasklist_channels|set_using',
"Channel selector below."
))
class TasklistConfigUI(LeoUI):
# TODO: Back option to global guild config
# TODO: Cohesive edit
# TODO: Migrate to ConfigUI
_listening = {}
setting_classes = (
TasklistSettings.task_reward,
@@ -286,6 +315,6 @@ class TasklistConfigUI(LeoUI):
class TasklistDashboard(DashboardSection):
section_name = _p('dash:tasklist|name', "Tasklist Configuration")
section_name = _p('dash:tasklist|name', "Tasklist Configuration ({commands[configure tasklist]})")
configui = TasklistConfigUI
setting_classes = configui.setting_classes

View File

@@ -33,6 +33,7 @@ class UserConfigSettings(SettingGroup):
and several other components such as reminder times.
"""
setting_id = 'timezone'
_set_cmd = 'my timezone'
_display_name = _p('userset:timezone', "timezone")
_desc = _p(