fix permissions

This commit is contained in:
Matthias Hochmeister
2026-03-25 08:42:45 +01:00
parent 43b7093996
commit eb92dfcc96
10 changed files with 26 additions and 32 deletions

View File

@@ -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' });

View File

@@ -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+ ─────────────────────────────────────────────────

View File

@@ -88,7 +88,7 @@ router.delete(
router.patch(
'/:id/status',
authenticate,
requirePermission('bestellungen:create'),
requirePermission('bestellungen:manage_orders'),
bestellungController.updateStatus.bind(bestellungController)
);

View File

@@ -42,7 +42,7 @@ router.get(
*/
router.post(
'/refresh-stats',
requirePermission('einsaetze:delete'),
requirePermission('einsaetze:create'),
incidentController.refreshStats.bind(incidentController)
);

View File

@@ -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=<YYYY>
* 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
);

View File

@@ -14,14 +14,8 @@ const DEFAULT_GROUP_HIERARCHY: Record<string, string[]> = {
const DEFAULT_PERMISSION_DEPS: Record<string, string[]> = {
'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'],

View File

@@ -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 ──

View File

@@ -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<Date>(() =>

View File

@@ -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(() => {

View File

@@ -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);