176 lines
4.7 KiB
JavaScript

export default defineEventHandler(async (event) => {
try {
const body = await readBody(event)
// Basic validation
if (!body.name) {
throw createError({
statusCode: 400,
statusMessage: 'Name is required'
})
}
if (!['email', 'push'].includes(body.type)) {
throw createError({
statusCode: 400,
statusMessage: 'Type must be either email or push'
})
}
if (body.priority && !['low', 'medium', 'high', 'critical'].includes(body.priority)) {
throw createError({
statusCode: 400,
statusMessage: 'Priority must be low, medium, high, or critical'
})
}
// Set default priority if not provided
const validatedData = {
...body,
priority: body.priority || 'medium'
}
// Get user from session
const user = event.context.user
if (!user) {
throw createError({
statusCode: 401,
statusMessage: 'Unauthorized'
})
}
// Start transaction
const result = await prisma.$transaction(async (tx) => {
// Get template if provided
let templateData = null
if (validatedData.template) {
templateData = await tx.notification_templates.findUnique({
where: { id: validatedData.template }
})
if (!templateData) {
throw createError({
statusCode: 400,
statusMessage: 'Template not found'
})
}
}
// Get segment if provided
let segmentData = null
let estimatedReach = 0
if (validatedData.segment) {
segmentData = await tx.user_segments.findFirst({
where: {
value: validatedData.segment,
is_active: true
}
})
if (!segmentData) {
throw createError({
statusCode: 400,
statusMessage: 'Segment not found'
})
}
// TODO: Calculate estimated reach based on segment
estimatedReach = 1000 // Placeholder
}
// Create notification
const notification = await tx.notifications.create({
data: {
title: validatedData.name,
type: 'bulk',
priority: validatedData.priority,
delivery_type: validatedData.scheduledAt ? 'scheduled' : 'immediate',
scheduled_at: validatedData.scheduledAt ? new Date(validatedData.scheduledAt) : null,
status: validatedData.scheduledAt ? 'scheduled' : 'sending',
audience_type: validatedData.segment ? 'segmented' : 'all',
content_type: validatedData.template ? 'template' : 'new',
template_id: templateData?.id,
estimated_reach: estimatedReach,
created_by: user.userID.toString(),
enable_tracking: true,
exclude_unsubscribed: true,
respect_do_not_disturb: true
}
})
// Create notification channel
await tx.notification_channels.create({
data: {
notification_id: notification.id,
channel_type: validatedData.type
}
})
// Add segment if provided
if (segmentData) {
await tx.notification_user_segments.create({
data: {
notification_id: notification.id,
segment_id: segmentData.id
}
})
}
// Queue for processing if immediate
if (!validatedData.scheduledAt) {
// Process recipients immediately
await processImmediateNotification(notification.id, {
type: validatedData.type,
segment: validatedData.segment
}, tx)
}
return {
id: notification.id,
estimatedReach
}
})
return result
} catch (error) {
console.error('Error creating batch:', error)
throw error
}
})
// Helper function to process immediate notifications
async function processImmediateNotification(notificationId, data, tx) {
// Get target users based on segment
const usersQuery = {
select: {
id: true,
email: true
},
where: {}
}
if (data.segment) {
// Add segment criteria
// TODO: Implement proper segment filtering
}
const users = await tx.users.findMany(usersQuery)
// Create recipient records and queue entries
for (const user of users) {
const notificationRecipient = await tx.notification_recipients.create({
data: {
notification_id: notificationId,
user_id: user.id,
email: user.email,
channel_type: data.type
}
})
await tx.notification_queue.create({
data: {
notification_id: notificationId,
recipient_id: notificationRecipient.id,
scheduled_for: new Date(),
priority: 5 // Default priority
}
})
}
}