Files
web-cad/backend/src/routes/notifications.ts
T

77 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Notifications Routes List, create, mark read, delete notifications
*/
import type { FastifyInstance } from 'fastify';
import type { DatabaseInterface } from '../database/DatabaseInterface.js';
import type { AuthService } from '../auth/AuthService.js';
import { validateIdParam } from '../utils/validation.js';
function extractToken(request: any): string | null {
const auth = request.headers?.authorization;
if (auth && auth.startsWith('Bearer ')) return auth.slice(7);
return null;
}
export function registerNotificationRoutes(fastify: FastifyInstance, db: DatabaseInterface, authService: AuthService) {
// List notifications for current user
fastify.get('/api/notifications', async (request, reply) => {
const token = extractToken(request);
if (!token) return reply.code(401).send({ error: 'Authentication required' });
const user = authService.getUserFromSession(token);
if (!user) return reply.code(401).send({ error: 'Invalid or expired session' });
return db.listNotifications(user.id);
});
// Create notification (only for self)
fastify.post('/api/notifications', async (request, reply) => {
const token = extractToken(request);
if (!token) return reply.code(401).send({ error: 'Authentication required' });
const user = authService.getUserFromSession(token);
if (!user) return reply.code(401).send({ error: 'Invalid or expired session' });
const body = request.body as { type?: string; title?: string; message?: string };
if (!body.title || !body.message) return reply.code(400).send({ error: 'title and message are required' });
const validTypes = ['info', 'share', 'warning', 'error'];
const type = validTypes.includes(body.type ?? '') ? body.type! : 'info';
return reply.code(201).send(db.createNotification({
user_id: user.id,
type,
title: body.title,
message: body.message,
}));
});
// Mark notification as read (ownership check)
fastify.patch('/api/notifications/:id/read', async (request, reply) => {
const token = extractToken(request);
if (!token) return reply.code(401).send({ error: 'Authentication required' });
const user = authService.getUserFromSession(token);
if (!user) return reply.code(401).send({ error: 'Invalid or expired session' });
const { id } = request.params as { id: string };
const idErr = validateIdParam(id, 'id');
if (idErr) return reply.code(400).send({ error: idErr });
const notif = db.getNotification(id);
if (!notif) return reply.code(404).send({ error: 'Notification not found' });
if (notif.user_id !== user.id) return reply.code(403).send({ error: 'Forbidden' });
const ok = db.markNotificationRead(id);
if (!ok) return reply.code(404).send({ error: 'Notification not found' });
return reply.code(204).send();
});
// Delete notification (ownership check)
fastify.delete('/api/notifications/:id', async (request, reply) => {
const token = extractToken(request);
if (!token) return reply.code(401).send({ error: 'Authentication required' });
const user = authService.getUserFromSession(token);
if (!user) return reply.code(401).send({ error: 'Invalid or expired session' });
const { id } = request.params as { id: string };
const idErr = validateIdParam(id, 'id');
if (idErr) return reply.code(400).send({ error: idErr });
const notif = db.getNotification(id);
if (!notif) return reply.code(404).send({ error: 'Notification not found' });
if (notif.user_id !== user.id) return reply.code(403).send({ error: 'Forbidden' });
const ok = db.deleteNotification(id);
if (!ok) return reply.code(404).send({ error: 'Notification not found' });
return reply.code(204).send();
});
}