235 lines
7.3 KiB
JavaScript
235 lines
7.3 KiB
JavaScript
import prisma from "~/server/utils/prisma";
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
try {
|
|
// Read request body
|
|
const body = await readBody(event);
|
|
|
|
// Get current user
|
|
const user = event.context.user;
|
|
if (!user || !user.userID) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Authentication required'
|
|
});
|
|
}
|
|
|
|
// Prepare data for saving
|
|
const draftData = {
|
|
title: body.title || 'Untitled Draft',
|
|
type: body.type || 'single',
|
|
priority: body.priority || 'medium',
|
|
category: body.category,
|
|
channels: Array.isArray(body.channels) ? body.channels : [],
|
|
emailSubject: body.emailSubject || null,
|
|
deliveryType: body.deliveryType || 'immediate',
|
|
scheduledAt: body.scheduledAt || null,
|
|
timezone: body.timezone || 'UTC',
|
|
audienceType: body.audienceType || 'all',
|
|
specificUsers: body.specificUsers || null,
|
|
userSegments: Array.isArray(body.userSegments) ? body.userSegments : [],
|
|
excludeUnsubscribed: body.excludeUnsubscribed !== false, // default true
|
|
contentType: body.contentType || 'new',
|
|
selectedTemplate: body.selectedTemplate || null,
|
|
emailContent: body.emailContent || null,
|
|
callToActionText: body.callToActionText || null,
|
|
callToActionUrl: body.callToActionUrl || null,
|
|
pushTitle: body.pushTitle || null,
|
|
pushBody: body.pushBody || null,
|
|
draftId: body.draftId // For updating existing drafts
|
|
};
|
|
|
|
// Use Prisma transaction
|
|
const result = await prisma.$transaction(async (tx) => {
|
|
let notificationId = draftData.draftId;
|
|
|
|
// Get category if provided
|
|
let categoryId = null;
|
|
if (draftData.category) {
|
|
const category = await tx.notification_categories.findFirst({
|
|
where: { value: draftData.category }
|
|
});
|
|
|
|
if (category) {
|
|
categoryId = category.id;
|
|
}
|
|
}
|
|
|
|
// Get template if provided
|
|
let templateId = null;
|
|
if (draftData.contentType === 'template' && draftData.selectedTemplate) {
|
|
const template = await tx.notification_templates.findFirst({
|
|
where: {
|
|
value: draftData.selectedTemplate,
|
|
is_active: true
|
|
}
|
|
});
|
|
|
|
if (template) {
|
|
templateId = template.id;
|
|
}
|
|
}
|
|
|
|
if (notificationId) {
|
|
// Check if the draft exists and belongs to the user
|
|
const existingDraft = await tx.notifications.findFirst({
|
|
where: {
|
|
id: notificationId,
|
|
created_by: user.userID.toString(),
|
|
status: 'draft'
|
|
}
|
|
});
|
|
|
|
if (!existingDraft) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: 'Draft not found or you do not have permission to update it'
|
|
});
|
|
}
|
|
|
|
// Update existing draft
|
|
const updatedDraft = await tx.notifications.update({
|
|
where: { id: notificationId },
|
|
data: {
|
|
title: draftData.title,
|
|
type: draftData.type,
|
|
priority: draftData.priority,
|
|
category_id: categoryId,
|
|
delivery_type: draftData.deliveryType,
|
|
scheduled_at: draftData.scheduledAt ? new Date(draftData.scheduledAt) : null,
|
|
timezone: draftData.timezone,
|
|
audience_type: draftData.audienceType,
|
|
specific_users: draftData.specificUsers,
|
|
exclude_unsubscribed: draftData.excludeUnsubscribed,
|
|
content_type: draftData.contentType,
|
|
template_id: templateId,
|
|
email_subject: draftData.emailSubject,
|
|
email_content: draftData.emailContent,
|
|
call_to_action_text: draftData.callToActionText,
|
|
call_to_action_url: draftData.callToActionUrl,
|
|
push_title: draftData.pushTitle,
|
|
push_body: draftData.pushBody,
|
|
updated_at: new Date()
|
|
}
|
|
});
|
|
|
|
notificationId = updatedDraft.id;
|
|
} else {
|
|
// Create new draft
|
|
const newDraft = await tx.notifications.create({
|
|
data: {
|
|
title: draftData.title,
|
|
type: draftData.type,
|
|
priority: draftData.priority,
|
|
category_id: categoryId,
|
|
delivery_type: draftData.deliveryType,
|
|
scheduled_at: draftData.scheduledAt ? new Date(draftData.scheduledAt) : null,
|
|
timezone: draftData.timezone,
|
|
audience_type: draftData.audienceType,
|
|
specific_users: draftData.specificUsers,
|
|
exclude_unsubscribed: draftData.excludeUnsubscribed,
|
|
respect_do_not_disturb: true,
|
|
enable_tracking: true,
|
|
content_type: draftData.contentType,
|
|
template_id: templateId,
|
|
email_subject: draftData.emailSubject,
|
|
email_content: draftData.emailContent,
|
|
call_to_action_text: draftData.callToActionText,
|
|
call_to_action_url: draftData.callToActionUrl,
|
|
push_title: draftData.pushTitle,
|
|
push_body: draftData.pushBody,
|
|
created_by: user.userID.toString(),
|
|
status: 'draft'
|
|
}
|
|
});
|
|
|
|
notificationId = newDraft.id;
|
|
}
|
|
|
|
// Update channels
|
|
if (draftData.channels && draftData.channels.length > 0) {
|
|
// Delete existing channels
|
|
await tx.notification_channels.deleteMany({
|
|
where: { notification_id: notificationId }
|
|
});
|
|
|
|
// Insert new channels
|
|
await tx.notification_channels.createMany({
|
|
data: draftData.channels.map(channel => ({
|
|
notification_id: notificationId,
|
|
channel_type: channel
|
|
}))
|
|
});
|
|
}
|
|
|
|
// Update segments
|
|
if (draftData.userSegments && draftData.userSegments.length > 0) {
|
|
// Delete existing segments
|
|
await tx.notification_user_segments.deleteMany({
|
|
where: { notification_id: notificationId }
|
|
});
|
|
|
|
// Insert new segments
|
|
for (const segment of draftData.userSegments) {
|
|
const segmentData = await tx.user_segments.findFirst({
|
|
where: {
|
|
value: segment,
|
|
is_active: true
|
|
}
|
|
});
|
|
|
|
if (segmentData) {
|
|
await tx.notification_user_segments.create({
|
|
data: {
|
|
notification_id: notificationId,
|
|
segment_id: segmentData.id
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
id: notificationId
|
|
};
|
|
});
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
id: result.id,
|
|
message: 'Draft saved successfully'
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
console.error('Error saving draft:', error);
|
|
|
|
// Handle Prisma errors
|
|
if (error.code && error.code.startsWith('P')) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Database operation failed',
|
|
data: {
|
|
error: error.message,
|
|
code: error.code
|
|
}
|
|
});
|
|
}
|
|
|
|
// Handle known errors with status codes
|
|
if (error.statusCode) {
|
|
throw error;
|
|
}
|
|
|
|
// Generic server error
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: 'Failed to save draft',
|
|
data: {
|
|
error: error.message
|
|
}
|
|
});
|
|
} finally {
|
|
}
|
|
});
|