Files
Nas-Notification/server/api/public/get-notification-list.get.js

132 lines
3.7 KiB
JavaScript

import { z } from "zod";
import prisma from "~/server/utils/prisma";
const ENV = useRuntimeConfig();
function requireApiKey(event) {
const headers = getRequestHeaders(event);
const provided = headers["x-api-key"] || headers["X-API-Key"];
const expected = ENV.notificationApiKey;
if (!expected) {
throw createError({
statusCode: 500,
statusMessage:
"Notification API is not configured (missing NUXT_NOTIFICATION_API_KEY environment variable)",
});
}
if (!provided || provided !== expected) {
throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
}
}
const listSchema = z.object({
page: z
.string()
.optional()
.transform((v) => (v ? parseInt(v) : 1))
.default("1"),
limit: z
.string()
.optional()
.transform((v) => (v ? parseInt(v) : 20))
.default("20"),
status: z.string().optional(),
priority: z.string().optional(),
category: z.string().optional(),
search: z.string().optional(),
sortBy: z.string().default("created_at"),
sortOrder: z.enum(["asc", "desc"]).default("desc"),
});
export default defineEventHandler(async (event) => {
try {
requireApiKey(event);
const params = listSchema.parse(getQuery(event) || {});
const where = {};
if (params.status) where.status = params.status;
if (params.priority) where.priority = params.priority;
if (params.category)
where.notification_categories = { value: params.category };
if (params.search) {
where.OR = [
{ title: { contains: params.search } },
{ email_subject: { contains: params.search } },
{ push_title: { contains: params.search } },
];
}
const total = await prisma.notifications.count({ where });
const notifications = await prisma.notifications.findMany({
where,
select: {
id: true,
title: true,
priority: true,
status: true,
delivery_type: true,
scheduled_at: true,
created_at: true,
notification_categories: { select: { name: true } },
notification_channels: { select: { channel_type: true } },
notification_recipients: { select: { status: true } },
},
orderBy: { [params.sortBy]: params.sortOrder },
skip: (params.page - 1) * params.limit,
take: params.limit,
});
const items = notifications.map((n) => {
const totalRecipients = n.notification_recipients.length;
const delivered = n.notification_recipients.filter(
(r) => r.status === "delivered"
).length;
const successRate =
totalRecipients > 0
? Math.round((delivered / totalRecipients) * 100)
: 0;
return {
id: n.id,
title: n.title,
category: n.notification_categories?.name || "Uncategorized",
channels: n.notification_channels.map((c) => c.channel_type),
priority: n.priority,
status: n.status,
recipients: totalRecipients,
successRate,
createdAt: n.created_at,
};
});
const totalPages = Math.ceil(total / params.limit);
return {
success: true,
data: {
notifications: items,
pagination: {
page: params.page,
totalPages,
totalItems: total,
hasMore: params.page < totalPages,
},
},
};
} catch (error) {
if (error instanceof z.ZodError) {
throw createError({
statusCode: 400,
statusMessage: "Invalid query parameters",
data: error.errors,
});
}
if (error.statusCode) throw error;
throw createError({
statusCode: 500,
statusMessage: "Failed to fetch notifications",
data: { error: error.message },
});
}
});