fix: summary message, stats back, admin cancel/back buttons, keyword added confirmation, notifications logging

This commit is contained in:
2026-06-17 13:18:33 +02:00
parent c48706ac9c
commit b59a2ab922
3 changed files with 70 additions and 12 deletions
+16
View File
@@ -0,0 +1,16 @@
# Agent Instructions
## Standard Practice
- **Always use subagents** (`Task` tool) to implement code changes unless explicitly told otherwise by the user. This optimizes token usage and enables parallel work.
- Each subagent should handle a single, well-scoped task with clear acceptance criteria.
- After subagents complete, verify syntax, commit, and deploy.
## Deployment Pattern
```bash
ssh tizona "cd /mnt/user/appdata/willhaben-tracker && docker compose down worker && git pull origin main && docker compose build worker --no-cache && docker compose up -d"
```
## Key Context
- Bot token: `8653489932:AAG_Ins2_z3sNHX8ZlGI4mhyzmUhWAWCZlg` (in `.env`)
- Admin TG ID: `298181113`
- PTB v21, asyncpg with Postgres 15
+41 -6
View File
@@ -180,7 +180,6 @@ def _admin_menu_keyboard() -> InlineKeyboardMarkup:
[InlineKeyboardButton(" Add User", callback_data="admin_add"),
InlineKeyboardButton("👥 List Users", callback_data="admin_list")],
[InlineKeyboardButton("🗑 Remove User", callback_data="admin_remove")],
[InlineKeyboardButton("↩ Back", callback_data="menu:")],
])
@@ -384,6 +383,8 @@ async def text_input_handler(update: Update, context: ContextTypes.DEFAULT_TYPE)
context.user_data.clear()
logger.info("Admin added user %d", tg_id)
await update.message.reply_text( # type: ignore[union-attr]
"<b>⚙️ Admin Panel</b>", parse_mode="HTML", reply_markup=_admin_menu_keyboard())
# ── admin: awaiting TG ID to remove user ──────────────────────────
elif state == "admin_awaiting_tg_id_remove":
@@ -428,6 +429,8 @@ async def text_input_handler(update: Update, context: ContextTypes.DEFAULT_TYPE)
context.user_data.clear()
logger.info("Admin removed user %d", tg_id)
await update.message.reply_text( # type: ignore[union-attr]
"<b>⚙️ Admin Panel</b>", parse_mode="HTML", reply_markup=_admin_menu_keyboard())
# ── callback router (handles ALL inline button clicks) ────────────────────
@@ -507,12 +510,16 @@ async def _handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
)
name = user["first_name"] or "there"
summary_chat_id = update.effective_chat.id # type: ignore[union-attr]
try:
await context.bot.send_message(
chat_id=chat_id,
chat_id=summary_chat_id,
text=f"<b>That was all your listings, {name}!</b>\n\nAnything else I can help with?",
parse_mode="HTML",
reply_markup=_main_menu_keyboard(),
)
except Exception:
logger.exception("Failed to send summary message for user %s", user["id"])
elif sub == "stats":
total_kw = await pool.fetchval(
@@ -529,7 +536,12 @@ async def _handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
f"Ads indexed: <code>{total_ads}</code>\n"
f"Notifications sent: <code>{total_notifs}</code>"
)
await query.edit_message_text(text=text, parse_mode="HTML")
await query.edit_message_text(
text=text, parse_mode="HTML",
reply_markup=InlineKeyboardMarkup([
[InlineKeyboardButton("↩ Back", callback_data="back:admin")],
]),
)
else:
# Empty payload — "Back" button from sub-menus, show main menu
@@ -601,7 +613,10 @@ async def _handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
await _edit_or_send(
context.bot, chat_id, msg_id, # type: ignore[arg-type]
f'<b>✅ Keyword added!</b>\n\n<blockquote>"{keyword_text}"</blockquote>{extra}',
f'<b>✅ Keyword added!</b>\n\n"{keyword_text}"{extra}',
reply_markup=InlineKeyboardMarkup([
[InlineKeyboardButton("↩ Back", callback_data="menu:")],
]),
)
logger.info("User %s subscribed to '%s'", update.effective_user.id, keyword_text)
@@ -789,13 +804,28 @@ async def _handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
# ADMIN FLOWS
# ════════════════════════════════════════════════════════════════════
elif action == "back":
if payload == "admin":
context.user_data.clear()
try:
await query.edit_message_text(
"<b>⚙️ Admin Panel</b>", parse_mode="HTML",
reply_markup=_admin_menu_keyboard())
except Exception:
await query.answer(show_alert=True)
elif action == "admin_add":
admin_row = await _require_admin(update)
if not admin_row:
return
context.user_data["state"] = "admin_awaiting_tg_id_add"
context.user_data["admin_action_msg_id"] = msg_id
await query.edit_message_text("Enter the Telegram user ID to add:", parse_mode="HTML")
await query.edit_message_text(
"Enter the Telegram user ID to add:", parse_mode="HTML",
reply_markup=InlineKeyboardMarkup([
[InlineKeyboardButton("❌ Cancel", callback_data="back:admin")],
]),
)
elif action == "admin_list":
admin_row = await _require_admin(update)
@@ -831,4 +861,9 @@ async def _handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -
return
context.user_data["state"] = "admin_awaiting_tg_id_remove"
context.user_data["admin_action_msg_id"] = msg_id
await query.edit_message_text("Enter the Telegram user ID to remove:", parse_mode="HTML")
await query.edit_message_text(
"Enter the Telegram user ID to remove:", parse_mode="HTML",
reply_markup=InlineKeyboardMarkup([
[InlineKeyboardButton("❌ Cancel", callback_data="back:admin")],
]),
)
+8 -1
View File
@@ -79,7 +79,14 @@ async def scheduler_task(pool: object, bot: ExtBot) -> None:
if initial_loaded:
notify_fields = {**fields, "keyword": keyword}
for tg_id in telegram_ids:
await notify_new_ad(bot, tg_id, notify_fields)
msg_id_val = await notify_new_ad(bot, tg_id, notify_fields)
if msg_id_val:
user_row = await pool.fetchrow("SELECT id FROM users WHERE telegram_id = $1", tg_id)
if user_row:
try:
await log_notification(pool, str(user_row["id"]), ad_uuid, msg_id_val)
except Exception:
logger.exception("Failed to log new ad notification")
new_count += 1
else:
ad_uuid = str(existing["id"])