rewrite: Ward refactor.

This commit is contained in:
2023-06-06 14:27:57 +03:00
parent e1a23695ee
commit 4bfc240530
21 changed files with 154 additions and 59 deletions

View File

@@ -13,7 +13,7 @@ from discord.ui.button import ButtonStyle
from meta import LionBot, LionCog, LionContext
from meta.errors import UserInputError
from utils.ui import AButton, AsComponents
from wards import low_management
from wards import low_management_ward
from .translator import ctx_locale, ctx_translator, SOURCE_LOCALE
from . import babel
@@ -115,7 +115,8 @@ class BabelCog(LionCog):
force_language=LocaleSettings.ForceLocale._display_name
)
@appcmds.guild_only() # Can be removed when attached as a subcommand
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def cmd_configure_language(self, ctx: LionContext,
language: Optional[str] = None,
force_language: Optional[appcmds.Choice[int]] = None):

View File

@@ -28,6 +28,7 @@ class ConfigCog(LionCog):
name=_p('group:configure', "configure"),
)
@appcmds.guild_only
@appcmds.default_permissions(manage_guild=True)
async def configure_group(self, ctx: LionContext):
"""
Bare command group, has no function.

View File

@@ -25,6 +25,7 @@ class DashCog(LionCog):
description="At-a-glance view of the server's configuration."
)
@appcmds.guild_only
@appcmds.default_permissions(manage_guild=True)
async def dashboard_cmd(self, ctx: LionContext):
ui = GuildDashboard(self.bot, ctx.guild, ctx.author.id, ctx.channel.id)
await ui.run(ctx.interaction)

View File

@@ -13,7 +13,7 @@ from discord import app_commands as appcmds
from meta import LionBot, LionCog, LionContext, ctx_bot
from meta.errors import UserInputError
from wards import low_management
from wards import low_management_ward
from settings import ModelData
from settings.setting_types import TimezoneSetting
from settings.groups import SettingGroup
@@ -101,7 +101,8 @@ class GeneralSettingsCog(LionCog):
timezone=GeneralSettings.Timezone._desc
)
@appcmds.guild_only()
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def cmd_configure_general(self, ctx: LionContext,
timezone: Optional[str] = None):
t = self.bot.translator.t

View File

@@ -11,7 +11,7 @@ from data import ORDER
from utils.ui import Confirm, Pager
from utils.lib import error_embed, MessageArgs, utc_now
from wards import low_management
from wards import low_management_ward
from constants import MAX_COINS
from . import babel, logger
@@ -801,7 +801,8 @@ class Economy(LionCog):
appcmds.Choice(name=EconomySettings.AllowTransfers._outputs[False], value=0),
]
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_economy(self, ctx: LionContext,
allow_transfers: Optional[appcmds.Choice[int]] = None,
coins_per_xp: Optional[appcmds.Range[int, 0, 2**15]] = None):

View File

@@ -31,6 +31,6 @@ class MetaCog(LionCog):
ctx.bot,
ctx.author,
ctx.guild,
show_admin=await low_management(ctx),
show_admin=await low_management(ctx.bot, ctx.author),
)
await ui.run(ctx.interaction)

View File

@@ -11,7 +11,7 @@ from meta.logger import log_wrap
from meta.sharding import THIS_SHARD
from utils.lib import utc_now
from wards import low_management
from wards import low_management_ward
from . import babel, logger
from .data import TimerData
@@ -807,7 +807,8 @@ class TimerCog(LionCog):
@appcmds.describe(
pomodoro_channel=TimerSettings.PomodoroChannel._desc
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_pomodoro_command(self, ctx: LionContext,
pomodoro_channel: Optional[discord.VoiceChannel | discord.TextChannel] = None):
t = self.bot.translator.t

View File

@@ -9,7 +9,7 @@ from discord.app_commands.transformers import AppCommandOptionType
from cachetools import LRUCache
from meta import LionBot, LionContext, LionCog
from wards import high_management
from wards import high_management_ward
from core.data import RankType
from utils.ui import ChoicedEnum, Transformed
from utils.lib import utc_now, replace_multiple
@@ -435,7 +435,8 @@ class RankCog(LionCog):
# ---------- Commands ----------
@cmds.hybrid_command(name=_p('cmd:ranks', "ranks"))
@cmds.check(high_management)
@appcmds.default_permissions(administrator=True)
@high_management_ward
async def ranks_cmd(self, ctx: LionContext):
"""
Command to access the Rank Overview UI.
@@ -472,7 +473,8 @@ class RankCog(LionCog):
dm_ranks=RankSettings.DMRanks._desc,
rank_channel=RankSettings.RankChannel._desc,
)
@cmds.check(high_management)
@appcmds.default_permissions(administrator=True)
@high_management_ward
async def configure_ranks_cmd(self, ctx: LionContext,
rank_type: Optional[Transformed[RankTypeChoice, AppCommandOptionType.string]] = None,
dm_ranks: Optional[bool] = None,

View File

@@ -5,11 +5,11 @@ from discord.ui.select import select, ChannelSelect, Select, SelectOption
from discord.ui.button import button, Button, ButtonStyle
from meta import LionBot
from wards import i_high_management
from wards import high_management_iward
from core.data import RankType
from utils.ui import ConfigUI, DashboardSection
from utils.lib import MessageArgs
from utils.lib import MessageArgs, error_embed
from ..settings import RankSettings
from .. import babel, logger
@@ -31,7 +31,20 @@ class RankConfigUI(ConfigUI):
super().__init__(bot, guildid, channelid, **kwargs)
async def interaction_check(self, interaction: discord.Interaction) -> bool:
return await i_high_management(interaction)
passed = await high_management_iward(interaction)
if passed:
return True
else:
await interaction.response.send_message(
embed=error_embed(
self.bot.translator.t(_p(
'ui:rankconfigui|check|not_permitted',
"You have insufficient server permissions to use this UI!"
))
),
ephemeral=True
)
return False
# ----- UI Components -----

View File

@@ -16,7 +16,7 @@ from utils.ui import Confirm
from constants import MAX_COINS
from core.data import CoreData
from wards import low_management
from wards import low_management_ward
from . import babel, logger
from .data import RoomData
@@ -888,7 +888,8 @@ class RoomCog(LionCog):
@appcmds.describe(
**{setting.setting_id: setting._desc for setting in RoomSettings.model_settings}
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_rooms_cmd(self, ctx: LionContext,
rooms_category: Optional[discord.CategoryChannel] = None,
rooms_price: Optional[Range[int, 0, MAX_COINS]] = None,

View File

@@ -72,6 +72,7 @@ from discord import app_commands as appcmds
from meta import LionBot, LionCog, LionContext
from utils import ui
from utils.lib import error_embed
from wards import low_management_ward
from . import babel
@@ -106,6 +107,9 @@ class Shopping(LionCog):
@cmds.hybrid_group(
name=_p('group:editshop', 'editshop')
)
@appcmds.guild_only
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def editshop_group(self, ctx: LionContext):
return

View File

@@ -9,7 +9,7 @@ from discord.ui.button import ButtonStyle
from meta import LionBot, LionCog, LionContext
from utils.lib import error_embed
from utils.ui import LeoUI, AButton
from wards import low_management
from wards import low_management_ward
from . import babel
from .data import StatsData
@@ -97,7 +97,8 @@ class StatsCog(LionCog):
"Time from which to start counting activity for rank badges and season leadeboards."
)
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_statistics_cmd(self, ctx: LionContext,
season_start: Optional[str] = None):
t = self.bot.translator.t

View File

@@ -20,7 +20,7 @@ from meta.app import shard_talk
from utils.ui import ChoicedEnum, Transformed, FastModal, LeoUI, error_handler_for, ModalRetryUI
from utils.lib import EmbedField, tabulate, MessageArgs, parse_ids, error_embed
from wards import sys_admin
from wards import sys_admin_ward
logger = logging.getLogger(__name__)
@@ -168,7 +168,7 @@ class Blacklists(LionCog):
name="blacklist",
description="Display and modify the user and guild blacklists."
)
@cmds.check(sys_admin)
@sys_admin_ward
async def blacklist_cmd(
self,
ctx: LionContext,

View File

@@ -7,7 +7,7 @@ import discord.ext.commands as cmds
from meta import LionBot, LionCog, LionContext
from meta.app import appname
from wards import sys_admin
from wards import sys_admin_ward
from settings.groups import SettingGroup
@@ -23,7 +23,7 @@ class LeoSettings(LionCog):
@cmds.hybrid_group(
name="leo"
)
@cmds.check(sys_admin)
@sys_admin_ward
async def leo_group(self, ctx: LionContext):
"""
Base command group for global leo-only functions.
@@ -35,7 +35,7 @@ class LeoSettings(LionCog):
name='dashboard',
description="Global setting dashboard"
)
@cmds.check(sys_admin)
@sys_admin_ward
async def dash_cmd(self, ctx: LionContext):
embed = discord.Embed(
title="System Admin Dashboard",
@@ -56,7 +56,7 @@ class LeoSettings(LionCog):
name='configure',
description="Leo Configuration Group"
)
@cmds.check(sys_admin)
@sys_admin_ward
async def leo_configure_group(self, ctx: LionContext):
"""
Base command group for global configuration of Leo.

View File

@@ -249,7 +249,7 @@ class Exec(LionCog):
self.talk_async = shard_talk.register_route('exec')(_async)
async def cog_check(self, ctx: LionContext) -> bool: # type: ignore
return await sys_admin(ctx)
return await sys_admin(ctx.bot, ctx.author.id)
@commands.hybrid_command(
name=_('async'),

View File

@@ -21,7 +21,7 @@ from settings.data import ModelData
from settings.setting_types import EnumSetting, StringSetting
from settings.groups import SettingGroup
from wards import sys_admin
from wards import sys_admin_ward
from . import babel
@@ -376,7 +376,7 @@ class PresenceCtrl(LionCog):
name="presence",
description="Globally set the bot status and activity."
)
@cmds.check(sys_admin)
@sys_admin_ward
@appcmds.describe(
status="Online status (online | idle | dnd | offline)",
type="Activity type (watching | listening | playing | streaming)",

View File

@@ -12,7 +12,7 @@ from utils.lib import utc_now, error_embed
from utils.ui import ChoicedEnum, Transformed
from data import Condition, NULL
from wards import low_management
from wards import low_management_ward
from . import babel, logger
from .data import TasklistData
@@ -712,7 +712,8 @@ class TasklistCog(LionCog):
reward=TasklistSettings.task_reward._desc,
reward_limit=TasklistSettings.task_reward_limit._desc
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_tasklist_cmd(self, ctx: LionContext,
reward: Optional[int] = None,
reward_limit: Optional[int] = None):

View File

@@ -15,7 +15,7 @@ from meta.sharding import THIS_SHARD
from meta.app import appname
from utils.lib import utc_now, error_embed
from wards import low_management
from wards import low_management_ward
from . import babel, logger
from .data import TextTrackerData
@@ -260,7 +260,8 @@ class TextTrackerCog(LionCog):
xp_per_period=TextTrackerSettings.XPPerPeriod._desc,
word_xp=TextTrackerSettings.WordXP._desc,
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_text_tracking_cmd(self, ctx: LionContext,
xp_per_period: Optional[appcmds.Range[int, 0, 2**15]] = None,
word_xp: Optional[appcmds.Range[int, 0, 2**15]] = None):

View File

@@ -14,7 +14,7 @@ from meta.sharding import THIS_SHARD
from utils.lib import utc_now, error_embed
from core.lion_guild import VoiceMode
from wards import low_management
from wards import low_management_ward
from . import babel, logger
from .data import VoiceTrackerData
@@ -625,7 +625,8 @@ class VoiceTrackerCog(LionCog):
hourly_live_bonus=VoiceTrackerSettings.HourlyLiveBonus._desc,
daily_voice_cap=VoiceTrackerSettings.DailyVoiceCap._desc,
)
@cmds.check(low_management)
@appcmds.default_permissions(manage_guild=True)
@low_management_ward
async def configure_voice_tracking_cmd(self, ctx: LionContext,
hourly_reward: Optional[int] = None, # TODO: Change these to Ranges
hourly_live_bonus: Optional[int] = None,

View File

@@ -6,7 +6,8 @@ from discord.ui.button import button, Button, ButtonStyle
from meta import conf, LionBot
from meta.errors import UserInputError
from wards import i_low_management
from utils.lib import error_embed
from wards import low_management_iward
from babel.translator import ctx_translator, LazyStr
from ..lib import tabulate
@@ -55,7 +56,20 @@ class ConfigUI(LeoUI):
"""
Default requirement for a Config UI is low management (i.e. manage_guild permissions).
"""
return await i_low_management(interaction)
passed = await low_management_iward(interaction)
if passed:
return True
else:
await interaction.response.send_message(
embed=error_embed(
self.bot.translator.t(_p(
'ui:configui|check|not_permitted',
"You have insufficient server permissions to use this UI!"
))
),
ephemeral=True
)
return False
async def cleanup(self):
self._listening.pop(self.channelid, None)

View File

@@ -1,47 +1,98 @@
from typing import Optional
import discord
from discord.ext.commands.errors import CheckFailure
import discord.ext.commands as cmds
from meta.LionContext import LionContext
from meta import conf
from babel.translator import LocalBabel
from meta import conf, LionContext, LionBot
babel = LocalBabel('wards')
_p = babel._p
# Interaction Wards
async def i_sys_admin(interaction: discord.Interaction) -> bool:
# Raw checks, return True/False depending on whether they pass
async def sys_admin(bot: LionBot, userid: int):
"""
Checks whether the context author is listed in the configuration file as a bot admin.
"""
admins = conf.bot.getintlist('admins')
return interaction.user.id in admins
admins = bot.config.bot.getintlist('admins')
return userid in admins
async def i_high_management(interaction: discord.Interaction) -> bool:
if await i_sys_admin(interaction):
async def high_management(bot: LionBot, member: discord.Member):
if await sys_admin(bot, member.id):
return True
return member.guild_permissions.administrator
async def low_management(bot: LionBot, member: discord.Member):
if await high_management(bot, member):
return True
return member.guild_permissions.manage_guild
# Interaction Wards, also return True/False
async def sys_admin_iward(interaction: discord.Interaction) -> bool:
return await sys_admin(interaction.client, interaction.user.id)
async def high_management_iward(interaction: discord.Interaction) -> bool:
if not interaction.guild:
return False
return interaction.user.guild_permissions.administrator
return await high_management(interaction.client, interaction.user)
async def i_low_management(interaction: discord.Interaction) -> bool:
if await i_high_management(interaction):
return True
async def low_management_iward(interaction: discord.Interaction) -> bool:
if not interaction.guild:
return False
return interaction.user.guild_permissions.manage_guild
return await low_management(interaction.client, interaction.user)
async def sys_admin(ctx: LionContext) -> bool:
admins = ctx.bot.config.bot.getintlist('admins')
return ctx.author.id in admins
# Command Wards, raise CheckFailure with localised error message
async def high_management(ctx: LionContext) -> bool:
if await sys_admin(ctx):
@cmds.check
async def sys_admin_ward(ctx: LionContext) -> bool:
passed = await sys_admin(ctx.bot, ctx.author.id)
if passed:
return True
else:
raise CheckFailure(
ctx.bot.translator.t(_p(
'ward:sys_admin|failed',
"You must be a bot owner to do this!"
))
)
@cmds.check
async def high_management_ward(ctx: LionContext) -> bool:
if not ctx.guild:
return False
return ctx.author.guild_permissions.administrator
passed = await high_management(ctx.bot, ctx.author)
if passed:
return True
else:
raise CheckFailure(
ctx.bot.translator.t(_p(
'ward:high_management|failed',
"You must have the `ADMINISTRATOR` permission in this server to do this!"
))
)
async def low_management(ctx: LionContext) -> bool:
return (await high_management(ctx)) or ctx.author.guild_permissions.manage_guild
@cmds.check
async def low_management_ward(ctx: LionContext) -> bool:
if not ctx.guild:
return False
passed = await low_management(ctx.bot, ctx.author)
if passed:
return True
else:
raise CheckFailure(
ctx.bot.translator.t(_p(
'ward:low_management|failed',
"You must have the `MANAGE_GUILD` permission in this server to do this!"
))
)