feat(bot): refresh groups list — manual button + auto event listener
Group sync previously only ran once at pairing time, so groups created in
WhatsApp afterwards never showed up.
Two complementary fixes:
- 🔄 Refresh button in the groups list view triggers
syncGroupsForAccount() on demand and re-renders the menu
- session.ts now subscribes to Baileys 'groups.upsert' and 'groups.update'
events and re-syncs (debounced 1.5s) so new groups appear without
manual action
This commit is contained in:
parent
5259f88776
commit
43882d5a1b
@ -19,6 +19,7 @@ import {
|
|||||||
showGroupDetail,
|
showGroupDetail,
|
||||||
showSendTestPrompt,
|
showSendTestPrompt,
|
||||||
executeSendTest,
|
executeSendTest,
|
||||||
|
refreshGroupsList,
|
||||||
} from "./callbacks.js";
|
} from "./callbacks.js";
|
||||||
import {
|
import {
|
||||||
consumePendingPairLabel,
|
consumePendingPairLabel,
|
||||||
@ -82,6 +83,9 @@ export function createTelegramBot(): Bot {
|
|||||||
bot.callbackQuery(/^st:(.+)$/, async (ctx) => {
|
bot.callbackQuery(/^st:(.+)$/, async (ctx) => {
|
||||||
await showSendTestPrompt(ctx, ctx.match[1]!);
|
await showSendTestPrompt(ctx, ctx.match[1]!);
|
||||||
});
|
});
|
||||||
|
bot.callbackQuery(/^rs:(.+)$/, async (ctx) => {
|
||||||
|
await refreshGroupsList(ctx, ctx.match[1]!);
|
||||||
|
});
|
||||||
|
|
||||||
// Plain-text messages: if the operator is in the "pending pair label" state
|
// Plain-text messages: if the operator is in the "pending pair label" state
|
||||||
// (because they tapped 📡 Pair New), treat their next non-command message as
|
// (because they tapped 📡 Pair New), treat their next non-command message as
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { sessionManager } from "../whatsapp/session-manager.js";
|
|||||||
import { writeAuditLog } from "../audit.js";
|
import { writeAuditLog } from "../audit.js";
|
||||||
import { setPendingPairLabel, setPendingSendToGroup } from "./state.js";
|
import { setPendingPairLabel, setPendingSendToGroup } from "./state.js";
|
||||||
import { sendTextToGroup } from "../whatsapp/sender.js";
|
import { sendTextToGroup } from "../whatsapp/sender.js";
|
||||||
|
import { syncGroupsForAccount } from "../whatsapp/group-sync.js";
|
||||||
import {
|
import {
|
||||||
mainMenu,
|
mainMenu,
|
||||||
helpMenu,
|
helpMenu,
|
||||||
@ -92,6 +93,38 @@ export async function showGroupsList(ctx: Context, accountId: string): Promise<v
|
|||||||
await showMenu(ctx, view);
|
await showMenu(ctx, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function refreshGroupsList(ctx: Context, accountId: string): Promise<void> {
|
||||||
|
const op = await findOperator(ctx);
|
||||||
|
if (!op) {
|
||||||
|
await ctx.answerCallbackQuery();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const account = await db.query.whatsappAccounts.findFirst({
|
||||||
|
where: (a, { eq, and }) => and(eq(a.id, accountId), eq(a.operatorId, op.id)),
|
||||||
|
});
|
||||||
|
if (!account) {
|
||||||
|
await ctx.answerCallbackQuery({ text: "Account not found.", show_alert: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const session = sessionManager.getSession(accountId);
|
||||||
|
if (!session) {
|
||||||
|
await ctx.answerCallbackQuery({
|
||||||
|
text: "Account not connected. Re-pair first.",
|
||||||
|
show_alert: true,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await ctx.answerCallbackQuery({ text: "Refreshing…" });
|
||||||
|
try {
|
||||||
|
const result = await syncGroupsForAccount(accountId, session.socket);
|
||||||
|
logger.info({ accountId, count: result.synced }, "refreshGroupsList: ok");
|
||||||
|
} catch (err) {
|
||||||
|
logger.error({ err, accountId }, "refreshGroupsList: failed");
|
||||||
|
}
|
||||||
|
const view = await groupsListMenu(op.id, accountId);
|
||||||
|
if (view) await showMenu(ctx, view);
|
||||||
|
}
|
||||||
|
|
||||||
export async function showUnpairConfirm(ctx: Context, accountId: string): Promise<void> {
|
export async function showUnpairConfirm(ctx: Context, accountId: string): Promise<void> {
|
||||||
await ctx.answerCallbackQuery();
|
await ctx.answerCallbackQuery();
|
||||||
const op = await findOperator(ctx);
|
const op = await findOperator(ctx);
|
||||||
|
|||||||
@ -144,18 +144,22 @@ export async function groupsListMenu(
|
|||||||
const name = g.name.length > 32 ? `${g.name.slice(0, 31)}…` : g.name;
|
const name = g.name.length > 32 ? `${g.name.slice(0, 31)}…` : g.name;
|
||||||
keyboard.text(`👥 ${name}`, `gr:${g.id}`).row();
|
keyboard.text(`👥 ${name}`, `gr:${g.id}`).row();
|
||||||
}
|
}
|
||||||
keyboard.text("⬅ Account", `acc:${accountId}`).text("⬅ Main Menu", "m:main");
|
keyboard
|
||||||
|
.text("🔄 Refresh", `rs:${accountId}`)
|
||||||
|
.row()
|
||||||
|
.text("⬅ Account", `acc:${accountId}`)
|
||||||
|
.text("⬅ Main Menu", "m:main");
|
||||||
|
|
||||||
if (groups.length === 0) {
|
if (groups.length === 0) {
|
||||||
return {
|
return {
|
||||||
text: `👥 *Groups in ${account.label}*\n\nNo groups synced yet.`,
|
text: `👥 *Groups in ${account.label}*\n\nNo groups synced yet. Tap *Refresh* to pull the latest list.`,
|
||||||
keyboard,
|
keyboard,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const overflow = groups.length > 30 ? `\n\n_…${groups.length - 30} more not shown_` : "";
|
const overflow = groups.length > 30 ? `\n\n_…${groups.length - 30} more not shown_` : "";
|
||||||
return {
|
return {
|
||||||
text: `👥 *Groups in ${account.label}*\n\nTap a group to send a test message.${overflow}`,
|
text: `👥 *Groups in ${account.label}*\n\nTap a group to send a test message, or *Refresh* to pick up new groups.${overflow}`,
|
||||||
keyboard,
|
keyboard,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
} from "@whiskeysockets/baileys";
|
} from "@whiskeysockets/baileys";
|
||||||
import { logger } from "../logger.js";
|
import { logger } from "../logger.js";
|
||||||
import { env } from "../env.js";
|
import { env } from "../env.js";
|
||||||
|
import { syncGroupsForAccount } from "./group-sync.js";
|
||||||
|
|
||||||
export type SessionEvent =
|
export type SessionEvent =
|
||||||
| { type: "qr"; payload: string }
|
| { type: "qr"; payload: string }
|
||||||
@ -50,6 +51,22 @@ export async function startSession(params: {
|
|||||||
|
|
||||||
socket.ev.on("creds.update", () => void saveCreds());
|
socket.ev.on("creds.update", () => void saveCreds());
|
||||||
|
|
||||||
|
// Keep `whatsapp_groups` in sync as Baileys discovers new groups or updates.
|
||||||
|
// Debounced so a flurry of upsert events from the initial sync collapses
|
||||||
|
// into a single DB write.
|
||||||
|
let groupsSyncTimer: NodeJS.Timeout | null = null;
|
||||||
|
const scheduleGroupsSync = (): void => {
|
||||||
|
if (groupsSyncTimer) return;
|
||||||
|
groupsSyncTimer = setTimeout(() => {
|
||||||
|
groupsSyncTimer = null;
|
||||||
|
void syncGroupsForAccount(accountId, socket).catch((err) =>
|
||||||
|
logger.warn({ err, accountId }, "auto group sync failed"),
|
||||||
|
);
|
||||||
|
}, 1500);
|
||||||
|
};
|
||||||
|
socket.ev.on("groups.upsert", scheduleGroupsSync);
|
||||||
|
socket.ev.on("groups.update", scheduleGroupsSync);
|
||||||
|
|
||||||
socket.ev.on("connection.update", (update: Partial<ConnectionState>) => {
|
socket.ev.on("connection.update", (update: Partial<ConnectionState>) => {
|
||||||
if (update.qr) {
|
if (update.qr) {
|
||||||
void onEvent({ type: "qr", payload: update.qr });
|
void onEvent({ type: "qr", payload: update.qr });
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user