feat: python worker (bot, scraper, notifier, scheduler)
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
import asyncpg
|
||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import ExtBot
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def notify_new_ad(
|
||||
bot: ExtBot,
|
||||
telegram_id: int,
|
||||
ad: dict,
|
||||
) -> None:
|
||||
price_str = f"{ad['price']:,.0f}" if ad.get("price") is not None else "N/A"
|
||||
|
||||
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']}"
|
||||
|
||||
location_line = f" | 📍 {ad['location']}" if ad.get("location") else ""
|
||||
|
||||
text = (
|
||||
f"🔍 New listing found!\n\n"
|
||||
f"{ad.get('title', 'Untitled')}\n"
|
||||
f"💰 {price_str} €{location_line}\n"
|
||||
)
|
||||
if published_str:
|
||||
text += f"{published_str}\n"
|
||||
|
||||
keyboard = []
|
||||
if ad.get("url"):
|
||||
keyboard.append(
|
||||
[InlineKeyboardButton("View Ad", url=ad["url"])]
|
||||
)
|
||||
|
||||
reply_markup: InlineKeyboardMarkup | None = (
|
||||
InlineKeyboardMarkup(keyboard) if keyboard else None
|
||||
)
|
||||
|
||||
try:
|
||||
message = await bot.send_message(
|
||||
chat_id=telegram_id,
|
||||
text=text,
|
||||
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,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Failed to send Telegram notification")
|
||||
|
||||
|
||||
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 log_notification(
|
||||
pool: asyncpg.Pool, user_id: str, ad_id: str, message_id: int
|
||||
) -> None:
|
||||
await pool.execute(
|
||||
"INSERT INTO notifications (user_id, ad_id, message_id) VALUES ($1, $2, $3)",
|
||||
user_id,
|
||||
ad_id,
|
||||
message_id,
|
||||
)
|
||||
Reference in New Issue
Block a user