You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
3.4 KiB
TypeScript

import { db } from '../db';
// Environment variables will be mocked in tests
const env = process.env;
type EvolutionGroup = {
id: string;
subject: string;
linkedParent?: string;
// Other fields from API response
};
export class GroupSyncService {
private static readonly SYNC_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
private static lastSyncAttempt = 0;
static async syncGroups(): Promise<{ added: number; updated: number }> {
if (!this.shouldSync()) {
return { added: 0, updated: 0 };
}
try {
const communityId = env.WHATSAPP_COMMUNITY_ID;
if (!communityId) {
throw new Error('WHATSAPP_COMMUNITY_ID is not set');
}
const groups = await this.fetchGroupsFromAPI();
const communityGroups = groups.filter(
(group) => group.linkedParent === communityId
);
return await this.upsertGroups(communityGroups);
} catch (error) {
console.error('Group sync failed:', error);
throw error;
} finally {
this.lastSyncAttempt = Date.now();
}
}
private static shouldSync(): boolean {
const timeSinceLastSync = Date.now() - this.lastSyncAttempt;
return timeSinceLastSync > this.SYNC_INTERVAL_MS;
}
private static async fetchGroupsFromAPI(): Promise<EvolutionGroup[]> {
const url = `${env.EVOLUTION_API_URL}/group/fetchAllGroups/${env.EVOLUTION_API_INSTANCE}?getParticipants=false`;
const response = await fetch(url, {
headers: {
apikey: env.EVOLUTION_API_KEY,
},
});
if (!response.ok) {
throw new Error(`API request failed: ${response.statusText}`);
}
const data = await response.json();
if (data.status !== 'success') {
throw new Error(`API error: ${data.message || 'Unknown error'}`);
}
return data.response;
}
private static async upsertGroups(groups: EvolutionGroup[]): Promise<{ added: number; updated: number }> {
let added = 0;
let updated = 0;
const transactionResult = db.transaction(() => {
// First mark all groups as inactive and update verification timestamp
const inactiveResult = db.prepare(`
UPDATE groups
SET active = FALSE,
last_verified = CURRENT_TIMESTAMP
`).run();
console.log('Marked groups inactive:', inactiveResult);
for (const group of groups) {
const existing = db.prepare('SELECT 1 FROM groups WHERE id = ?').get(group.id);
console.log('Checking group:', group.id, 'exists:', !!existing);
if (existing) {
const updateResult = db.prepare(
'UPDATE groups SET name = ?, active = TRUE, last_verified = CURRENT_TIMESTAMP WHERE id = ?'
).run(group.subject, group.id);
console.log('Updated group:', group.id, 'result:', updateResult);
updated++;
} else {
const insertResult = db.prepare(
'INSERT INTO groups (id, community_id, name, active) VALUES (?, ?, ?, TRUE)'
).run(group.id, env.WHATSAPP_COMMUNITY_ID, group.subject);
console.log('Added group:', group.id, 'result:', insertResult);
added++;
}
}
return { added, updated };
});
try {
const result = transactionResult();
console.log(`Group sync completed: ${result.added} added, ${result.updated} updated`);
return result;
} catch (error) {
console.error('Error in upsertGroups:', error);
throw error;
}
}
}