/** * Component: Notification Backend API * Documentation: documentation/backend/services/notifications.md */ import { NextRequest, NextResponse } from 'next/server'; import { requireAuth, requireAdmin, AuthenticatedRequest } from '@/lib/middleware/auth'; import { prisma } from '@/lib/db'; import { getNotificationService, NotificationBackendType } from '@/lib/services/notification.service'; import { RMABLogger } from '@/lib/utils/logger'; import { z } from 'zod'; const logger = RMABLogger.create('API.Admin.Notifications'); const CreateBackendSchema = z.object({ type: z.enum(['discord', 'pushover', 'email', 'slack', 'telegram', 'webhook']), name: z.string().min(1), config: z.record(z.any()), events: z.array(z.enum(['request_pending_approval', 'request_approved', 'request_available', 'request_error'])).min(1), enabled: z.boolean().default(true), }); /** * GET /api/admin/notifications * List all notification backends (sensitive values masked) */ export async function GET(request: NextRequest) { return requireAuth(request, async (req: AuthenticatedRequest) => { return requireAdmin(req, async () => { try { const backends = await prisma.notificationBackend.findMany({ orderBy: { createdAt: 'desc' }, }); const notificationService = getNotificationService(); // Mask sensitive config values const maskedBackends = backends.map((backend) => ({ ...backend, config: notificationService.maskConfig(backend.type as NotificationBackendType, backend.config), })); return NextResponse.json({ success: true, backends: maskedBackends, }); } catch (error) { logger.error('Failed to fetch notification backends', { error: error instanceof Error ? error.message : String(error), }); return NextResponse.json( { error: 'FetchError', message: 'Failed to fetch notification backends', }, { status: 500 } ); } }); }); } /** * POST /api/admin/notifications * Create new notification backend */ export async function POST(request: NextRequest) { return requireAuth(request, async (req: AuthenticatedRequest) => { return requireAdmin(req, async () => { try { const body = await request.json(); const { type, name, config, events, enabled } = CreateBackendSchema.parse(body); const notificationService = getNotificationService(); // Encrypt sensitive config values const encryptedConfig = notificationService.encryptConfig(type, config); // Create backend const backend = await prisma.notificationBackend.create({ data: { type, name, config: encryptedConfig, events, enabled, }, }); logger.info(`Created notification backend: ${name} (${type})`, { backendId: backend.id, adminId: req.user?.sub, }); // Return with masked values return NextResponse.json({ success: true, backend: { ...backend, config: notificationService.maskConfig(type, backend.config), }, }, { status: 201 }); } catch (error) { logger.error('Failed to create notification backend', { error: error instanceof Error ? error.message : String(error), }); if (error instanceof z.ZodError) { return NextResponse.json( { error: 'ValidationError', details: error.errors, }, { status: 400 } ); } return NextResponse.json( { error: 'CreateError', message: 'Failed to create notification backend', }, { status: 500 } ); } }); }); }