fix: remove dead query_ads ref, fix /stats for global dedup schema

This commit is contained in:
2026-06-16 22:13:25 +02:00
parent fcd192420f
commit b93811bb1b
2 changed files with 202 additions and 152 deletions
+113 -36
View File
@@ -1,5 +1,6 @@
import logging
from datetime import datetime
from typing import Any
import asyncpg
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
@@ -8,63 +9,139 @@ from telegram.ext import ExtBot
logger = logging.getLogger(__name__)
async def notify_new_ad(
bot: ExtBot,
telegram_id: int,
ad: dict,
) -> None:
def _build_keyboard(ad: dict[str, Any]) -> InlineKeyboardMarkup | None:
keyboard: list[list[InlineKeyboardButton]] = []
if ad.get("url"):
keyboard.append(
[InlineKeyboardButton("View Ad →", url=ad["url"])]
)
return InlineKeyboardMarkup(keyboard) if keyboard else None
def _format_text(header: str, ad: dict[str, Any]) -> str:
title = ad.get("title", "Untitled")
price_str = f"{ad['price']:,.0f}" if ad.get("price") is not None else "N/A"
location_part = ""
if ad.get("location"):
if ad.get("postcode"):
location_part = f" 📍 {ad['location']}, {ad['postcode']}"
else:
location_part = f" 📍 {ad['location']}"
published_str = ""
if ad.get("published_at"):
try:
dt = datetime.fromisoformat(ad["published_at"])
published_str = f"Published: {dt:%d.%m.%Y %H:%M}"
except (ValueError, TypeError):
published_str = f"Published: {ad['published_at']}"
pub = ad["published_at"]
if isinstance(pub, datetime):
published_str = f"{pub.strftime('%d.%m.%Y %H:%M')}"
else:
try:
dt = datetime.fromisoformat(str(pub))
published_str = f"{dt.strftime('%d.%m.%Y %H:%M')}"
except (ValueError, TypeError):
published_str = str(pub)
location_line = f" | 📍 {ad['location']}" if ad.get("location") else ""
modified_str = ""
if ad.get("modified_at"):
mod = ad["modified_at"]
if isinstance(mod, datetime):
modified_str = f"{mod.strftime('%d.%m.%Y %H:%M')}"
else:
try:
dt = datetime.fromisoformat(str(mod))
modified_str = f"{dt.strftime('%d.%m.%Y %H:%M')}"
except (ValueError, TypeError):
modified_str = str(mod)
text = (
f"🔍 New listing found!\n\n"
f"{ad.get('title', 'Untitled')}\n"
f"💰 {price_str}{location_line}\n"
)
text_lines = [
header,
"",
f"<b>{title}</b>",
"",
f"💰 {price_str}{location_part}",
]
if published_str:
text += f"{published_str}\n"
pub_line = f"Published: {published_str}"
if modified_str:
pub_line += f" | Modified: {modified_str}"
text_lines.append(pub_line)
keyboard = []
if ad.get("url"):
keyboard.append(
[InlineKeyboardButton("View Ad", url=ad["url"])]
)
return "\n".join(text_lines)
reply_markup: InlineKeyboardMarkup | None = (
InlineKeyboardMarkup(keyboard) if keyboard else None
)
async def notify_new_ad(
bot: ExtBot,
telegram_id: int,
ad: dict[str, Any],
) -> int | None:
text = _format_text("🆕 New listing found!", ad)
reply_markup = _build_keyboard(ad)
try:
message = await bot.send_message(
chat_id=telegram_id,
text=text,
reply_markup=reply_markup,
)
if ad.get("main_image_url"):
message = await bot.send_photo(
chat_id=telegram_id,
photo=ad["main_image_url"],
caption=text,
parse_mode="HTML",
reply_markup=reply_markup,
)
else:
message = await bot.send_message(
chat_id=telegram_id,
text=text,
parse_mode="HTML",
reply_markup=reply_markup,
)
logger.info(
"Sent notification to %s for ad %s (msg_id=%s)",
telegram_id,
ad.get("wh_ad_id"),
message.message_id,
)
return message.message_id
except Exception:
logger.exception("Failed to send Telegram notification")
return None
async def mark_notified(pool: asyncpg.Pool, search_query_id: str, ad_id: str) -> None:
await pool.execute(
"UPDATE query_ads SET is_notified = true WHERE search_query_id = $1 AND ad_id = $2",
search_query_id,
ad_id,
)
async def notify_price_drop(
bot: ExtBot,
telegram_id: int,
ad: dict[str, Any],
) -> int | None:
text = _format_text("⚠️ Price drop!", ad)
reply_markup = _build_keyboard(ad)
try:
if ad.get("main_image_url"):
message = await bot.send_photo(
chat_id=telegram_id,
photo=ad["main_image_url"],
caption=text,
parse_mode="HTML",
reply_markup=reply_markup,
)
else:
message = await bot.send_message(
chat_id=telegram_id,
text=text,
parse_mode="HTML",
reply_markup=reply_markup,
)
logger.info(
"Sent price drop to %s for ad %s (msg_id=%s)",
telegram_id,
ad.get("wh_ad_id"),
message.message_id,
)
return message.message_id
except Exception:
logger.exception("Failed to send Telegram notification")
return None
async def log_notification(