feat: habilitar sync multicomunidad y persistir nombres de grupos

Co-authored-by: aider (openrouter/openai/gpt-5) <aider@aider.chat>
main
brobert 1 month ago
parent 46d172fc12
commit 228f2d40a2

@ -330,6 +330,7 @@ export class WebhookServer {
.prepare(`SELECT 1 FROM allowed_groups WHERE group_id = ? LIMIT 1`)
.get(remoteJid) as any;
if (!exists) {
try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {}
try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {}
try { Metrics.inc('unknown_groups_discovered_total'); } catch {}
try {
@ -347,6 +348,7 @@ export class WebhookServer {
}
} catch {
// Si la tabla no existe por alguna razón, intentar upsert y retornar igualmente
try { await GroupSyncService.ensureGroupLabelAndName(remoteJid); } catch {}
try { AllowedGroups.upsertPending(remoteJid, (GroupSyncService.activeGroupsCache.get(remoteJid) || null), normalizedSenderId); } catch {}
try { Metrics.inc('unknown_groups_discovered_total'); } catch {}
try {

@ -80,39 +80,14 @@ export class GroupSyncService {
Metrics.inc('sync_runs_total');
try {
const communityId = process.env.WHATSAPP_COMMUNITY_ID;
if (!communityId) {
console.log(' WHATSAPP_COMMUNITY_ID no definido - mostrando todas las comunidades');
const groups = await this.fetchGroupsFromAPI();
const communities = groups.filter(g => g.linkedParent);
// Intento best-effort de rellenar labels faltantes en allowed_groups usando la lista completa
try { (AllowedGroups as any).dbInstance = this.dbInstance; this.fillMissingAllowedGroupLabels(groups); } catch {}
return { added: 0, updated: 0 }; // No sync when just listing
}
const groups = await this.fetchGroupsFromAPI();
console.log(' Grupos crudos de la API:', JSON.stringify(groups, null, 2));
const communityGroups = groups.filter((group) => {
const matches = group.linkedParent === communityId;
console.log(` Grupo ${group.id} (${group.subject}):`, {
linkedParent: group.linkedParent,
matchesCommunity: matches,
isCommunityItself: group.id === communityId
});
return matches;
});
console.log(' Grupos que pasaron el filtro:', communityGroups.map(g => ({
id: g.id,
name: g.subject,
parent: g.linkedParent
})));
console.log(' Sin filtrar por comunidad (modo multicomunidad). Total grupos:', groups.length);
const dbGroupsBefore = this.dbInstance.prepare('SELECT id, active FROM groups').all();
console.log(' Grupos en DB antes de upsert:', dbGroupsBefore);
const result = await this.upsertGroups(communityGroups);
const result = await this.upsertGroups(groups);
const dbGroupsAfter = this.dbInstance.prepare('SELECT id, active FROM groups').all();
console.log(' Grupos en DB después de upsert:', dbGroupsAfter);
@ -368,14 +343,14 @@ export class GroupSyncService {
if (existing) {
const updateResult = this.dbInstance.prepare(
'UPDATE groups SET name = ?, active = TRUE, last_verified = CURRENT_TIMESTAMP WHERE id = ?'
).run(group.subject, group.id);
'UPDATE groups SET name = ?, community_id = COALESCE(?, community_id), active = TRUE, last_verified = CURRENT_TIMESTAMP WHERE id = ?'
).run(group.subject, group.linkedParent || null, group.id);
console.log('Updated group:', group.id, 'result:', updateResult);
updated++;
} else {
const insertResult = this.dbInstance.prepare(
'INSERT INTO groups (id, community_id, name, active) VALUES (?, ?, ?, TRUE)'
).run(group.id, process.env.WHATSAPP_COMMUNITY_ID, group.subject);
).run(group.id, group.linkedParent || null, group.subject);
console.log('Added group:', group.id, 'result:', insertResult);
added++;
}
@ -860,6 +835,54 @@ export class GroupSyncService {
return { created, reactivated, updatedName };
}
/**
* Asegura tener el nombre/label de un grupo (cache/DB/API) y lo persiste tanto en groups como en allowed_groups.
* Devuelve el nombre si se pudo resolver, o null en caso contrario.
*/
public static async ensureGroupLabelAndName(groupId: string): Promise<string | null> {
try {
if (!groupId) return null;
// 1) Cache en memoria
const cached = this.activeGroupsCache.get(groupId);
if (cached && cached.trim()) {
try { this.ensureGroupExists(groupId, cached); } catch {}
try { (AllowedGroups as any).dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, cached, null); } catch {}
this.cacheActiveGroups();
return cached;
}
// 2) DB (tabla groups)
try {
const row = this.dbInstance.prepare('SELECT name FROM groups WHERE id = ?').get(groupId) as any;
const name = row?.name ? String(row.name).trim() : '';
if (name) {
try { this.ensureGroupExists(groupId, name); } catch {}
try { (AllowedGroups as any).dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, name, null); } catch {}
this.cacheActiveGroups();
return name;
}
} catch {}
// 3) API (evitar en tests)
if (process.env.NODE_ENV !== 'test') {
const groups = await this.fetchGroupsFromAPI();
const g = groups.find((gg) => gg?.id === groupId);
const subject = g?.subject ? String(g.subject).trim() : '';
if (subject) {
try { this.ensureGroupExists(groupId, subject); } catch {}
try { (AllowedGroups as any).dbInstance = this.dbInstance; AllowedGroups.upsertPending(groupId, subject, null); } catch {}
this.cacheActiveGroups();
return subject;
}
}
return null;
} catch {
return null;
}
}
/**
* Sincroniza miembros para un grupo concreto (útil tras detectar un grupo nuevo).
*/

Loading…
Cancel
Save