|
|
|
@ -691,4 +691,59 @@ export class GroupSyncService {
|
|
|
|
const gids = this.getActiveGroupIdsForUser(userId);
|
|
|
|
const gids = this.getActiveGroupIdsForUser(userId);
|
|
|
|
return gids.filter(gid => this.isSnapshotFresh(gid));
|
|
|
|
return gids.filter(gid => this.isSnapshotFresh(gid));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Asegura un registro de grupo activo en la base de datos (upsert idempotente).
|
|
|
|
|
|
|
|
* Si no existe, lo crea con active=1. Si existe y estaba inactivo, lo reactiva.
|
|
|
|
|
|
|
|
* Puede actualizar el nombre si se proporciona.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static ensureGroupExists(groupId: string, name?: string | null): { created: boolean; reactivated: boolean; updatedName: boolean } {
|
|
|
|
|
|
|
|
if (!groupId) return { created: false, reactivated: false, updatedName: false };
|
|
|
|
|
|
|
|
let created = false, reactivated = false, updatedName = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.dbInstance.transaction(() => {
|
|
|
|
|
|
|
|
const row = this.dbInstance.prepare(`SELECT id, active, name FROM groups WHERE id = ?`).get(groupId) as any;
|
|
|
|
|
|
|
|
if (!row) {
|
|
|
|
|
|
|
|
const community = process.env.WHATSAPP_COMMUNITY_ID || '';
|
|
|
|
|
|
|
|
this.dbInstance.prepare(`
|
|
|
|
|
|
|
|
INSERT INTO groups (id, community_id, name, active, last_verified)
|
|
|
|
|
|
|
|
VALUES (?, ?, ?, 1, CURRENT_TIMESTAMP)
|
|
|
|
|
|
|
|
`).run(groupId, community, name || null);
|
|
|
|
|
|
|
|
created = true;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// Reactivar si estaba inactivo y opcionalmente actualizar nombre
|
|
|
|
|
|
|
|
const shouldUpdateName = (typeof name === 'string' && name.trim().length > 0 && name !== row.name);
|
|
|
|
|
|
|
|
if (row.active !== 1 || shouldUpdateName) {
|
|
|
|
|
|
|
|
this.dbInstance.prepare(`
|
|
|
|
|
|
|
|
UPDATE groups
|
|
|
|
|
|
|
|
SET active = 1,
|
|
|
|
|
|
|
|
name = COALESCE(?, name),
|
|
|
|
|
|
|
|
last_verified = CURRENT_TIMESTAMP
|
|
|
|
|
|
|
|
WHERE id = ?
|
|
|
|
|
|
|
|
`).run(shouldUpdateName ? name : null, groupId);
|
|
|
|
|
|
|
|
reactivated = row.active !== 1;
|
|
|
|
|
|
|
|
updatedName = shouldUpdateName;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Actualizar caché
|
|
|
|
|
|
|
|
this.cacheActiveGroups();
|
|
|
|
|
|
|
|
Metrics.set('active_groups', this.activeGroupsCache.size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { created, reactivated, updatedName };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Sincroniza miembros para un grupo concreto (útil tras detectar un grupo nuevo).
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static async syncMembersForGroup(groupId: string): Promise<{ added: number; updated: number; deactivated: number }> {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const snapshot = await (this as any).fetchGroupMembersFromAPI(groupId);
|
|
|
|
|
|
|
|
return this.reconcileGroupMembers(groupId, snapshot);
|
|
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
|
|
console.error(`❌ Failed to sync members for group ${groupId}:`, e instanceof Error ? e.message : String(e));
|
|
|
|
|
|
|
|
return { added: 0, updated: 0, deactivated: 0 };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|