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
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;
|
|
}
|
|
}
|
|
}
|