96 lines
3.1 KiB
TypeScript
96 lines
3.1 KiB
TypeScript
import { requireSalesOrAdmin } from '~/server/utils/auth';
|
|
import { getNocoDbConfiguration } from '~/server/utils/nocodb';
|
|
import { logAuditEvent } from '~/server/utils/audit-logger';
|
|
import { findDuplicates, createInterestConfig } from '~/server/utils/duplicate-detection';
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
console.log('[INTERESTS] Find duplicates request');
|
|
|
|
try {
|
|
// Require sales or admin access for duplicate detection
|
|
await requireSalesOrAdmin(event);
|
|
|
|
const query = getQuery(event);
|
|
const threshold = query.threshold ? parseFloat(query.threshold as string) : 0.8;
|
|
const dateRange = query.dateRange ? parseInt(query.dateRange as string) : 365; // Default 1 year
|
|
|
|
// Get all interests from NocoDB
|
|
const config = getNocoDbConfiguration();
|
|
const interestTableId = "mbs9hjauug4eseo"; // Interest table ID
|
|
|
|
let url = `${config.url}/api/v2/tables/${interestTableId}/records`;
|
|
|
|
// Add date filtering if specified (include records without Created At)
|
|
if (dateRange && dateRange > 0) {
|
|
const cutoffDate = new Date();
|
|
cutoffDate.setDate(cutoffDate.getDate() - dateRange);
|
|
// Include records without Created At OR within date range
|
|
const dateFilter = `((Created At,gte,${cutoffDate.toISOString()}),or,(Created At,is,null))`;
|
|
url += `?where=${encodeURIComponent(dateFilter)}`;
|
|
}
|
|
|
|
const response = await $fetch(url, {
|
|
headers: {
|
|
'xc-token': config.token
|
|
},
|
|
params: {
|
|
limit: 5000 // Get a large batch for duplicate detection
|
|
}
|
|
}) as any;
|
|
|
|
const interests = response.list || [];
|
|
console.log('[INTERESTS] Analyzing', interests.length, 'interests for duplicates');
|
|
|
|
// Find duplicate groups using the new centralized utility
|
|
const duplicateConfig = createInterestConfig();
|
|
const duplicateGroups = findDuplicates(interests, duplicateConfig);
|
|
|
|
// Convert to the expected format
|
|
const formattedGroups = duplicateGroups.map(group => ({
|
|
id: group.id,
|
|
interests: group.items,
|
|
matchReason: group.matchReason,
|
|
confidence: group.confidence,
|
|
masterCandidate: group.masterCandidate
|
|
}));
|
|
|
|
console.log('[INTERESTS] Found', formattedGroups.length, 'duplicate groups');
|
|
|
|
// Log the audit event
|
|
await logAuditEvent(event, 'FIND_INTEREST_DUPLICATES', 'interest', {
|
|
changes: {
|
|
totalInterests: interests.length,
|
|
duplicateGroups: formattedGroups.length,
|
|
threshold,
|
|
dateRange
|
|
}
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
duplicateGroups: formattedGroups,
|
|
totalInterests: interests.length,
|
|
duplicateCount: formattedGroups.reduce((sum, group) => sum + group.interests.length, 0),
|
|
threshold,
|
|
dateRange
|
|
}
|
|
};
|
|
|
|
} catch (error: any) {
|
|
console.error('[INTERESTS] Failed to find duplicates:', error);
|
|
|
|
if (error.statusCode === 403) {
|
|
return {
|
|
success: false,
|
|
error: 'Insufficient permissions. Sales or admin access required.'
|
|
};
|
|
}
|
|
|
|
return {
|
|
success: false,
|
|
error: 'Failed to find duplicates'
|
|
};
|
|
}
|
|
});
|