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.
This commit is contained in:
2026-05-09 22:37:39 +07:00
parent dbb6d0e015
commit 0f0f9b93f3
3 changed files with 8 additions and 1 deletions
+4
View File
@@ -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 {
+3 -1
View File
@@ -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');
};
}
+1
View File
@@ -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({