234 lines
6.9 KiB
JavaScript
234 lines
6.9 KiB
JavaScript
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
|
|
};
|
|
});
|
|
}
|