Toby Harradine 0870403299
Permissions redesign (#2149)
API changes:
- Cogs must now inherit from `commands.Cog` (see #2151 for discussion and more details)
- All functions which are not decorators in the `redbot.core.checks` module are now deprecated in favour of their counterparts in `redbot.core.utils.mod`. This is to make this module more consistent and end the confusing naming convention.
- `redbot.core.checks.check_overrides` function is now gone, overrideable checks can now be created with the `@commands.permissions_check` decorator
- Command, Group, Cog and Context have some new attributes and methods, but they are for internal use so shouldn't concern cog creators (unless they're making a permissions cog!).
- `__permissions_check_before` and `__permissions_check_after` have been replaced:  A cog method named `__permissions_hook` will be evaluated as permissions hooks in the same way `__permissions_check_before` previously was. Permissions hooks can also be added/removed/verified through the new `*_permissions_hook()` methods on the bot object, and they will be verified even when permissions is unloaded.
- New utility method `redbot.core.utils.chat_formatting.humanize_list`
- New dependency [`schema`](https://github.com/keleshev/schema)

User-facing changes:
- When a `@bot_has_permissions` check fails, the bot will respond saying what permissions were actually missing.
- All YAML-related `[p]permissions` subcommands now reside under the `[p]permissions acl` sub-group (tbh I still think the whole cog has too many top-level commands)
- The YAML schema for these commands has been changed
- A rule cannot be set as allow and deny at the same time (previously this would just default to allow)

Documentation:
- New documentation for `redbot.core.commands.requires` and `redbot.core.checks` modules
- Renewed documentation for the permissions cog
- `sphinx.ext.doctest` is now enabled

Note: standard discord.py checks will still behave exactly the same way, in fact they are checked before `Requires` is looked at, so they are not overrideable. 

Signed-off-by: Toby Harradine <tobyharradine@gmail.com>
2018-10-01 13:19:25 +10:00

123 lines
4.5 KiB
Python

import discord
from redbot.core.utils.chat_formatting import box
from redbot.core import checks, bank, commands
from redbot.core.i18n import Translator, cog_i18n
from redbot.core.bot import Red # Only used for type hints
_ = Translator("Bank", __file__)
def check_global_setting_guildowner():
"""
Command decorator. If the bank is not global, it checks if the author is
either the guildowner or has the administrator permission.
"""
async def pred(ctx: commands.Context):
author = ctx.author
if not await bank.is_global():
if not isinstance(ctx.channel, discord.abc.GuildChannel):
return False
if await ctx.bot.is_owner(author):
return True
permissions = ctx.channel.permissions_for(author)
return author == ctx.guild.owner or permissions.administrator
else:
return await ctx.bot.is_owner(author)
return commands.check(pred)
def check_global_setting_admin():
"""
Command decorator. If the bank is not global, it checks if the author is
either a bot admin or has the manage_guild permission.
"""
async def pred(ctx: commands.Context):
author = ctx.author
if not await bank.is_global():
if not isinstance(ctx.channel, discord.abc.GuildChannel):
return False
if await ctx.bot.is_owner(author):
return True
permissions = ctx.channel.permissions_for(author)
is_guild_owner = author == ctx.guild.owner
admin_role = await ctx.bot.db.guild(ctx.guild).admin_role()
return admin_role in author.roles or is_guild_owner or permissions.manage_guild
else:
return await ctx.bot.is_owner(author)
return commands.check(pred)
@cog_i18n(_)
class Bank(commands.Cog):
"""Bank"""
def __init__(self, bot: Red):
super().__init__()
self.bot = bot
# SECTION commands
@check_global_setting_guildowner()
@checks.guildowner_or_permissions(administrator=True)
@commands.group(autohelp=True)
async def bankset(self, ctx: commands.Context):
"""Base command for bank settings"""
if ctx.invoked_subcommand is None:
if await bank.is_global():
bank_name = await bank._conf.bank_name()
currency_name = await bank._conf.currency()
default_balance = await bank._conf.default_balance()
else:
if not ctx.guild:
return
bank_name = await bank._conf.guild(ctx.guild).bank_name()
currency_name = await bank._conf.guild(ctx.guild).currency()
default_balance = await bank._conf.guild(ctx.guild).default_balance()
settings = _(
"Bank settings:\n\nBank name: {}\nCurrency: {}\nDefault balance: {}"
).format(bank_name, currency_name, default_balance)
await ctx.send(box(settings))
@bankset.command(name="toggleglobal")
@checks.is_owner()
async def bankset_toggleglobal(self, ctx: commands.Context, confirm: bool = False):
"""Toggles whether the bank is global or not
If the bank is global, it will become per-server
If the bank is per-server, it will become global"""
cur_setting = await bank.is_global()
word = _("per-server") if cur_setting else _("global")
if confirm is False:
await ctx.send(
_(
"This will toggle the bank to be {}, deleting all accounts "
"in the process! If you're sure, type `{}`"
).format(word, "{}bankset toggleglobal yes".format(ctx.prefix))
)
else:
await bank.set_global(not cur_setting)
await ctx.send(_("The bank is now {}.").format(word))
@bankset.command(name="bankname")
@check_global_setting_guildowner()
async def bankset_bankname(self, ctx: commands.Context, *, name: str):
"""Set the bank's name"""
await bank.set_bank_name(name, ctx.guild)
await ctx.send(_("Bank's name has been set to {}").format(name))
@bankset.command(name="creditsname")
@check_global_setting_guildowner()
async def bankset_creditsname(self, ctx: commands.Context, *, name: str):
"""Set the name for the bank's currency"""
await bank.set_currency_name(name, ctx.guild)
await ctx.send(_("Currency name has been set to {}").format(name))
# ENDSECTION