1
0
forked from sass/tipibot

Add patch notes to bot

This commit is contained in:
Rene Arumetsa
2026-05-03 12:02:19 +03:00
parent 8529706809
commit 58684d5f34
4 changed files with 174 additions and 0 deletions

3
bot.py
View File

@@ -35,6 +35,7 @@ from commands.economy_profile_commands import register_economy_profile_commands
from commands.economy_support_commands import register_economy_support_commands from commands.economy_support_commands import register_economy_support_commands
from commands.ops_channel_commands import register_ops_channel_commands from commands.ops_channel_commands import register_ops_channel_commands
from commands.ops_admin_commands import register_ops_admin_commands from commands.ops_admin_commands import register_ops_admin_commands
from commands.info_commands import register_info_commands
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Logging # Logging
@@ -483,6 +484,8 @@ register_ops_channel_commands(
set_allowed_channels=_set_allowed_channels, set_allowed_channels=_set_allowed_channels,
) )
register_info_commands(tree, bot, log)
@tree.command(name="ping", description=S.CMD["ping"]) @tree.command(name="ping", description=S.CMD["ping"])
async def cmd_ping(interaction: discord.Interaction): async def cmd_ping(interaction: discord.Interaction):

148
commands/info_commands.py Normal file
View File

@@ -0,0 +1,148 @@
from __future__ import annotations
import logging
import re
from pathlib import Path
import discord
from discord import app_commands
import strings as S
_PATCHNOTES_PATH = Path(__file__).resolve().parent.parent / "docs" / "PATCHNOTES.md"
_VERSION_RE = re.compile(r"^##\s+(.+?)\s*$")
_EMBED_DESC_MAX = 4096
_SELECT_OPTIONS_MAX = 25
def _load_versions() -> list[tuple[str, str]]:
try:
text = _PATCHNOTES_PATH.read_text(encoding="utf-8")
except FileNotFoundError:
return []
versions: list[tuple[str, str]] = []
cur_header: str | None = None
cur_body: list[str] = []
for line in text.splitlines():
m = _VERSION_RE.match(line)
if m:
if cur_header is not None:
versions.append((cur_header, "\n".join(cur_body).strip()))
cur_header = m.group(1).strip()
cur_body = []
elif cur_header is not None:
cur_body.append(line)
if cur_header is not None:
versions.append((cur_header, "\n".join(cur_body).strip()))
return versions
def _build_embed(versions: list[tuple[str, str]], idx: int) -> discord.Embed:
header, body = versions[idx]
if len(body) > _EMBED_DESC_MAX:
body = body[: _EMBED_DESC_MAX - 1] + ""
embed = discord.Embed(
title=S.PATCHNOTES_UI["title"].format(version=header),
description=body or S.PATCHNOTES_UI["empty_version"],
color=0x5865F2,
)
embed.set_footer(
text=S.PATCHNOTES_UI["footer"].format(idx=idx + 1, total=len(versions))
)
return embed
def register_info_commands(
tree: app_commands.CommandTree,
bot: discord.Client,
log: logging.Logger,
) -> None:
@tree.command(name="patchnotes", description=S.CMD["patchnotes"])
async def cmd_patchnotes(interaction: discord.Interaction):
versions = _load_versions()
if not versions:
await interaction.response.send_message(
S.PATCHNOTES_UI["empty_file"], ephemeral=True
)
return
invoker_id = interaction.user.id
class PatchNotesView(discord.ui.View):
def __init__(self, idx: int = 0):
super().__init__(timeout=180)
self.idx = idx
self._rebuild()
def _rebuild(self):
self.clear_items()
newer_btn = discord.ui.Button(
label=S.PATCHNOTES_UI["btn_newer"],
style=discord.ButtonStyle.secondary,
disabled=self.idx <= 0,
)
older_btn = discord.ui.Button(
label=S.PATCHNOTES_UI["btn_older"],
style=discord.ButtonStyle.secondary,
disabled=self.idx >= len(versions) - 1,
)
newer_btn.callback = self._make_step_cb(-1)
older_btn.callback = self._make_step_cb(+1)
self.add_item(newer_btn)
self.add_item(older_btn)
opts: list[discord.SelectOption] = []
for i, (hdr, _) in enumerate(versions[:_SELECT_OPTIONS_MAX]):
opts.append(
discord.SelectOption(
label=hdr[:100],
value=str(i),
default=(i == self.idx),
)
)
if len(opts) > 1:
select = discord.ui.Select(
placeholder=S.PATCHNOTES_UI["select_placeholder"],
options=opts,
min_values=1,
max_values=1,
)
select.callback = self._make_select_cb(select)
self.add_item(select)
def _make_step_cb(self, delta: int):
async def _cb(interaction: discord.Interaction):
if interaction.user.id != invoker_id:
await interaction.response.send_message(
S.ERR["not_your_menu"], ephemeral=True
)
return
self.idx = max(0, min(len(versions) - 1, self.idx + delta))
self._rebuild()
await interaction.response.edit_message(
embed=_build_embed(versions, self.idx), view=self
)
return _cb
def _make_select_cb(self, select: discord.ui.Select):
async def _cb(interaction: discord.Interaction):
if interaction.user.id != invoker_id:
await interaction.response.send_message(
S.ERR["not_your_menu"], ephemeral=True
)
return
self.idx = int(select.values[0])
self._rebuild()
await interaction.response.edit_message(
embed=_build_embed(versions, self.idx), view=self
)
return _cb
view = PatchNotesView(0)
await interaction.response.send_message(
embed=_build_embed(versions, 0), view=view, ephemeral=True
)
log.info("/patchnotes by %s (%d versions)", interaction.user, len(versions))

8
docs/PATCHNOTES.md Normal file
View File

@@ -0,0 +1,8 @@
# TipiBOTi muudatuste logi
Siit leiad ülevaate TipiBOTi uuendustest. Uusimad muudatused on üleval.
Vorminda iga versioon `## ` peakirjaga (nt `## v0.1.0 — 2026-05-03`).
## v0.1.0 — 2026-05-03
- Lisatud `/patchnotes`

View File

@@ -171,6 +171,7 @@ CMD: dict[str, str] = {
"fish": "Mine kalastama (interaktiivne mäng, 2min ooteaeg)", "fish": "Mine kalastama (interaktiivne mäng, 2min ooteaeg)",
"fishbook": "Vaata oma kalakogu ja kogutud kalaliike", "fishbook": "Vaata oma kalakogu ja kogutud kalaliike",
"fishsell": "Müü kalu oma inventarist", "fishsell": "Müü kalu oma inventarist",
"patchnotes": "Vaata TipiBOTi viimaseid muudatusi ja uuendusi",
} }
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -752,6 +753,20 @@ SEND_UI: dict[str, str] = {
"forbidden": "❌ Mul pole õigust kanalisse {channel} kirjutada.", "forbidden": "❌ Mul pole õigust kanalisse {channel} kirjutada.",
} }
# ---------------------------------------------------------------------------
# /patchnotes UI strings
# ---------------------------------------------------------------------------
PATCHNOTES_UI: dict[str, str] = {
"title": "📝 Muudatuste logi — {version}",
"footer": "Versioon {idx}/{total}",
"btn_newer": "◀ Uuem",
"btn_older": "Vanem ▶",
"select_placeholder": "Vali versioon…",
"empty_file": " Muudatuste logi on hetkel tühi.",
"empty_version": "_(selle versiooni kohta märkmeid pole)_",
}
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# /allowchannel /denychannel /channels UI strings # /allowchannel /denychannel /channels UI strings
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------