mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-22 02:37:57 -05:00
[Bank] Allow Bot Owner/Guild Owners to remove invalid users from the bank (#2845)
* Add command to remove dead members from bank * Add a global check * Added a FIXME so `bank_local_clean` is updated once bulk-update is implemented Added a brief warning to warn devs not to use the `_get_base_group` as it can mess up their config files Removed a redundant existence check * Updated commit to reflect changes requested in review * Updated commit to reflect changes requested in review * 🤦 * Return command to run with user id so we don't worry about safeguarding the command agaisn't invalid formats * Braaaainnn Removed aliases that used old naming scheme * TL:DR Added global bank support, and rework permissions Renamed `bank_local_clean` to `bank_prune` Added support for global banks to `bank_prune` `bank_prune` will now raise `BankPruneError` if trying to prune a local bank and `guild` is not supplied Renamed `cleanup` subgroup to `prune` `prune` subgroup will have 3 commands: `user` : Deletes the bank account for the specified member : Accepts `Union[discord.Member, discord.User, int]` `global` : Prune global bank accounts for all users who no longer share a server with the bot `local` : Prune local bank accounts for all users who are no longer in the guild Changed check for `prune` subgroup to be `@check_global_setting_admin()` [p]bank prune local : Can be run by Guild owners only [p]bank prune global : Can be run by Bot Owner only [p]bank prune user : Can be run by Admins, Guild owners and Bot Owner * Yikes ... Updated kwarg name * Fixed unexpected unindent: docstring of redbot.core.bank.bank_prune:14:Field list ends without a blank line * ... * 3rd time lucky? * 4th time lucky? * Fix Docstring * Initial commit to address review by Flame * Updated code to reflect Flame's comments * Skip pruning of unavailable guilds * Fixed typo in string * *sigh* black is the bane of my existence * addressed Flames commends Fixed [p]bank prune user, When run via DM it will now return an error message to the user (Thanks jack1142) * Time to get some sleep * 'DM' > 'DMs' in string * Add towncrier entries Signed-off-by: Draper <guyreis96@gmail.com> * Update to reflect Flame's review Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com>
This commit is contained in:
@@ -3,12 +3,13 @@ import logging
|
||||
import random
|
||||
from collections import defaultdict, deque, namedtuple
|
||||
from enum import Enum
|
||||
from typing import cast, Iterable
|
||||
from typing import cast, Iterable, Union
|
||||
|
||||
import discord
|
||||
|
||||
from redbot.cogs.bank import check_global_setting_guildowner, check_global_setting_admin
|
||||
from redbot.core import Config, bank, commands, errors
|
||||
from redbot.cogs.mod.converters import RawUserIds
|
||||
from redbot.core import Config, bank, commands, errors, checks
|
||||
from redbot.core.i18n import Translator, cog_i18n
|
||||
from redbot.core.utils.chat_formatting import box, humanize_number
|
||||
from redbot.core.utils.menus import menu, DEFAULT_CONTROLS
|
||||
@@ -257,6 +258,87 @@ class Economy(commands.Cog):
|
||||
)
|
||||
)
|
||||
|
||||
@_bank.group(name="prune")
|
||||
@check_global_setting_admin()
|
||||
async def _prune(self, ctx):
|
||||
"""Prune bank accounts."""
|
||||
pass
|
||||
|
||||
@_prune.command(name="local")
|
||||
@commands.guild_only()
|
||||
@checks.guildowner()
|
||||
async def _local(self, ctx, confirmation: bool = False):
|
||||
"""Prune bank accounts for users no longer in the server."""
|
||||
global_bank = await bank.is_global()
|
||||
if global_bank is True:
|
||||
return await ctx.send(_("This command cannot be used with a global bank."))
|
||||
|
||||
if confirmation is False:
|
||||
await ctx.send(
|
||||
_(
|
||||
"This will delete all bank accounts for users no longer in this server."
|
||||
"\nIf you're sure, type "
|
||||
"`{prefix}bank prune local yes`"
|
||||
).format(prefix=ctx.prefix)
|
||||
)
|
||||
else:
|
||||
await bank.bank_prune(self.bot, guild=ctx.guild)
|
||||
await ctx.send(
|
||||
_("Bank accounts for users no longer in this server have been deleted.")
|
||||
)
|
||||
|
||||
@_prune.command(name="global")
|
||||
@checks.is_owner()
|
||||
async def _global(self, ctx, confirmation: bool = False):
|
||||
"""Prune bank accounts for users who no longer share a server with the bot."""
|
||||
global_bank = await bank.is_global()
|
||||
if global_bank is False:
|
||||
return await ctx.send(_("This command cannot be used with a local bank."))
|
||||
|
||||
if confirmation is False:
|
||||
await ctx.send(
|
||||
_(
|
||||
"This will delete all bank accounts for users "
|
||||
"who no longer share a server with the bot."
|
||||
"\nIf you're sure, type `{prefix}bank prune global yes`"
|
||||
).format(prefix=ctx.prefix)
|
||||
)
|
||||
else:
|
||||
await bank.bank_prune(self.bot)
|
||||
await ctx.send(
|
||||
_(
|
||||
"Bank accounts for users who "
|
||||
"no longer share a server with the bot have been pruned."
|
||||
)
|
||||
)
|
||||
|
||||
@_prune.command(usage="<user> [confirmation=False]")
|
||||
async def user(
|
||||
self, ctx, member_or_id: Union[discord.Member, RawUserIds], confirmation: bool = False
|
||||
):
|
||||
"""Delete the bank account of a specified user."""
|
||||
global_bank = await bank.is_global()
|
||||
if global_bank is False and ctx.guild is None:
|
||||
return await ctx.send(_("This command cannot be used in DMs with a local bank."))
|
||||
try:
|
||||
name = member_or_id.display_name
|
||||
uid = member_or_id.id
|
||||
except AttributeError:
|
||||
name = member_or_id
|
||||
uid = member_or_id
|
||||
|
||||
if confirmation is False:
|
||||
await ctx.send(
|
||||
_(
|
||||
"This will delete {name}'s bank account."
|
||||
"\nIf you're sure, type "
|
||||
"`{prefix}bank prune user {id} yes`"
|
||||
).format(prefix=ctx.prefix, id=uid, name=name)
|
||||
)
|
||||
else:
|
||||
await bank.bank_prune(self.bot, guild=ctx.guild, user_id=uid)
|
||||
await ctx.send(_("The bank account for {name} has been pruned.").format(name=name))
|
||||
|
||||
@guild_only_check()
|
||||
@commands.command()
|
||||
async def payday(self, ctx: commands.Context):
|
||||
|
||||
@@ -8,6 +8,8 @@ import discord
|
||||
from redbot.core.utils.chat_formatting import humanize_number
|
||||
from . import Config, errors, commands
|
||||
from .i18n import Translator
|
||||
from .bot import Red
|
||||
from .errors import BankPruneError
|
||||
|
||||
_ = Translator("Bank API", __file__)
|
||||
|
||||
@@ -33,6 +35,7 @@ __all__ = [
|
||||
"set_max_balance",
|
||||
"cost",
|
||||
"AbortPurchase",
|
||||
"bank_prune",
|
||||
]
|
||||
|
||||
_MAX_BALANCE = 2 ** 63 - 1
|
||||
@@ -365,6 +368,59 @@ async def wipe_bank(guild: Optional[discord.Guild] = None) -> None:
|
||||
await _conf.clear_all_members(guild)
|
||||
|
||||
|
||||
async def bank_prune(bot: Red, guild: discord.Guild = None, user_id: int = None) -> None:
|
||||
"""Prune bank accounts from the bank.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bot : Red
|
||||
The bot.
|
||||
guild : discord.Guild
|
||||
The guild to prune. This is required if the bank is set to local.
|
||||
user_id : int
|
||||
The id of the user whose account will be pruned.
|
||||
If supplied this will prune only this user's bank account
|
||||
otherwise it will prune all invalid users from the bank.
|
||||
|
||||
Raises
|
||||
------
|
||||
BankPruneError
|
||||
If guild is :code:`None` and the bank is Local.
|
||||
|
||||
"""
|
||||
|
||||
global_bank = await is_global()
|
||||
|
||||
if global_bank:
|
||||
_guilds = [g for g in bot.guilds if not g.unavailable and g.large and not g.chunked]
|
||||
_uguilds = [g for g in bot.guilds if g.unavailable]
|
||||
group = _conf._get_base_group(_conf.USER)
|
||||
|
||||
else:
|
||||
if guild is None:
|
||||
raise BankPruneError("'guild' can't be None when pruning a local bank")
|
||||
_guilds = [guild] if not guild.unavailable and guild.large else []
|
||||
_uguilds = [guild] if guild.unavailable else []
|
||||
group = _conf._get_base_group(_conf.MEMBER, str(guild.id))
|
||||
|
||||
if user_id is None:
|
||||
await bot.request_offline_members(*_guilds)
|
||||
accounts = await group.all()
|
||||
tmp = accounts.copy()
|
||||
members = bot.get_all_members() if global_bank else guild.members
|
||||
user_list = {str(m.id) for m in members if m.guild not in _uguilds}
|
||||
|
||||
async with group.all() as bank_data: # FIXME: use-config-bulk-update
|
||||
if user_id is None:
|
||||
for acc in tmp:
|
||||
if acc not in user_list:
|
||||
del bank_data[acc]
|
||||
else:
|
||||
user_id = str(user_id)
|
||||
if user_id in bank_data:
|
||||
del bank_data[user_id]
|
||||
|
||||
|
||||
async def get_leaderboard(positions: int = None, guild: discord.Guild = None) -> List[tuple]:
|
||||
"""
|
||||
Gets the bank's leaderboard
|
||||
|
||||
@@ -883,6 +883,12 @@ class Config:
|
||||
self.custom_groups[group_identifier] = identifier_count
|
||||
|
||||
def _get_base_group(self, category: str, *primary_keys: str) -> Group:
|
||||
"""
|
||||
.. warning::
|
||||
:code:`Config._get_base_group()` should not be used to get config groups as
|
||||
this is not a safe operation. Using this could end up corrupting your config file.
|
||||
"""
|
||||
# noinspection PyTypeChecker
|
||||
pkey_len, is_custom = ConfigCategory.get_pkey_info(category, self.custom_groups)
|
||||
identifier_data = IdentifierData(
|
||||
cog_name=self.cog_name,
|
||||
|
||||
@@ -51,6 +51,10 @@ class BalanceTooHigh(BankError, OverflowError):
|
||||
)
|
||||
|
||||
|
||||
class BankPruneError(BankError):
|
||||
"""Raised when trying to prune a local bank and no server is specified."""
|
||||
|
||||
|
||||
class MissingExtraRequirements(RedError):
|
||||
"""Raised when an extra requirement is missing but required."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user