add features
This commit is contained in:
@@ -89,6 +89,28 @@ function getUserId(req: Request): string {
|
||||
return req.user!.id;
|
||||
}
|
||||
|
||||
function getUserGroups(req: Request): string[] {
|
||||
return req.user?.groups ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the user is authorised to write to equipment in the given
|
||||
* category. Admin can write to any category. Fahrmeister can only write to
|
||||
* motorised categories. Zeugmeister can only write to non-motorised categories.
|
||||
*/
|
||||
async function checkCategoryPermission(kategorieId: string, groups: string[]): Promise<boolean> {
|
||||
if (groups.includes('dashboard_admin')) return true;
|
||||
|
||||
const result = await equipmentService.getCategoryById(kategorieId);
|
||||
if (!result) return false; // unknown category → deny
|
||||
|
||||
if (result.motorisiert) {
|
||||
return groups.includes('dashboard_fahrmeister');
|
||||
} else {
|
||||
return groups.includes('dashboard_zeugmeister');
|
||||
}
|
||||
}
|
||||
|
||||
// ── Controller ────────────────────────────────────────────────────────────────
|
||||
|
||||
class EquipmentController {
|
||||
@@ -193,6 +215,12 @@ class EquipmentController {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const groups = getUserGroups(req);
|
||||
const allowed = await checkCategoryPermission(parsed.data.kategorie_id, groups);
|
||||
if (!allowed) {
|
||||
res.status(403).json({ success: false, message: 'Keine Berechtigung für diese Kategorie' });
|
||||
return;
|
||||
}
|
||||
const equipment = await equipmentService.createEquipment(parsed.data, getUserId(req));
|
||||
res.status(201).json({ success: true, data: equipment });
|
||||
} catch (error) {
|
||||
@@ -221,6 +249,25 @@ class EquipmentController {
|
||||
res.status(400).json({ success: false, message: 'Kein Feld zum Aktualisieren angegeben' });
|
||||
return;
|
||||
}
|
||||
// Determine which category to check permissions against
|
||||
const groups = getUserGroups(req);
|
||||
if (!groups.includes('dashboard_admin')) {
|
||||
// If kategorie_id is being changed, check against the new category; otherwise fetch existing
|
||||
let kategorieId = parsed.data.kategorie_id;
|
||||
if (!kategorieId) {
|
||||
const existing = await equipmentService.getEquipmentById(id);
|
||||
if (!existing) {
|
||||
res.status(404).json({ success: false, message: 'Ausrüstung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
kategorieId = existing.kategorie_id;
|
||||
}
|
||||
const allowed = await checkCategoryPermission(kategorieId, groups);
|
||||
if (!allowed) {
|
||||
res.status(403).json({ success: false, message: 'Keine Berechtigung für diese Kategorie' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
const equipment = await equipmentService.updateEquipment(id, parsed.data, getUserId(req));
|
||||
if (!equipment) {
|
||||
res.status(404).json({ success: false, message: 'Ausrüstung nicht gefunden' });
|
||||
@@ -253,6 +300,19 @@ class EquipmentController {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const groups = getUserGroups(req);
|
||||
if (!groups.includes('dashboard_admin')) {
|
||||
const existing = await equipmentService.getEquipmentById(id);
|
||||
if (!existing) {
|
||||
res.status(404).json({ success: false, message: 'Ausrüstung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
const allowed = await checkCategoryPermission(existing.kategorie_id, groups);
|
||||
if (!allowed) {
|
||||
res.status(403).json({ success: false, message: 'Keine Berechtigung für diese Kategorie' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
await equipmentService.updateStatus(
|
||||
id, parsed.data.status, parsed.data.bemerkung, getUserId(req)
|
||||
);
|
||||
@@ -302,6 +362,19 @@ class EquipmentController {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const groups = getUserGroups(req);
|
||||
if (!groups.includes('dashboard_admin')) {
|
||||
const existing = await equipmentService.getEquipmentById(id);
|
||||
if (!existing) {
|
||||
res.status(404).json({ success: false, message: 'Ausrüstung nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
const allowed = await checkCategoryPermission(existing.kategorie_id, groups);
|
||||
if (!allowed) {
|
||||
res.status(403).json({ success: false, message: 'Keine Berechtigung für diese Kategorie' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
const entry = await equipmentService.addWartungslog(id, parsed.data, getUserId(req));
|
||||
res.status(201).json({ success: true, data: entry });
|
||||
} catch (error: any) {
|
||||
|
||||
72
backend/src/controllers/notification.controller.ts
Normal file
72
backend/src/controllers/notification.controller.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
// =============================================================================
|
||||
// Notification Controller
|
||||
// =============================================================================
|
||||
|
||||
import { Request, Response } from 'express';
|
||||
import notificationService from '../services/notification.service';
|
||||
import logger from '../utils/logger';
|
||||
|
||||
function isValidUUID(s: string): boolean {
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s);
|
||||
}
|
||||
|
||||
class NotificationController {
|
||||
/** GET /api/notifications — returns all notifications for the authenticated user. */
|
||||
async getNotifications(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const userId = req.user!.id;
|
||||
const notifications = await notificationService.getByUser(userId);
|
||||
res.status(200).json({ success: true, data: notifications });
|
||||
} catch (error) {
|
||||
logger.error('NotificationController.getNotifications error', { error });
|
||||
res.status(500).json({ success: false, message: 'Notifications konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
/** GET /api/notifications/count — returns unread count for the authenticated user. */
|
||||
async getUnreadCount(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const userId = req.user!.id;
|
||||
const count = await notificationService.getUnreadCount(userId);
|
||||
res.status(200).json({ success: true, data: { count } });
|
||||
} catch (error) {
|
||||
logger.error('NotificationController.getUnreadCount error', { error });
|
||||
res.status(500).json({ success: false, message: 'Anzahl konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
/** PATCH /api/notifications/:id/read — marks a single notification as read. */
|
||||
async markAsRead(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const { id } = req.params as Record<string, string>;
|
||||
if (!isValidUUID(id)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige Notification-ID' });
|
||||
return;
|
||||
}
|
||||
const userId = req.user!.id;
|
||||
const updated = await notificationService.markAsRead(id, userId);
|
||||
if (!updated) {
|
||||
res.status(404).json({ success: false, message: 'Notification nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, message: 'Als gelesen markiert' });
|
||||
} catch (error) {
|
||||
logger.error('NotificationController.markAsRead error', { error });
|
||||
res.status(500).json({ success: false, message: 'Notification konnte nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
|
||||
/** POST /api/notifications/mark-all-read — marks all notifications as read. */
|
||||
async markAllRead(req: Request, res: Response): Promise<void> {
|
||||
try {
|
||||
const userId = req.user!.id;
|
||||
await notificationService.markAllRead(userId);
|
||||
res.status(200).json({ success: true, message: 'Alle als gelesen markiert' });
|
||||
} catch (error) {
|
||||
logger.error('NotificationController.markAllRead error', { error });
|
||||
res.status(500).json({ success: false, message: 'Notifications konnten nicht aktualisiert werden' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new NotificationController();
|
||||
Reference in New Issue
Block a user