import prisma from '~/server/utils/prisma' export default defineEventHandler(async (event) => { try { // Check authentication const user = event.context.user; if (!user || !user.userID) { return { statusCode: 401, body: { success: false, message: 'Unauthorized' } } } const query = getQuery(event) let logs = []; let totalLogs = 0; let failedDeliveries = 0; let successfulDeliveries = 0; let total = 0; try { // Define filters const filters = {} // Date range filter if (query.startDate) { filters.created_at = { ...filters.created_at, gte: new Date(query.startDate) } } if (query.endDate) { filters.created_at = { ...filters.created_at, lte: new Date(query.endDate) } } // Action filter if (query.action) { filters.action = query.action } // Channel filter if (query.channel) { filters.channel_type = query.channel } // Status filter if (query.status) { filters.status = query.status } // Actor/user filter if (query.actor) { filters.actor = { contains: query.actor } } // Notification ID filter if (query.notificationId) { filters.notification_id = query.notificationId } // Keyword search in details or error_message if (query.keyword) { filters.OR = [ { details: { contains: query.keyword } }, { error_message: { contains: query.keyword } } ] } // Pagination const page = parseInt(query.page) || 1 const limit = parseInt(query.limit) || 10 const skip = (page - 1) * limit try { console.log("Attempting to query notification_logs table..."); // First check if the table exists let tableExists = true; try { await prisma.$queryRaw`SELECT 1 FROM notification_logs LIMIT 1`; console.log("notification_logs table exists!"); } catch (tableCheckError) { console.error("Table check error:", tableCheckError.message); console.error("Table likely doesn't exist - you need to run the migration!"); tableExists = false; throw new Error("notification_logs table does not exist"); } if (tableExists) { // Get total count for pagination total = await prisma.notification_logs.count({ where: filters }) // Get logs with pagination and sorting logs = await prisma.notification_logs.findMany({ where: filters, orderBy: { created_at: 'desc' }, skip, take: limit }) // Get summary stats totalLogs = await prisma.notification_logs.count() failedDeliveries = await prisma.notification_logs.count({ where: { status: 'Failed' } }) successfulDeliveries = await prisma.notification_logs.count({ where: { status: 'Sent' } }) console.log(`Successfully fetched ${logs.length} logs from database`); } } catch (dbError) { console.error("Database query error:", dbError.message); console.error("Stack trace:", dbError.stack); // Uncommenting the mock data code below will revert to using mock data // If you want to see real errors, keep this commented out /* // If the database table doesn't exist or there's another error, use mock data logs = generateMockLogs(limit); total = 25; // Mock total count totalLogs = 25; failedDeliveries = 3; successfulDeliveries = 20; */ throw dbError; // Re-throw to see actual error in response } } catch (prismaError) { console.error("Prisma error:", prismaError.message); console.error("Stack trace:", prismaError.stack); // Uncommenting the mock data code below will revert to using mock data // If you want to see real errors, keep this commented out /* // If there's an issue with Prisma itself, use mock data logs = generateMockLogs(10); total = 25; // Mock total count totalLogs = 25; failedDeliveries = 3; successfulDeliveries = 20; */ throw prismaError; // Re-throw to see actual error in response } // Calculate success rate const successRate = totalLogs > 0 ? Math.round((successfulDeliveries / totalLogs) * 100) : 0 const page = parseInt(query.page) || 1 const limit = parseInt(query.limit) || 10 return { statusCode: 200, body: { success: true, data: { logs, pagination: { page, limit, total, pages: Math.ceil(total / limit) }, summary: { totalLogs, failedDeliveries, successfulDeliveries, successRate } } } } } catch (error) { console.error('Error fetching notification logs:', error) return { statusCode: 500, body: { success: false, message: 'Failed to fetch notification logs', error: error.message, stack: error.stack } } } }) // Helper function to generate mock logs for testing function generateMockLogs(count = 10) { const actions = ['Notification Created', 'Notification Sent', 'Delivery Attempted', 'Notification Opened']; const statuses = ['Sent', 'Failed', 'Opened', 'Queued']; const channels = ['Email', 'SMS', 'Push Notification', 'Webhook']; const actors = ['System', 'Admin', 'API', 'Scheduler']; return Array.from({ length: count }, (_, i) => { const status = statuses[Math.floor(Math.random() * statuses.length)]; const action = actions[Math.floor(Math.random() * actions.length)]; const created_at = new Date(); created_at.setHours(created_at.getHours() - Math.floor(Math.random() * 72)); // Random time in last 72 hours return { id: `mock-${i+1}-${Date.now()}`.substring(0, 36), notification_id: `notif-${i+1}-${Date.now()}`.substring(0, 36), action, actor: actors[Math.floor(Math.random() * actors.length)], actor_id: `user-${i+1}`, channel_type: channels[Math.floor(Math.random() * channels.length)], status, details: `${action} via ${channels[Math.floor(Math.random() * channels.length)]}`, source_ip: `192.168.1.${i+1}`, error_code: status === 'Failed' ? 'ERR_DELIVERY_FAILED' : null, error_message: status === 'Failed' ? 'Failed to deliver notification' : null, created_at }; }); }