mirror of
https://github.com/Cog-Creators/Red-DiscordBot.git
synced 2025-11-06 03:08:55 -05:00
[Bank] Allow bank managers to set the maximum allowed balance in the bank (#2926)
* Removes `MAX_BALANCE` from bank, user `bank.get_max_balance()` now `[p]bankset maxbal` can be used to set the maximum bank balance Signed-off-by: Guy <guyreis96@gmail.com> * Removes `MAX_BALANCE` from bank, user `bank.get_max_balance()` now `[p]bankset maxbal` can be used to set the maximum bank balance Signed-off-by: Guy <guyreis96@gmail.com> * Removes `MAX_BALANCE` from bank, user `bank.get_max_balance()` now `[p]bankset maxbal` can be used to set the maximum bank balance Signed-off-by: Guy <guyreis96@gmail.com> * Rename method 🤦 Signed-off-by: Guy <guyreis96@gmail.com> * Updated this to be aware of #2925 Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com> * Addressed Flames review + Fixed 1 bug in errors.py + `[p]leaderboard` and `[p]bank balance` will set the users balance to max balance if the bank maxbal is lower than the previous user balance Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com> * Missed this clarification Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com> * address Flames review Signed-off-by: guyre <27962761+drapersniper@users.noreply.github.com>
This commit is contained in:
parent
b490942bcd
commit
e04eed4a89
1
changelog.d/2926.breaking.rst
Normal file
1
changelog.d/2926.breaking.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
Removed :cons:`bank.MAX_BALANCE`, use :meth:`bank.get_max_balance()` from now.
|
||||||
1
changelog.d/2926.feature.rst
Normal file
1
changelog.d/2926.feature.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
`[p]bankset maxbal` can be used to set the maximum bank balance.
|
||||||
@ -86,11 +86,12 @@ class Bank(commands.Cog):
|
|||||||
|
|
||||||
settings = _(
|
settings = _(
|
||||||
"Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n"
|
"Bank settings:\n\nBank name: {bank_name}\nCurrency: {currency_name}\n"
|
||||||
"Default balance: {default_balance}"
|
"Default balance: {default_balance}\nMaximum allowed balance: {maximum_bal}"
|
||||||
).format(
|
).format(
|
||||||
bank_name=bank_name,
|
bank_name=bank_name,
|
||||||
currency_name=currency_name,
|
currency_name=currency_name,
|
||||||
default_balance=humanize_number(default_balance),
|
default_balance=humanize_number(default_balance),
|
||||||
|
maximum_bal=humanize_number(await bank.get_max_balance(ctx.guild)),
|
||||||
)
|
)
|
||||||
await ctx.send(box(settings))
|
await ctx.send(box(settings))
|
||||||
|
|
||||||
@ -130,4 +131,21 @@ class Bank(commands.Cog):
|
|||||||
await bank.set_currency_name(name, ctx.guild)
|
await bank.set_currency_name(name, ctx.guild)
|
||||||
await ctx.send(_("Currency name has been set to: {name}").format(name=name))
|
await ctx.send(_("Currency name has been set to: {name}").format(name=name))
|
||||||
|
|
||||||
|
@bankset.command(name="maxbal")
|
||||||
|
@check_global_setting_guildowner()
|
||||||
|
async def bankset_maxbal(self, ctx: commands.Context, *, amount: int):
|
||||||
|
"""Set the maximum balance a user can get."""
|
||||||
|
try:
|
||||||
|
await bank.set_max_balance(amount, ctx.guild)
|
||||||
|
except ValueError:
|
||||||
|
# noinspection PyProtectedMember
|
||||||
|
return await ctx.send(
|
||||||
|
_("Amount must be greater than zero and less than {max}.").format(
|
||||||
|
max=humanize_number(bank._MAX_BALANCE)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await ctx.send(
|
||||||
|
_("Maximum balance has been set to: {amount}").format(amount=humanize_number(amount))
|
||||||
|
)
|
||||||
|
|
||||||
# ENDSECTION
|
# ENDSECTION
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import calendar
|
import calendar
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
from collections import defaultdict, deque
|
from collections import defaultdict, deque, namedtuple
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import cast, Iterable
|
from typing import cast, Iterable
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ T_ = Translator("Economy", __file__)
|
|||||||
logger = logging.getLogger("red.economy")
|
logger = logging.getLogger("red.economy")
|
||||||
|
|
||||||
NUM_ENC = "\N{COMBINING ENCLOSING KEYCAP}"
|
NUM_ENC = "\N{COMBINING ENCLOSING KEYCAP}"
|
||||||
|
MOCK_MEMBER = namedtuple("Member", "id guild")
|
||||||
|
|
||||||
|
|
||||||
class SMReel(Enum):
|
class SMReel(Enum):
|
||||||
@ -159,7 +160,10 @@ class Economy(commands.Cog):
|
|||||||
|
|
||||||
bal = await bank.get_balance(user)
|
bal = await bank.get_balance(user)
|
||||||
currency = await bank.get_currency_name(ctx.guild)
|
currency = await bank.get_currency_name(ctx.guild)
|
||||||
|
max_bal = await bank.get_max_balance(ctx.guild)
|
||||||
|
if bal > max_bal:
|
||||||
|
bal = max_bal
|
||||||
|
await bank.set_balance(user, bal)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("{user}'s balance is {num} {currency}").format(
|
_("{user}'s balance is {num} {currency}").format(
|
||||||
user=user.display_name, num=humanize_number(bal), currency=currency
|
user=user.display_name, num=humanize_number(bal), currency=currency
|
||||||
@ -363,6 +367,7 @@ class Economy(commands.Cog):
|
|||||||
"""
|
"""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
author = ctx.author
|
author = ctx.author
|
||||||
|
max_bal = await bank.get_max_balance(ctx.guild)
|
||||||
if top < 1:
|
if top < 1:
|
||||||
top = 10
|
top = 10
|
||||||
if await bank.is_global() and show_global:
|
if await bank.is_global() and show_global:
|
||||||
@ -372,6 +377,9 @@ class Economy(commands.Cog):
|
|||||||
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
|
bank_sorted = await bank.get_leaderboard(positions=top, guild=guild)
|
||||||
try:
|
try:
|
||||||
bal_len = len(humanize_number(bank_sorted[0][1]["balance"]))
|
bal_len = len(humanize_number(bank_sorted[0][1]["balance"]))
|
||||||
|
bal_len_max = len(humanize_number(max_bal))
|
||||||
|
if bal_len > bal_len_max:
|
||||||
|
bal_len = bal_len_max
|
||||||
# first user is the largest we'll see
|
# first user is the largest we'll see
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return await ctx.send(_("There are no accounts in the bank."))
|
return await ctx.send(_("There are no accounts in the bank."))
|
||||||
@ -394,8 +402,12 @@ class Economy(commands.Cog):
|
|||||||
if await ctx.bot.is_owner(ctx.author):
|
if await ctx.bot.is_owner(ctx.author):
|
||||||
user_id = f"({str(acc[0])})"
|
user_id = f"({str(acc[0])})"
|
||||||
name = f"{acc[1]['name']} {user_id}"
|
name = f"{acc[1]['name']} {user_id}"
|
||||||
balance = humanize_number(acc[1]["balance"])
|
|
||||||
|
|
||||||
|
balance = acc[1]["balance"]
|
||||||
|
if balance > max_bal:
|
||||||
|
balance = max_bal
|
||||||
|
await bank.set_balance(MOCK_MEMBER(acc[0], guild), balance)
|
||||||
|
balance = humanize_number(balance)
|
||||||
if acc[0] != author.id:
|
if acc[0] != author.id:
|
||||||
temp_msg += (
|
temp_msg += (
|
||||||
f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
|
f"{f'{humanize_number(pos)}.': <{pound_len+2}} "
|
||||||
@ -560,7 +572,8 @@ class Economy(commands.Cog):
|
|||||||
"Slot cooldown: {slot_time}\n"
|
"Slot cooldown: {slot_time}\n"
|
||||||
"Payday amount: {payday_amount}\n"
|
"Payday amount: {payday_amount}\n"
|
||||||
"Payday cooldown: {payday_time}\n"
|
"Payday cooldown: {payday_time}\n"
|
||||||
"Amount given at account registration: {register_amount}"
|
"Amount given at account registration: {register_amount}\n"
|
||||||
|
"Maximum allowed balance: {maximum_bal}"
|
||||||
).format(
|
).format(
|
||||||
slot_min=humanize_number(await conf.SLOT_MIN()),
|
slot_min=humanize_number(await conf.SLOT_MIN()),
|
||||||
slot_max=humanize_number(await conf.SLOT_MAX()),
|
slot_max=humanize_number(await conf.SLOT_MAX()),
|
||||||
@ -568,6 +581,7 @@ class Economy(commands.Cog):
|
|||||||
payday_time=humanize_number(await conf.PAYDAY_TIME()),
|
payday_time=humanize_number(await conf.PAYDAY_TIME()),
|
||||||
payday_amount=humanize_number(await conf.PAYDAY_CREDITS()),
|
payday_amount=humanize_number(await conf.PAYDAY_CREDITS()),
|
||||||
register_amount=humanize_number(await bank.get_default_balance(guild)),
|
register_amount=humanize_number(await bank.get_default_balance(guild)),
|
||||||
|
maximum_bal=humanize_number(await bank.get_max_balance(guild)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -639,9 +653,13 @@ class Economy(commands.Cog):
|
|||||||
async def paydayamount(self, ctx: commands.Context, creds: int):
|
async def paydayamount(self, ctx: commands.Context, creds: int):
|
||||||
"""Set the amount earned each payday."""
|
"""Set the amount earned each payday."""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
if creds <= 0 or creds > bank.MAX_BALANCE:
|
max_balance = await bank.get_max_balance(ctx.guild)
|
||||||
await ctx.send(_("Har har so funny."))
|
if creds <= 0 or creds > max_balance:
|
||||||
return
|
return await ctx.send(
|
||||||
|
_("Amount must be greater than zero and less than {maxbal}.").format(
|
||||||
|
maxbal=humanize_number(max_balance)
|
||||||
|
)
|
||||||
|
)
|
||||||
credits_name = await bank.get_currency_name(guild)
|
credits_name = await bank.get_currency_name(guild)
|
||||||
if await bank.is_global():
|
if await bank.is_global():
|
||||||
await self.config.PAYDAY_CREDITS.set(creds)
|
await self.config.PAYDAY_CREDITS.set(creds)
|
||||||
@ -657,9 +675,13 @@ class Economy(commands.Cog):
|
|||||||
async def rolepaydayamount(self, ctx: commands.Context, role: discord.Role, creds: int):
|
async def rolepaydayamount(self, ctx: commands.Context, role: discord.Role, creds: int):
|
||||||
"""Set the amount earned each payday for a role."""
|
"""Set the amount earned each payday for a role."""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
if creds <= 0 or creds > bank.MAX_BALANCE:
|
max_balance = await bank.get_max_balance(ctx.guild)
|
||||||
await ctx.send(_("Har har so funny."))
|
if creds <= 0 or creds > max_balance:
|
||||||
return
|
return await ctx.send(
|
||||||
|
_("Amount must be greater than zero and less than {maxbal}.").format(
|
||||||
|
maxbal=humanize_number(max_balance)
|
||||||
|
)
|
||||||
|
)
|
||||||
credits_name = await bank.get_currency_name(guild)
|
credits_name = await bank.get_currency_name(guild)
|
||||||
if await bank.is_global():
|
if await bank.is_global():
|
||||||
await ctx.send(_("The bank must be per-server for per-role paydays to work."))
|
await ctx.send(_("The bank must be per-server for per-role paydays to work."))
|
||||||
@ -676,10 +698,16 @@ class Economy(commands.Cog):
|
|||||||
async def registeramount(self, ctx: commands.Context, creds: int):
|
async def registeramount(self, ctx: commands.Context, creds: int):
|
||||||
"""Set the initial balance for new bank accounts."""
|
"""Set the initial balance for new bank accounts."""
|
||||||
guild = ctx.guild
|
guild = ctx.guild
|
||||||
if creds < 0:
|
max_balance = await bank.get_max_balance(ctx.guild)
|
||||||
creds = 0
|
|
||||||
credits_name = await bank.get_currency_name(guild)
|
credits_name = await bank.get_currency_name(guild)
|
||||||
await bank.set_default_balance(creds, guild)
|
try:
|
||||||
|
await bank.set_default_balance(creds, guild)
|
||||||
|
except ValueError:
|
||||||
|
return await ctx.send(
|
||||||
|
_("Amount must be greater than or equal to zero and less than {maxbal}.").format(
|
||||||
|
maxbal=humanize_number(max_balance)
|
||||||
|
)
|
||||||
|
)
|
||||||
await ctx.send(
|
await ctx.send(
|
||||||
_("Registering an account will now give {num} {currency}.").format(
|
_("Registering an account will now give {num} {currency}.").format(
|
||||||
num=humanize_number(creds), currency=credits_name
|
num=humanize_number(creds), currency=credits_name
|
||||||
|
|||||||
@ -12,7 +12,6 @@ from .i18n import Translator
|
|||||||
_ = Translator("Bank API", __file__)
|
_ = Translator("Bank API", __file__)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"MAX_BALANCE",
|
|
||||||
"Account",
|
"Account",
|
||||||
"get_balance",
|
"get_balance",
|
||||||
"set_balance",
|
"set_balance",
|
||||||
@ -30,20 +29,28 @@ __all__ = [
|
|||||||
"set_currency_name",
|
"set_currency_name",
|
||||||
"get_default_balance",
|
"get_default_balance",
|
||||||
"set_default_balance",
|
"set_default_balance",
|
||||||
|
"get_max_balance",
|
||||||
|
"set_max_balance",
|
||||||
"cost",
|
"cost",
|
||||||
"AbortPurchase",
|
"AbortPurchase",
|
||||||
]
|
]
|
||||||
|
|
||||||
MAX_BALANCE = 2 ** 63 - 1
|
_MAX_BALANCE = 2 ** 63 - 1
|
||||||
|
|
||||||
_DEFAULT_GLOBAL = {
|
_DEFAULT_GLOBAL = {
|
||||||
"is_global": False,
|
"is_global": False,
|
||||||
"bank_name": "Twentysix bank",
|
"bank_name": "Twentysix bank",
|
||||||
"currency": "credits",
|
"currency": "credits",
|
||||||
"default_balance": 100,
|
"default_balance": 100,
|
||||||
|
"max_balance": _MAX_BALANCE,
|
||||||
}
|
}
|
||||||
|
|
||||||
_DEFAULT_GUILD = {"bank_name": "Twentysix bank", "currency": "credits", "default_balance": 100}
|
_DEFAULT_GUILD = {
|
||||||
|
"bank_name": "Twentysix bank",
|
||||||
|
"currency": "credits",
|
||||||
|
"default_balance": 100,
|
||||||
|
"max_balance": _MAX_BALANCE,
|
||||||
|
}
|
||||||
|
|
||||||
_DEFAULT_MEMBER = {"name": "", "balance": 0, "created_at": 0}
|
_DEFAULT_MEMBER = {"name": "", "balance": 0, "created_at": 0}
|
||||||
|
|
||||||
@ -186,10 +193,11 @@ async def set_balance(member: discord.Member, amount: int) -> int:
|
|||||||
"""
|
"""
|
||||||
if amount < 0:
|
if amount < 0:
|
||||||
raise ValueError("Not allowed to have negative balance.")
|
raise ValueError("Not allowed to have negative balance.")
|
||||||
if amount > MAX_BALANCE:
|
max_bal = await get_max_balance(member.guild)
|
||||||
|
if amount > max_bal:
|
||||||
currency = await get_currency_name(member.guild)
|
currency = await get_currency_name(member.guild)
|
||||||
raise errors.BalanceTooHigh(
|
raise errors.BalanceTooHigh(
|
||||||
user=member.display_name, max_balance=MAX_BALANCE, currency_name=currency
|
user=member.display_name, max_balance=max_bal, currency_name=currency
|
||||||
)
|
)
|
||||||
if await is_global():
|
if await is_global():
|
||||||
group = _conf.user(member)
|
group = _conf.user(member)
|
||||||
@ -329,10 +337,12 @@ async def transfer_credits(from_: discord.Member, to: discord.Member, amount: in
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if await get_balance(to) + amount > MAX_BALANCE:
|
max_bal = await get_max_balance(to.guild)
|
||||||
|
|
||||||
|
if await get_balance(to) + amount > max_bal:
|
||||||
currency = await get_currency_name(to.guild)
|
currency = await get_currency_name(to.guild)
|
||||||
raise errors.BalanceTooHigh(
|
raise errors.BalanceTooHigh(
|
||||||
user=to.display_name, max_balance=MAX_BALANCE, currency_name=currency
|
user=to.display_name, max_balance=max_bal, currency_name=currency
|
||||||
)
|
)
|
||||||
|
|
||||||
await withdraw_credits(from_, amount)
|
await withdraw_credits(from_, amount)
|
||||||
@ -635,6 +645,75 @@ async def set_currency_name(name: str, guild: discord.Guild = None) -> str:
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
async def get_max_balance(guild: discord.Guild = None) -> int:
|
||||||
|
"""Get the max balance for the bank.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
guild : `discord.Guild`, optional
|
||||||
|
The guild to get the max balance for (required if bank is
|
||||||
|
guild-specific).
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The maximum allowed balance.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
RuntimeError
|
||||||
|
If the bank is guild-specific and guild was not provided.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if await is_global():
|
||||||
|
return await _conf.max_balance()
|
||||||
|
elif guild is not None:
|
||||||
|
return await _conf.guild(guild).max_balance()
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Guild must be provided.")
|
||||||
|
|
||||||
|
|
||||||
|
async def set_max_balance(amount: int, guild: discord.Guild = None) -> int:
|
||||||
|
"""Set the maximum balance for the bank.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
amount : int
|
||||||
|
The new maximum balance.
|
||||||
|
guild : `discord.Guild`, optional
|
||||||
|
The guild to set the max balance for (required if bank is
|
||||||
|
guild-specific).
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
int
|
||||||
|
The new maximum balance.
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
RuntimeError
|
||||||
|
If the bank is guild-specific and guild was not provided.
|
||||||
|
ValueError
|
||||||
|
If the amount is less than 0 or higher than 2 ** 63 - 1.
|
||||||
|
"""
|
||||||
|
if not (0 < amount <= _MAX_BALANCE):
|
||||||
|
raise ValueError(
|
||||||
|
"Amount must be greater than zero and less than {max}.".format(
|
||||||
|
max=humanize_number(_MAX_BALANCE, override_locale="en_US")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if await is_global():
|
||||||
|
await _conf.max_balance.set(amount)
|
||||||
|
elif guild is not None:
|
||||||
|
await _conf.guild(guild).max_balance.set(amount)
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
"Guild must be provided if setting the maximum balance of a guild-specific bank."
|
||||||
|
)
|
||||||
|
return amount
|
||||||
|
|
||||||
|
|
||||||
async def get_default_balance(guild: discord.Guild = None) -> int:
|
async def get_default_balance(guild: discord.Guild = None) -> int:
|
||||||
"""Get the current default balance amount.
|
"""Get the current default balance amount.
|
||||||
|
|
||||||
@ -684,12 +763,18 @@ async def set_default_balance(amount: int, guild: discord.Guild = None) -> int:
|
|||||||
RuntimeError
|
RuntimeError
|
||||||
If the bank is guild-specific and guild was not provided.
|
If the bank is guild-specific and guild was not provided.
|
||||||
ValueError
|
ValueError
|
||||||
If the amount is invalid.
|
If the amount is less than 0 or higher than the max allowed balance.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
amount = int(amount)
|
amount = int(amount)
|
||||||
if amount < 0:
|
max_bal = await get_max_balance(guild)
|
||||||
raise ValueError("Amount must be greater than zero.")
|
|
||||||
|
if not (0 < amount <= max_bal):
|
||||||
|
raise ValueError(
|
||||||
|
"Amount must be greater than zero and less than {max}.".format(
|
||||||
|
max=humanize_number(max_bal, override_locale="en_US")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if await is_global():
|
if await is_global():
|
||||||
await _conf.default_balance.set(amount)
|
await _conf.default_balance.set(amount)
|
||||||
@ -714,7 +799,7 @@ def cost(amount: int):
|
|||||||
You can intentionally refund by raising `AbortPurchase`
|
You can intentionally refund by raising `AbortPurchase`
|
||||||
(this error will be consumed and not show to users)
|
(this error will be consumed and not show to users)
|
||||||
|
|
||||||
Other exceptions will propogate and will be handled by Red's (and/or
|
Other exceptions will propagate and will be handled by Red's (and/or
|
||||||
any other configured) error handling.
|
any other configured) error handling.
|
||||||
"""
|
"""
|
||||||
if not isinstance(amount, int) or amount < 0:
|
if not isinstance(amount, int) or amount < 0:
|
||||||
|
|||||||
@ -46,7 +46,7 @@ class BalanceTooHigh(BankError, OverflowError):
|
|||||||
self.currency_name = currency_name
|
self.currency_name = currency_name
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return _("{user}'s balance cannot rise above max {currency}.").format(
|
return _("{user}'s balance cannot rise above {max} {currency}.").format(
|
||||||
user=self.user, max=humanize_number(self.max_balance), currency=self.currency_name
|
user=self.user, max=humanize_number(self.max_balance), currency=self.currency_name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user