diff --git a/backend/src/controllers/booking.controller.ts b/backend/src/controllers/booking.controller.ts index 3eb9ceb..d77ddf5 100644 --- a/backend/src/controllers/booking.controller.ts +++ b/backend/src/controllers/booking.controller.ts @@ -226,8 +226,8 @@ class BookingController { const isOwner = booking.gebucht_von === req.user!.id; const groups: string[] = req.user?.groups ?? []; const isAdmin = groups.includes('dashboard_admin'); - const canCancelOwn = isAdmin || permissionService.hasPermission(groups, 'kalender:cancel_own_bookings'); - const canCancelAny = isAdmin || permissionService.hasPermission(groups, 'kalender:delete_bookings'); + const canCancelOwn = isAdmin || permissionService.hasPermission(groups, 'kalender:manage_bookings'); + const canCancelAny = isAdmin || permissionService.hasPermission(groups, 'kalender:manage_bookings'); if (!(isOwner && canCancelOwn) && !canCancelAny) { res.status(403).json({ success: false, message: 'Keine Berechtigung' }); diff --git a/backend/src/routes/atemschutz.routes.ts b/backend/src/routes/atemschutz.routes.ts index b8a08bf..1b84f42 100644 --- a/backend/src/routes/atemschutz.routes.ts +++ b/backend/src/routes/atemschutz.routes.ts @@ -5,14 +5,14 @@ import { requirePermission } from '../middleware/rbac.middleware'; const router = Router(); -// ── Read-only (any authenticated user) ─────────────────────────────────────── +// ── Read-only ──────────────────────────────────────────────────────────────── -router.get('/', authenticate, atemschutzController.list.bind(atemschutzController)); -router.get('/stats', authenticate, atemschutzController.getStats.bind(atemschutzController)); -router.get('/expiring', authenticate, atemschutzController.getExpiring.bind(atemschutzController)); +router.get('/', authenticate, requirePermission('atemschutz:view'), atemschutzController.list.bind(atemschutzController)); +router.get('/stats', authenticate, requirePermission('atemschutz:view'), atemschutzController.getStats.bind(atemschutzController)); +router.get('/expiring', authenticate, requirePermission('atemschutz:view'), atemschutzController.getExpiring.bind(atemschutzController)); router.get('/my-status', authenticate, atemschutzController.getMyStatus.bind(atemschutzController)); -router.get('/user/:userId', authenticate, atemschutzController.getByUserId.bind(atemschutzController)); -router.get('/:id', authenticate, atemschutzController.getOne.bind(atemschutzController)); +router.get('/user/:userId', authenticate, requirePermission('atemschutz:view'), atemschutzController.getByUserId.bind(atemschutzController)); +router.get('/:id', authenticate, requirePermission('atemschutz:view'), atemschutzController.getOne.bind(atemschutzController)); // ── Write — gruppenfuehrer+ ───────────────────────────────────────────────── diff --git a/backend/src/routes/bestellung.routes.ts b/backend/src/routes/bestellung.routes.ts index 5a43a14..8b86754 100644 --- a/backend/src/routes/bestellung.routes.ts +++ b/backend/src/routes/bestellung.routes.ts @@ -88,7 +88,7 @@ router.delete( router.patch( '/:id/status', authenticate, - requirePermission('bestellungen:create'), + requirePermission('bestellungen:manage_orders'), bestellungController.updateStatus.bind(bestellungController) ); diff --git a/backend/src/routes/incident.routes.ts b/backend/src/routes/incident.routes.ts index 1cc7fb8..5f33aa4 100644 --- a/backend/src/routes/incident.routes.ts +++ b/backend/src/routes/incident.routes.ts @@ -42,7 +42,7 @@ router.get( */ router.post( '/refresh-stats', - requirePermission('einsaetze:delete'), + requirePermission('einsaetze:create'), incidentController.refreshStats.bind(incidentController) ); diff --git a/backend/src/routes/training.routes.ts b/backend/src/routes/training.routes.ts index 88af479..8b286ea 100644 --- a/backend/src/routes/training.routes.ts +++ b/backend/src/routes/training.routes.ts @@ -9,7 +9,7 @@ const router = Router(); // --------------------------------------------------------------------------- // injectTeilnahmenFlag // -// Sets req.canSeeTeilnahmen = true for users with kalender:mark_attendance. +// Sets req.canSeeTeilnahmen = true for users with kalender:create. // Regular Mitglieder see only attendance counts; officers see the full list. // --------------------------------------------------------------------------- @@ -23,7 +23,7 @@ async function injectTeilnahmenFlag( const groups: string[] = req.user?.groups ?? []; (req as any).canSeeTeilnahmen = groups.includes('dashboard_admin') || - permissionService.hasPermission(groups, 'kalender:mark_attendance'); + permissionService.hasPermission(groups, 'kalender:create'); } } catch (_err) { // Non-fatal — default to restricted view @@ -67,12 +67,12 @@ router.get('/calendar-token', authenticate, trainingController.getCalendarToken) /** * GET /api/training/stats?year= * Annual participation stats. - * Requires Kommandant or above (requirePermission('kalender:view_reports')). + * Requires Kommandant or above (requirePermission('kalender:create')). */ router.get( '/stats', authenticate, - requirePermission('kalender:view_reports'), + requirePermission('kalender:create'), trainingController.getStats ); @@ -120,7 +120,7 @@ router.patch( router.delete( '/:id', authenticate, - requirePermission('kalender:cancel'), + requirePermission('kalender:create'), trainingController.cancelEvent ); @@ -141,7 +141,7 @@ router.patch( router.post( '/:id/attendance/mark', authenticate, - requirePermission('kalender:mark_attendance'), + requirePermission('kalender:create'), trainingController.markAttendance ); diff --git a/backend/src/services/permission.service.ts b/backend/src/services/permission.service.ts index fa910c8..0e87f59 100644 --- a/backend/src/services/permission.service.ts +++ b/backend/src/services/permission.service.ts @@ -14,14 +14,8 @@ const DEFAULT_GROUP_HIERARCHY: Record = { const DEFAULT_PERMISSION_DEPS: Record = { 'kalender:create': ['kalender:view'], - 'kalender:cancel': ['kalender:view'], - 'kalender:mark_attendance': ['kalender:view'], - 'kalender:create_bookings': ['kalender:view'], - 'kalender:edit_bookings': ['kalender:view', 'kalender:create_bookings'], - 'kalender:cancel_own_bookings': ['kalender:view'], - 'kalender:delete_bookings': ['kalender:view', 'kalender:edit_bookings'], - 'kalender:manage_categories': ['kalender:view'], - 'kalender:view_reports': ['kalender:view'], + 'kalender:view_bookings': ['kalender:view'], + 'kalender:manage_bookings': ['kalender:view', 'kalender:view_bookings'], 'kalender:widget_events': ['kalender:view'], 'kalender:widget_bookings': ['kalender:view'], 'kalender:widget_quick_add': ['kalender:view', 'kalender:create'], diff --git a/frontend/src/pages/BestellungDetail.tsx b/frontend/src/pages/BestellungDetail.tsx index baa0948..e1f58e6 100644 --- a/frontend/src/pages/BestellungDetail.tsx +++ b/frontend/src/pages/BestellungDetail.tsx @@ -112,7 +112,7 @@ export default function BestellungDetail() { const erinnerungen = data?.erinnerungen ?? []; const historie = data?.historie ?? []; - const canEdit = hasPermission('bestellungen:edit'); + const canEdit = hasPermission('bestellungen:create'); const nextStatus = bestellung ? getNextStatus(bestellung.status) : null; // ── Mutations ── diff --git a/frontend/src/pages/FahrzeugBuchungen.tsx b/frontend/src/pages/FahrzeugBuchungen.tsx index 2ed5394..d1ef23c 100644 --- a/frontend/src/pages/FahrzeugBuchungen.tsx +++ b/frontend/src/pages/FahrzeugBuchungen.tsx @@ -96,10 +96,10 @@ function FahrzeugBuchungen() { const { user } = useAuth(); const { hasPermission } = usePermissionContext(); const notification = useNotification(); - const canCreate = hasPermission('kalender:create_bookings'); - const canWrite = hasPermission('kalender:edit_bookings'); - const canCancelOwn = hasPermission('kalender:cancel_own_bookings'); - const canChangeBuchungsArt = hasPermission('kalender:manage_categories'); + const canCreate = hasPermission('kalender:manage_bookings'); + const canWrite = hasPermission('kalender:manage_bookings'); + const canCancelOwn = hasPermission('kalender:manage_bookings'); + const canChangeBuchungsArt = hasPermission('kalender:create'); // ── Week navigation ──────────────────────────────────────────────────────── const [currentWeekStart, setCurrentWeekStart] = useState(() => diff --git a/frontend/src/pages/Kalender.tsx b/frontend/src/pages/Kalender.tsx index 3d977c3..b857185 100644 --- a/frontend/src/pages/Kalender.tsx +++ b/frontend/src/pages/Kalender.tsx @@ -1746,8 +1746,8 @@ export default function Kalender() { const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const canWriteEvents = hasPermission('kalender:create'); - const canWriteBookings = hasPermission('kalender:edit_bookings'); - const canCreateBookings = hasPermission('kalender:create_bookings'); + const canWriteBookings = hasPermission('kalender:manage_bookings'); + const canCreateBookings = hasPermission('kalender:manage_bookings'); // ── Tab ───────────────────────────────────────────────────────────────────── const [activeTab, setActiveTab] = useState(() => { diff --git a/frontend/src/pages/UebungDetail.tsx b/frontend/src/pages/UebungDetail.tsx index 2f8b148..c4c23d8 100644 --- a/frontend/src/pages/UebungDetail.tsx +++ b/frontend/src/pages/UebungDetail.tsx @@ -272,7 +272,7 @@ export default function UebungDetail() { const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const canWrite = hasPermission('kalender:create'); - const canSeeAttendees = hasPermission('kalender:mark_attendance'); + const canSeeAttendees = hasPermission('kalender:create'); const [markAttendanceOpen, setMarkAttendanceOpen] = useState(false); const [rsvpLoading, setRsvpLoading] = useState<'zugesagt' | 'abgesagt' | null>(null);