forked from sass/tipibot
217 lines
8.4 KiB
Python
217 lines
8.4 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
|
|
import discord
|
|
from discord import app_commands
|
|
|
|
import economy
|
|
import strings as S
|
|
|
|
|
|
def register_economy_support_commands(
|
|
tree: app_commands.CommandTree,
|
|
parse_amount: Callable[[str, int], tuple[int | None, str | None]],
|
|
coin: Callable[[int], str],
|
|
cancel_reminder_task: Callable[[int, str], None],
|
|
) -> None:
|
|
class FundModal(discord.ui.Modal):
|
|
summa = discord.ui.TextInput(
|
|
label=S.REQUEST_UI["modal_label"],
|
|
min_length=1,
|
|
max_length=10,
|
|
)
|
|
|
|
def __init__(self, view: "RequestView"):
|
|
super().__init__(title=S.REQUEST_UI["modal_title"])
|
|
self._view = view
|
|
self.summa.placeholder = f"1 - {view.remaining}"
|
|
|
|
async def on_submit(self, interaction: discord.Interaction):
|
|
amount, err = parse_amount(self.summa.value, 0)
|
|
if err or amount is None:
|
|
await interaction.response.send_message(S.ERR["invalid_amount"], ephemeral=True)
|
|
return
|
|
if amount <= 0 or amount > self._view.remaining:
|
|
await interaction.response.send_message(
|
|
S.ERR["fund_range"].format(max=self._view.remaining), ephemeral=True
|
|
)
|
|
return
|
|
|
|
res = await economy.do_give(interaction.user.id, self._view.requester.id, amount)
|
|
if not res["ok"]:
|
|
data = await economy.get_user(interaction.user.id)
|
|
await interaction.response.send_message(
|
|
S.ERR["broke"].format(bal=coin(data["balance"])), ephemeral=True
|
|
)
|
|
return
|
|
|
|
self._view.remaining -= amount
|
|
funded_line = S.REQUEST_UI["funded_line"].format(
|
|
name=interaction.user.display_name,
|
|
amount=coin(amount),
|
|
)
|
|
if self._view.remaining <= 0:
|
|
self._view.fund_btn.disabled = True
|
|
self._view.fund_btn.label = S.REQUEST_UI["btn_funded"]
|
|
self._view.fund_btn.style = discord.ButtonStyle.secondary
|
|
self._view.stop()
|
|
funded_line += S.REQUEST_UI["funded_full"]
|
|
else:
|
|
self._view.fund_btn.label = S.REQUEST_UI["btn_fund_remaining"].format(
|
|
remaining=self._view.remaining
|
|
)
|
|
funded_line += S.REQUEST_UI["funded_partial"].format(
|
|
remaining=coin(self._view.remaining)
|
|
)
|
|
|
|
await interaction.response.send_message(funded_line)
|
|
if self._view.message:
|
|
await self._view.message.edit(view=self._view)
|
|
|
|
class RequestView(discord.ui.View):
|
|
def __init__(self, requester: discord.Member, amount: int, target: discord.Member | None):
|
|
super().__init__(timeout=300)
|
|
self.requester = requester
|
|
self.remaining = amount
|
|
self.target = target
|
|
self.message: discord.Message | None = None
|
|
self.fund_btn = discord.ui.Button(
|
|
label=S.REQUEST_UI["btn_fund"],
|
|
style=discord.ButtonStyle.success,
|
|
)
|
|
self.fund_btn.callback = self._fund
|
|
self.add_item(self.fund_btn)
|
|
|
|
async def _fund(self, interaction: discord.Interaction):
|
|
if interaction.user.id == self.requester.id:
|
|
await interaction.response.send_message(S.ERR["request_self_fund"], ephemeral=True)
|
|
return
|
|
if self.target and interaction.user.id != self.target.id:
|
|
await interaction.response.send_message(
|
|
S.ERR["request_targeted"].format(name=self.target.display_name),
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
await interaction.response.send_modal(FundModal(self))
|
|
|
|
async def on_timeout(self):
|
|
for item in self.children:
|
|
item.disabled = True
|
|
|
|
max_request = 1_000_000
|
|
|
|
@tree.command(name="request", description=S.CMD["request"])
|
|
@app_commands.describe(
|
|
summa=S.OPT["request_summa"],
|
|
põhjus=S.OPT["request_põhjus"],
|
|
sihtmärk=S.OPT["request_sihtmärk"],
|
|
)
|
|
async def cmd_request(
|
|
interaction: discord.Interaction,
|
|
summa: str,
|
|
põhjus: str,
|
|
sihtmärk: discord.Member | None = None,
|
|
):
|
|
summa_int, err = parse_amount(summa, 0)
|
|
if err or summa_int is None:
|
|
await interaction.response.send_message(err or S.ERR["invalid_amount"], ephemeral=True)
|
|
return
|
|
if summa_int <= 0:
|
|
await interaction.response.send_message(S.ERR["positive_amount"], ephemeral=True)
|
|
return
|
|
if summa_int > max_request:
|
|
await interaction.response.send_message(
|
|
S.ERR["fund_range"].format(max=coin(max_request)),
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
summa = summa_int
|
|
if sihtmärk and sihtmärk.id == interaction.user.id:
|
|
await interaction.response.send_message(S.ERR["request_self"], ephemeral=True)
|
|
return
|
|
if sihtmärk and sihtmärk.bot:
|
|
await interaction.response.send_message(S.ERR["request_bot"], ephemeral=True)
|
|
return
|
|
|
|
audience = (
|
|
S.REQUEST_UI["audience_targeted"].format(name=sihtmärk.display_name)
|
|
if sihtmärk
|
|
else S.REQUEST_UI["audience_all"]
|
|
)
|
|
embed = discord.Embed(
|
|
title=S.TITLE["request"],
|
|
description=S.REQUEST_UI["desc"].format(
|
|
requester=interaction.user.display_name,
|
|
amount=coin(summa),
|
|
reason=põhjus,
|
|
audience=audience,
|
|
),
|
|
color=0xF4C430,
|
|
)
|
|
embed.set_footer(text=S.REQUEST_UI["footer"])
|
|
view = RequestView(interaction.user, summa, sihtmärk)
|
|
await interaction.response.send_message(embed=embed, view=view)
|
|
view.message = await interaction.original_response()
|
|
|
|
class RemindersSelect(discord.ui.Select):
|
|
def __init__(self, user_id: int, current: list[str]):
|
|
self.user_id = user_id
|
|
options = [
|
|
discord.SelectOption(
|
|
label=label,
|
|
description=desc,
|
|
value=cmd,
|
|
default=cmd in current,
|
|
)
|
|
for cmd, label, desc in S.REMINDER_OPTS
|
|
]
|
|
super().__init__(
|
|
placeholder=S.REMINDERS_UI["select_placeholder"],
|
|
options=options,
|
|
min_values=0,
|
|
max_values=len(S.REMINDER_OPTS),
|
|
)
|
|
|
|
async def callback(self, interaction: discord.Interaction):
|
|
if interaction.user.id != self.user_id:
|
|
await interaction.response.send_message(S.ERR["not_your_menu"], ephemeral=True)
|
|
return
|
|
await economy.do_set_reminders(self.user_id, self.values)
|
|
enabled = set(self.values)
|
|
for cmd in [opt[0] for opt in S.REMINDER_OPTS]:
|
|
if cmd not in enabled:
|
|
cancel_reminder_task(self.user_id, cmd)
|
|
if self.values:
|
|
names = " ".join(f"`/{v}`" for v in self.values)
|
|
msg = S.REMINDERS_UI["saved_on"].format(names=names)
|
|
else:
|
|
msg = S.REMINDERS_UI["saved_off"]
|
|
await interaction.response.send_message(msg, ephemeral=True)
|
|
|
|
class RemindersView(discord.ui.View):
|
|
def __init__(self, user_id: int, current: list[str]):
|
|
super().__init__(timeout=60)
|
|
self.add_item(RemindersSelect(user_id, current))
|
|
|
|
@tree.command(name="reminders", description=S.CMD["reminders"])
|
|
async def cmd_reminders(interaction: discord.Interaction):
|
|
user_data = await economy.get_user(interaction.user.id)
|
|
current = user_data.get("reminders", [])
|
|
if current:
|
|
status = " ".join(f"`/{c}`" for c in current)
|
|
desc = S.REMINDERS_UI["desc_active"].format(status=status)
|
|
else:
|
|
desc = S.REMINDERS_UI["desc_none"]
|
|
embed = discord.Embed(
|
|
title=S.TITLE["reminders"],
|
|
description=desc,
|
|
color=0x5865F2,
|
|
)
|
|
embed.set_footer(text=S.REMINDERS_UI["footer"])
|
|
await interaction.response.send_message(
|
|
embed=embed,
|
|
view=RemindersView(interaction.user.id, current),
|
|
ephemeral=True,
|
|
)
|