From 0f0f9b93f380569a4a0cb3ccfd196d4e9d219781 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sat, 9 May 2026 22:37:39 +0700 Subject: [PATCH] fix: /delgroup wipes group key + scheduler/checkapp guard non-finite updated /delgroup previously only removed the chatId from the admin allowlist; the matching group:{chatId} key (with its tracked-app state) was left in Redis with no TTL. Re-adding the same group later resurrected the old subscription list. Now the command calls store.group.deleteGroup after the admin removal succeeds. The scheduler's Google branch and /checkapp's Google rows path both called daysBetween(updatedMs, now) without guarding non-finite updatedMs values, unlike the parallel Apple branches. A garbage upstream value would have produced NaN days. Skip those entries. --- src/bot/commands/check-app.js | 4 ++++ src/bot/commands/delete-group.js | 4 +++- src/scheduler/scheduler.js | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bot/commands/check-app.js b/src/bot/commands/check-app.js index 8a7080a..24d20cb 100644 --- a/src/bot/commands/check-app.js +++ b/src/bot/commands/check-app.js @@ -60,6 +60,10 @@ async function googleRowsFor(apps, scraper, nowMs, threshold, timezone) { continue; } const updatedMs = Number(resp.updated); + if (!Number.isFinite(updatedMs)) { + rows.push([a.appId, '?', '?', mark(false)]); + continue; + } const days = daysBetween(updatedMs, nowMs); rows.push([a.appId, formatDateInTz(new Date(updatedMs), timezone), String(days), mark(days <= threshold)]); } catch { diff --git a/src/bot/commands/delete-group.js b/src/bot/commands/delete-group.js index 1f41635..181b236 100644 --- a/src/bot/commands/delete-group.js +++ b/src/bot/commands/delete-group.js @@ -1,6 +1,7 @@ import { requireAdminUser } from './command-utils.js'; -// /delgroup [groupId] — admin-only. +// /delgroup [groupId] — admin-only. Removes from allowlist AND wipes the +// group's tracked-app state to avoid orphaned `group:{chatId}` keys. export function createDeleteGroupCommand(config, store) { return async (msg, sender, args) => { if (!(await requireAdminUser(msg.from.id, msg.chat.id, config, sender))) return; @@ -22,6 +23,7 @@ export function createDeleteGroupCommand(config, store) { await sender.sendMessage(msg.chat.id, 'Group is not added'); return; } + await store.group.deleteGroup(groupId); await sender.sendMessage(msg.chat.id, 'Group deleted successfully'); }; } diff --git a/src/scheduler/scheduler.js b/src/scheduler/scheduler.js index f1ec14b..c66ca67 100644 --- a/src/scheduler/scheduler.js +++ b/src/scheduler/scheduler.js @@ -68,6 +68,7 @@ async function checkGroup(groupId, silent, now, config, store, sender, appleScra const app = await googleScraper.getApp(info.appId, info.country); if (!app) continue; const updatedMs = Number(app.updated); + if (!Number.isFinite(updatedMs)) continue; const days = daysBetween(updatedMs, now.getTime()); if (days > threshold) { stale.push({