fix: skip notifications during baseline load, add /interval command with /list display
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
CREATE TABLE IF NOT EXISTS keywords (
|
CREATE TABLE IF NOT EXISTS keywords (
|
||||||
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
keyword text NOT NULL,
|
keyword text NOT NULL,
|
||||||
interval_minutes int NOT NULL DEFAULT 60,
|
interval_minutes int NOT NULL DEFAULT 5,
|
||||||
is_active boolean NOT NULL DEFAULT true,
|
is_active boolean NOT NULL DEFAULT true,
|
||||||
last_scraped_at timestamptz,
|
last_scraped_at timestamptz,
|
||||||
initial_loaded boolean NOT NULL DEFAULT false,
|
initial_loaded boolean NOT NULL DEFAULT false,
|
||||||
|
|||||||
+79
-2
@@ -79,6 +79,7 @@ def register_handlers(app: Application) -> None:
|
|||||||
app.add_handler(CommandHandler("add", add_handler))
|
app.add_handler(CommandHandler("add", add_handler))
|
||||||
app.add_handler(CommandHandler("list", list_handler))
|
app.add_handler(CommandHandler("list", list_handler))
|
||||||
app.add_handler(CommandHandler("delete", delete_handler))
|
app.add_handler(CommandHandler("delete", delete_handler))
|
||||||
|
app.add_handler(CommandHandler("interval", interval_handler))
|
||||||
app.add_handler(CommandHandler("stats", stats_handler))
|
app.add_handler(CommandHandler("stats", stats_handler))
|
||||||
app.add_handler(CommandHandler("adduser", adduser_handler))
|
app.add_handler(CommandHandler("adduser", adduser_handler))
|
||||||
app.add_handler(CommandHandler("removeuser", removeuser_handler))
|
app.add_handler(CommandHandler("removeuser", removeuser_handler))
|
||||||
@@ -99,6 +100,7 @@ async def start_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> N
|
|||||||
"/add <keyword> — Subscribe to a keyword (shared across users)\n"
|
"/add <keyword> — Subscribe to a keyword (shared across users)\n"
|
||||||
"/list — List your subscriptions\n"
|
"/list — List your subscriptions\n"
|
||||||
"/delete <keyword_id> — Unsubscribe from a keyword\n"
|
"/delete <keyword_id> — Unsubscribe from a keyword\n"
|
||||||
|
"/interval <keyword_id> <minutes> — Change scrape interval\n"
|
||||||
"/stats — View your tracking statistics",
|
"/stats — View your tracking statistics",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -127,7 +129,7 @@ async def add_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> Non
|
|||||||
if not existing:
|
if not existing:
|
||||||
kw_id = str(uuid.uuid4())
|
kw_id = str(uuid.uuid4())
|
||||||
await pool.execute(
|
await pool.execute(
|
||||||
"INSERT INTO keywords (id, keyword, interval_minutes, is_active) VALUES ($1, $2, 60, true)",
|
"INSERT INTO keywords (id, keyword, interval_minutes, is_active) VALUES ($1, $2, 5, true)",
|
||||||
kw_id,
|
kw_id,
|
||||||
keyword,
|
keyword,
|
||||||
)
|
)
|
||||||
@@ -171,7 +173,7 @@ async def list_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
|
|||||||
|
|
||||||
pool = await get_pool()
|
pool = await get_pool()
|
||||||
subscriptions = await pool.fetch(
|
subscriptions = await pool.fetch(
|
||||||
"SELECT kw.id, kw.keyword, kw.is_active, kw.last_scraped_at, COUNT(ks2.user_id) AS subs "
|
"SELECT kw.id, kw.keyword, kw.is_active, kw.interval_minutes, kw.last_scraped_at, COUNT(ks2.user_id) AS subs "
|
||||||
"FROM keyword_subscriptions ks "
|
"FROM keyword_subscriptions ks "
|
||||||
"JOIN keywords kw ON kw.id = ks.keyword_id "
|
"JOIN keywords kw ON kw.id = ks.keyword_id "
|
||||||
"LEFT JOIN keyword_subscriptions ks2 ON ks2.keyword_id = ks.keyword_id "
|
"LEFT JOIN keyword_subscriptions ks2 ON ks2.keyword_id = ks.keyword_id "
|
||||||
@@ -194,12 +196,87 @@ async def list_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> No
|
|||||||
f"{i}. \"{s['keyword']}\"\n"
|
f"{i}. \"{s['keyword']}\"\n"
|
||||||
f" ID: {s['id']}\n"
|
f" ID: {s['id']}\n"
|
||||||
f" Status: {status}{subs}\n"
|
f" Status: {status}{subs}\n"
|
||||||
|
f" Interval: {s['interval_minutes']} min\n"
|
||||||
f" Last scraped: {last}"
|
f" Last scraped: {last}"
|
||||||
)
|
)
|
||||||
|
|
||||||
await update.message.reply_text("\n\n".join(lines)) # type: ignore[union-attr]
|
await update.message.reply_text("\n\n".join(lines)) # type: ignore[union-attr]
|
||||||
|
|
||||||
|
|
||||||
|
# -- /interval ------------------------------------------------------------
|
||||||
|
|
||||||
|
async def interval_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
row = await _require_user(update)
|
||||||
|
if not row:
|
||||||
|
return
|
||||||
|
|
||||||
|
text = (update.message or update.callback_query).text or "" # type: ignore[union-attr]
|
||||||
|
parts = text.split()
|
||||||
|
if len(parts) < 3:
|
||||||
|
await update.message.reply_text("Usage: /interval <keyword_id> <minutes>") # type: ignore[union-attr]
|
||||||
|
return
|
||||||
|
|
||||||
|
keyword_id = parts[1].strip()
|
||||||
|
try:
|
||||||
|
uuid.UUID(keyword_id)
|
||||||
|
except ValueError:
|
||||||
|
await update.message.reply_text("Invalid keyword ID format.") # type: ignore[union-attr]
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
minutes = int(parts[2])
|
||||||
|
except ValueError:
|
||||||
|
await update.message.reply_text("Interval must be a number (minutes).") # type: ignore[union-attr]
|
||||||
|
return
|
||||||
|
|
||||||
|
if minutes < 1 or minutes > 1440:
|
||||||
|
await update.message.reply_text("Interval must be between 1 and 1440 minutes.") # type: ignore[union-attr]
|
||||||
|
return
|
||||||
|
|
||||||
|
pool = await get_pool()
|
||||||
|
|
||||||
|
sub_check = await pool.fetchrow(
|
||||||
|
"SELECT 1 FROM keyword_subscriptions WHERE keyword_id = $1 AND user_id = $2",
|
||||||
|
keyword_id,
|
||||||
|
row["id"],
|
||||||
|
)
|
||||||
|
if not sub_check:
|
||||||
|
await update.message.reply_text("You are not subscribed to this keyword.") # type: ignore[union-attr]
|
||||||
|
return
|
||||||
|
|
||||||
|
kw_row = await pool.fetchrow(
|
||||||
|
"SELECT id, interval_minutes FROM keywords WHERE id = $1",
|
||||||
|
keyword_id,
|
||||||
|
)
|
||||||
|
if not kw_row:
|
||||||
|
await update.message.reply_text("Keyword not found.") # type: ignore[union-attr]
|
||||||
|
return
|
||||||
|
|
||||||
|
old_interval = kw_row["interval_minutes"]
|
||||||
|
await pool.execute(
|
||||||
|
"UPDATE keywords SET interval_minutes = $1 WHERE id = $2",
|
||||||
|
minutes,
|
||||||
|
keyword_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
sub_count = await pool.fetchval(
|
||||||
|
"SELECT COUNT(*) FROM keyword_subscriptions WHERE keyword_id = $1",
|
||||||
|
keyword_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
if sub_count > 1:
|
||||||
|
await update.message.reply_text( # type: ignore[union-attr]
|
||||||
|
f"Interval updated: {old_interval} min → {minutes} min\n"
|
||||||
|
f"(affects all {sub_count} subscriber(s))",
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text( # type: ignore[union-attr]
|
||||||
|
f"Interval updated: {old_interval} min → {minutes} min",
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info("User %s changed interval for keyword '%s' to %d min", update.effective_user.id, keyword_id, minutes)
|
||||||
|
|
||||||
|
|
||||||
# -- /delete --------------------------------------------------------------
|
# -- /delete --------------------------------------------------------------
|
||||||
|
|
||||||
async def delete_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
async def delete_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
|||||||
+1
-1
@@ -96,7 +96,7 @@ async def scheduler_task(pool: object, bot: ExtBot) -> None:
|
|||||||
fields.get("main_image_url"), fields.get("postcode"), ad_uuid,
|
fields.get("main_image_url"), fields.get("postcode"), ad_uuid,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not initial_loaded:
|
if initial_loaded:
|
||||||
notify_fields = {**fields, "keyword": keyword}
|
notify_fields = {**fields, "keyword": keyword}
|
||||||
for tg_id in telegram_ids:
|
for tg_id in telegram_ids:
|
||||||
await notify_new_ad(bot, tg_id, notify_fields)
|
await notify_new_ad(bot, tg_id, notify_fields)
|
||||||
|
|||||||
Reference in New Issue
Block a user