Напоминалки: кнопка удаления списком и ФИО получателей вместо голых id
- В разделе «Напоминалки» добавлена кнопка «🗑 Удалить напоминание» с выбором из списка (как в разделе «Быстрые ответы»), не только текстовая команда. - При выборе получателей и в списке напоминаний теперь показывается ФИО админа из VK рядом со ссылкой (если удалось получить), чтобы не кликать по каждой ссылке для опознания. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -480,6 +480,12 @@ class VKBotApplication:
|
||||
ids |= self._runtime_admins()
|
||||
return sorted(ids)
|
||||
|
||||
def _admin_display(self, uid: int) -> str:
|
||||
"""ФИО из VK + ссылка, если имя удалось получить, иначе только ссылка
|
||||
(используется в мастере напоминалок, чтобы не кликать по каждому id)."""
|
||||
name = self._vk_name(uid)
|
||||
return f"{name} (vk.com/id{uid})" if name else f"vk.com/id{uid}"
|
||||
|
||||
def _send_reminders_admin(self, user_id: int):
|
||||
"""Раздел «Напоминалки»: список активных + инструкции."""
|
||||
rows = db.get_active_reminders()
|
||||
@@ -487,7 +493,7 @@ class VKBotApplication:
|
||||
for r in rows:
|
||||
dt = datetime.strptime(r["next_at"], "%Y-%m-%d %H:%M:%S")
|
||||
who = "всем админам" if r["recipients"] == "all" else \
|
||||
", ".join(f"id{uid}" for uid in r["recipients"])
|
||||
", ".join(self._admin_display(uid) for uid in r["recipients"])
|
||||
period = REMINDER_PERIOD_LABELS.get(r["recurrence"], r["recurrence"])
|
||||
short = (r["text"][:50] + "…") if len(r["text"]) > 50 else r["text"]
|
||||
listing += (f"🔹 [{r['id']}] {dt.strftime('%d.%m.%Y %H:%M')} ({period}) → {who}\n"
|
||||
@@ -497,13 +503,14 @@ class VKBotApplication:
|
||||
kb = VkKeyboard(inline=True)
|
||||
kb.add_button("➕ Добавить", color=VkKeyboardColor.PRIMARY)
|
||||
kb.add_line()
|
||||
kb.add_button("🗑 Удалить напоминание", color=VkKeyboardColor.NEGATIVE)
|
||||
kb.add_line()
|
||||
kb.add_button("В админку ↩️", color=VkKeyboardColor.SECONDARY)
|
||||
self.send_message(
|
||||
user_id,
|
||||
"⏰ Напоминалки\n\n"
|
||||
f"{listing}\n"
|
||||
"Чтобы удалить: напоминалка удалить <id>\n"
|
||||
"Чтобы добавить: нажмите «➕ Добавить»",
|
||||
"Управляйте кнопками ниже: ➕ добавить • 🗑 удалить",
|
||||
keyboard=kb.get_keyboard()
|
||||
)
|
||||
|
||||
@@ -663,6 +670,17 @@ class VKBotApplication:
|
||||
elif text_lower.startswith("напоминалка удалить"):
|
||||
self._handle_reminder_delete(user_id, text_clean)
|
||||
return
|
||||
elif text_lower in ["🗑 удалить напоминание", "удалить напоминание"]:
|
||||
rows = db.get_active_reminders()
|
||||
if not rows:
|
||||
self.send_message(user_id, "Активных напоминаний нет.")
|
||||
self._send_reminders_admin(user_id)
|
||||
return
|
||||
items = [(r["id"], r["text"]) for r in rows]
|
||||
db.update_user_state(user_id, "ADMIN_REMINDER_DEL_PICK")
|
||||
self.send_message(user_id, "🗑 Какое напоминание удалить? Выберите:",
|
||||
keyboard=get_pick_keyboard(items))
|
||||
return
|
||||
elif text_lower in ["уведомления: вкл 🔔", "уведомления: выкл 🔕", "уведомления", "уведомления 🔔", "уведомления 🔕"]:
|
||||
self._toggle_admin_notifications(user_id)
|
||||
return
|
||||
@@ -1697,6 +1715,16 @@ class VKBotApplication:
|
||||
return
|
||||
|
||||
# ---------- Напоминалки ----------
|
||||
if state == "ADMIN_REMINDER_DEL_PICK":
|
||||
rid = pick_id(text)
|
||||
if not rid.isdigit() or not db.delete_reminder(int(rid)):
|
||||
self.send_message(user_id, "⚠️ Выберите напоминание кнопкой ниже.")
|
||||
return
|
||||
db.update_user_state(user_id, "FREE_CHAT")
|
||||
self.send_message(user_id, f"✅ Напоминание №{rid} удалено.")
|
||||
self._send_reminders_admin(user_id)
|
||||
return
|
||||
|
||||
if state == "ADMIN_REMINDER_DATE":
|
||||
dt = parse_reminder_datetime(text)
|
||||
if not dt:
|
||||
@@ -1719,7 +1747,7 @@ class VKBotApplication:
|
||||
self._admin_ctx.setdefault(user_id, {})["text"] = text.strip()
|
||||
admins = self._all_admin_ids()
|
||||
self._admin_ctx[user_id]["admins_list"] = admins
|
||||
listing = "\n".join(f"{i + 1}. vk.com/id{a}" for i, a in enumerate(admins))
|
||||
listing = "\n".join(f"{i + 1}. {self._admin_display(a)}" for i, a in enumerate(admins))
|
||||
db.update_user_state(user_id, "ADMIN_REMINDER_RECIPIENTS")
|
||||
self.send_message(
|
||||
user_id,
|
||||
|
||||
@@ -417,3 +417,18 @@ def test_admin_reminder_delete(app, monkeypatch):
|
||||
# поэтому проверяем все сообщения этого шага, а не только последнее.
|
||||
new_msgs = [s["msg"] for s in app._sent[before:]]
|
||||
assert any("не найдено" in m for m in new_msgs)
|
||||
|
||||
|
||||
def test_admin_reminder_delete_via_picker_button(app, monkeypatch):
|
||||
"""Удаление через кнопку «🗑 Удалить напоминание» + выбор из списка (без ввода id вручную)."""
|
||||
admin = 80005
|
||||
monkeypatch.setattr(bot.config, "ADMIN_IDS", [admin])
|
||||
rid = bot.db.add_reminder("Продлить хостинг", "2099-01-01 09:00:00", "once", [admin], created_by=admin)
|
||||
|
||||
app.handle_message(admin, "⏰ Напоминалки")
|
||||
app.handle_message(admin, "🗑 Удалить напоминание")
|
||||
assert _state(admin) == "ADMIN_REMINDER_DEL_PICK"
|
||||
|
||||
app.handle_message(admin, f"{rid}. Продлить хостинг") # клик по кнопке пикера
|
||||
assert _state(admin) == "FREE_CHAT"
|
||||
assert not bot.db.get_active_reminders()
|
||||
|
||||
Reference in New Issue
Block a user