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 import LionBot, LionCog, LionContext
from meta.errors import UserInputError from meta.errors import UserInputError
from utils.ui import AButton, AsComponents 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 .translator import ctx_locale, ctx_translator, SOURCE_LOCALE
from . import babel from . import babel
@@ -115,7 +115,8 @@ class BabelCog(LionCog):
force_language=LocaleSettings.ForceLocale._display_name force_language=LocaleSettings.ForceLocale._display_name
) )
@appcmds.guild_only() # Can be removed when attached as a subcommand @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, async def cmd_configure_language(self, ctx: LionContext,
language: Optional[str] = None, language: Optional[str] = None,
force_language: Optional[appcmds.Choice[int]] = None): force_language: Optional[appcmds.Choice[int]] = None):

View File

@@ -28,6 +28,7 @@ class ConfigCog(LionCog):
name=_p('group:configure', "configure"), name=_p('group:configure', "configure"),
) )
@appcmds.guild_only @appcmds.guild_only
@appcmds.default_permissions(manage_guild=True)
async def configure_group(self, ctx: LionContext): async def configure_group(self, ctx: LionContext):
""" """
Bare command group, has no function. 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." description="At-a-glance view of the server's configuration."
) )
@appcmds.guild_only @appcmds.guild_only
@appcmds.default_permissions(manage_guild=True)
async def dashboard_cmd(self, ctx: LionContext): async def dashboard_cmd(self, ctx: LionContext):
ui = GuildDashboard(self.bot, ctx.guild, ctx.author.id, ctx.channel.id) ui = GuildDashboard(self.bot, ctx.guild, ctx.author.id, ctx.channel.id)
await ui.run(ctx.interaction) await ui.run(ctx.interaction)

View File

@@ -13,7 +13,7 @@ from discord import app_commands as appcmds
from meta import LionBot, LionCog, LionContext, ctx_bot from meta import LionBot, LionCog, LionContext, ctx_bot
from meta.errors import UserInputError from meta.errors import UserInputError
from wards import low_management from wards import low_management_ward
from settings import ModelData from settings import ModelData
from settings.setting_types import TimezoneSetting from settings.setting_types import TimezoneSetting
from settings.groups import SettingGroup from settings.groups import SettingGroup
@@ -101,7 +101,8 @@ class GeneralSettingsCog(LionCog):
timezone=GeneralSettings.Timezone._desc timezone=GeneralSettings.Timezone._desc
) )
@appcmds.guild_only() @appcmds.guild_only()
@cmds.check(low_management) @appcmds.default_permissions(manage_guild=True)
@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):
t = self.bot.translator.t t = self.bot.translator.t

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ from discord.app_commands.transformers import AppCommandOptionType
from cachetools import LRUCache from cachetools import LRUCache
from meta import LionBot, LionContext, LionCog from meta import LionBot, LionContext, LionCog
from wards import high_management from wards import high_management_ward
from core.data import RankType from core.data import RankType
from utils.ui import ChoicedEnum, Transformed from utils.ui import ChoicedEnum, Transformed
from utils.lib import utc_now, replace_multiple from utils.lib import utc_now, replace_multiple
@@ -435,7 +435,8 @@ class RankCog(LionCog):
# ---------- Commands ---------- # ---------- Commands ----------
@cmds.hybrid_command(name=_p('cmd:ranks', "ranks")) @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): async def ranks_cmd(self, ctx: LionContext):
""" """
Command to access the Rank Overview UI. Command to access the Rank Overview UI.
@@ -472,7 +473,8 @@ class RankCog(LionCog):
dm_ranks=RankSettings.DMRanks._desc, dm_ranks=RankSettings.DMRanks._desc,
rank_channel=RankSettings.RankChannel._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, async def configure_ranks_cmd(self, ctx: LionContext,
rank_type: Optional[Transformed[RankTypeChoice, AppCommandOptionType.string]] = None, rank_type: Optional[Transformed[RankTypeChoice, AppCommandOptionType.string]] = None,
dm_ranks: Optional[bool] = 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 discord.ui.button import button, Button, ButtonStyle
from meta import LionBot from meta import LionBot
from wards import i_high_management from wards import high_management_iward
from core.data import RankType from core.data import RankType
from utils.ui import ConfigUI, DashboardSection from utils.ui import ConfigUI, DashboardSection
from utils.lib import MessageArgs from utils.lib import MessageArgs, error_embed
from ..settings import RankSettings from ..settings import RankSettings
from .. import babel, logger from .. import babel, logger
@@ -31,7 +31,20 @@ class RankConfigUI(ConfigUI):
super().__init__(bot, guildid, channelid, **kwargs) super().__init__(bot, guildid, channelid, **kwargs)
async def interaction_check(self, interaction: discord.Interaction) -> bool: 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 ----- # ----- UI Components -----

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 from wards import low_management_ward
from . import babel, logger from . import babel, logger
from .data import RoomData from .data import RoomData
@@ -888,7 +888,8 @@ 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}
) )
@cmds.check(low_management) @appcmds.default_permissions(manage_guild=True)
@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

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

View File

@@ -9,7 +9,7 @@ from discord.ui.button import ButtonStyle
from meta import LionBot, LionCog, LionContext from meta import LionBot, LionCog, LionContext
from utils.lib import error_embed from utils.lib import error_embed
from utils.ui import LeoUI, AButton from utils.ui import LeoUI, AButton
from wards import low_management from wards import low_management_ward
from . import babel from . import babel
from .data import StatsData from .data import StatsData
@@ -97,7 +97,8 @@ class StatsCog(LionCog):
"Time from which to start counting activity for rank badges and season leadeboards." "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, 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

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

View File

@@ -7,7 +7,7 @@ import discord.ext.commands as cmds
from meta import LionBot, LionCog, LionContext from meta import LionBot, LionCog, LionContext
from meta.app import appname from meta.app import appname
from wards import sys_admin from wards import sys_admin_ward
from settings.groups import SettingGroup from settings.groups import SettingGroup
@@ -23,7 +23,7 @@ class LeoSettings(LionCog):
@cmds.hybrid_group( @cmds.hybrid_group(
name="leo" name="leo"
) )
@cmds.check(sys_admin) @sys_admin_ward
async def leo_group(self, ctx: LionContext): async def leo_group(self, ctx: LionContext):
""" """
Base command group for global leo-only functions. Base command group for global leo-only functions.
@@ -35,7 +35,7 @@ class LeoSettings(LionCog):
name='dashboard', name='dashboard',
description="Global setting dashboard" description="Global setting dashboard"
) )
@cmds.check(sys_admin) @sys_admin_ward
async def dash_cmd(self, ctx: LionContext): async def dash_cmd(self, ctx: LionContext):
embed = discord.Embed( embed = discord.Embed(
title="System Admin Dashboard", title="System Admin Dashboard",
@@ -56,7 +56,7 @@ class LeoSettings(LionCog):
name='configure', name='configure',
description="Leo Configuration Group" description="Leo Configuration Group"
) )
@cmds.check(sys_admin) @sys_admin_ward
async def leo_configure_group(self, ctx: LionContext): async def leo_configure_group(self, ctx: LionContext):
""" """
Base command group for global configuration of Leo. 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) self.talk_async = shard_talk.register_route('exec')(_async)
async def cog_check(self, ctx: LionContext) -> bool: # type: ignore 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( @commands.hybrid_command(
name=_('async'), name=_('async'),

View File

@@ -21,7 +21,7 @@ from settings.data import ModelData
from settings.setting_types import EnumSetting, StringSetting from settings.setting_types import EnumSetting, StringSetting
from settings.groups import SettingGroup from settings.groups import SettingGroup
from wards import sys_admin from wards import sys_admin_ward
from . import babel from . import babel
@@ -376,7 +376,7 @@ class PresenceCtrl(LionCog):
name="presence", name="presence",
description="Globally set the bot status and activity." description="Globally set the bot status and activity."
) )
@cmds.check(sys_admin) @sys_admin_ward
@appcmds.describe( @appcmds.describe(
status="Online status (online | idle | dnd | offline)", status="Online status (online | idle | dnd | offline)",
type="Activity type (watching | listening | playing | streaming)", 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 utils.ui import ChoicedEnum, Transformed
from data import Condition, NULL from data import Condition, NULL
from wards import low_management from wards import low_management_ward
from . import babel, logger from . import babel, logger
from .data import TasklistData from .data import TasklistData
@@ -712,7 +712,8 @@ 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
) )
@cmds.check(low_management) @appcmds.default_permissions(manage_guild=True)
@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,
reward_limit: 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 meta.app import appname
from utils.lib import utc_now, error_embed from utils.lib import utc_now, error_embed
from wards import low_management from wards import low_management_ward
from . import babel, logger from . import babel, logger
from .data import TextTrackerData from .data import TextTrackerData
@@ -260,7 +260,8 @@ 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,
) )
@cmds.check(low_management) @appcmds.default_permissions(manage_guild=True)
@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,
word_xp: 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 utils.lib import utc_now, error_embed
from core.lion_guild import VoiceMode from core.lion_guild import VoiceMode
from wards import low_management from wards import low_management_ward
from . import babel, logger from . import babel, logger
from .data import VoiceTrackerData from .data import VoiceTrackerData
@@ -625,7 +625,8 @@ 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,
) )
@cmds.check(low_management) @appcmds.default_permissions(manage_guild=True)
@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
hourly_live_bonus: Optional[int] = None, 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 import conf, LionBot
from meta.errors import UserInputError 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 babel.translator import ctx_translator, LazyStr
from ..lib import tabulate 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). 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): async def cleanup(self):
self._listening.pop(self.channelid, None) self._listening.pop(self.channelid, None)

View File

@@ -1,47 +1,98 @@
from typing import Optional
import discord import discord
from discord.ext.commands.errors import CheckFailure
import discord.ext.commands as cmds
from meta.LionContext import LionContext from babel.translator import LocalBabel
from meta import conf
from meta import conf, LionContext, LionBot
babel = LocalBabel('wards')
_p = babel._p
# Interaction Wards # Raw checks, return True/False depending on whether they pass
async def sys_admin(bot: LionBot, userid: int):
async def i_sys_admin(interaction: discord.Interaction) -> bool:
""" """
Checks whether the context author is listed in the configuration file as a bot admin. Checks whether the context author is listed in the configuration file as a bot admin.
""" """
admins = conf.bot.getintlist('admins') admins = bot.config.bot.getintlist('admins')
return interaction.user.id in admins return userid in admins
async def i_high_management(interaction: discord.Interaction) -> bool: async def high_management(bot: LionBot, member: discord.Member):
if await i_sys_admin(interaction): if await sys_admin(bot, member.id):
return True 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: if not interaction.guild:
return False 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: async def low_management_iward(interaction: discord.Interaction) -> bool:
if await i_high_management(interaction):
return True
if not interaction.guild: if not interaction.guild:
return False return False
return interaction.user.guild_permissions.manage_guild return await low_management(interaction.client, interaction.user)
async def sys_admin(ctx: LionContext) -> bool: # Command Wards, raise CheckFailure with localised error message
admins = ctx.bot.config.bot.getintlist('admins')
return ctx.author.id in admins
@cmds.check
async def high_management(ctx: LionContext) -> bool: async def sys_admin_ward(ctx: LionContext) -> bool:
if await sys_admin(ctx): passed = await sys_admin(ctx.bot, ctx.author.id)
if passed:
return True 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: if not ctx.guild:
return False 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: @cmds.check
return (await high_management(ctx)) or ctx.author.guild_permissions.manage_guild 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!"
))
)