rights system

This commit is contained in:
Matthias Hochmeister
2026-03-23 10:50:52 +01:00
parent 2bb22850f4
commit 515f14956e
24 changed files with 629 additions and 363 deletions

View File

@@ -85,7 +85,7 @@ function parseAuditQuery(query: Record<string, unknown>): AuditFilters {
router.get(
'/audit-log',
authenticate,
requirePermission('admin:access'),
requirePermission('admin:view'),
async (req: Request, res: Response): Promise<void> => {
try {
const filters = parseAuditQuery(req.query as Record<string, unknown>);
@@ -122,7 +122,7 @@ router.get(
router.get(
'/audit-log/export',
authenticate,
requirePermission('admin:access'),
requirePermission('admin:view'),
async (req: Request, res: Response): Promise<void> => {
try {
// For CSV exports we fetch up to 10,000 rows (no pagination).
@@ -176,7 +176,7 @@ const FDISK_SYNC_URL = process.env.FDISK_SYNC_URL ?? '';
router.get(
'/fdisk-sync/logs',
authenticate,
requirePermission('admin:access'),
requirePermission('admin:view'),
async (_req: Request, res: Response): Promise<void> => {
if (!FDISK_SYNC_URL) {
res.status(503).json({ success: false, message: 'FDISK sync service not configured' });
@@ -194,7 +194,7 @@ router.get(
router.post(
'/fdisk-sync/trigger',
authenticate,
requirePermission('admin:access'),
requirePermission('admin:view'),
async (req: Request, res: Response): Promise<void> => {
if (!FDISK_SYNC_URL) {
res.status(503).json({ success: false, message: 'FDISK sync service not configured' });

View File

@@ -4,7 +4,7 @@ import { authenticate } from '../middleware/auth.middleware';
import { requirePermission } from '../middleware/rbac.middleware';
const router = Router();
const adminAuth = [authenticate, requirePermission('admin:access')] as const;
const adminAuth = [authenticate, requirePermission('admin:write')] as const;
// Public (authenticated): get active banners
router.get('/active', authenticate, bannerController.getActive.bind(bannerController));

View File

@@ -118,7 +118,7 @@ router.get(
router.post(
'/import',
authenticate,
requirePermission('kalender:create_events'),
requirePermission('kalender:create'),
eventsController.importEvents.bind(eventsController)
);
@@ -129,7 +129,7 @@ router.post(
router.post(
'/',
authenticate,
requirePermission('kalender:create_events'),
requirePermission('kalender:create'),
eventsController.createEvent.bind(eventsController)
);
@@ -146,7 +146,7 @@ router.get('/:id', authenticate, eventsController.getById.bind(eventsController)
router.patch(
'/:id',
authenticate,
requirePermission('kalender:create_events'),
requirePermission('kalender:create'),
eventsController.updateEvent.bind(eventsController)
);
@@ -157,7 +157,7 @@ router.patch(
router.delete(
'/:id',
authenticate,
requirePermission('kalender:create_events'),
requirePermission('kalender:create'),
eventsController.cancelEvent.bind(eventsController)
);
@@ -168,7 +168,7 @@ router.delete(
router.post(
'/:id/delete',
authenticate,
requirePermission('kalender:create_events'),
requirePermission('kalender:create'),
eventsController.deleteEvent.bind(eventsController)
);

View File

@@ -17,19 +17,19 @@ router.use(authenticate);
// "stats" as a userId parameter.
router.get(
'/stats',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getMemberStats.bind(memberController)
);
router.get(
'/',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getMembers.bind(memberController)
);
router.get(
'/:userId',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getMemberById.bind(memberController)
);
@@ -41,25 +41,25 @@ router.post(
router.get(
'/:userId/befoerderungen',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getBefoerderungen.bind(memberController)
);
router.get(
'/:userId/untersuchungen',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getUntersuchungen.bind(memberController)
);
router.get(
'/:userId/fahrgenehmigungen',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getFahrgenehmigungen.bind(memberController)
);
router.get(
'/:userId/ausbildungen',
requirePermission('mitglieder:view'),
requirePermission('mitglieder:view_all'),
memberController.getAusbildungen.bind(memberController)
);

View File

@@ -9,9 +9,10 @@ const router = Router();
router.get('/me', authenticate, permissionController.getMyPermissions.bind(permissionController));
// ── Admin-only routes ─────────────────────────────────────────────────────
router.get('/admin/matrix', authenticate, requirePermission('admin:access'), permissionController.getMatrix.bind(permissionController));
router.get('/admin/groups', authenticate, requirePermission('admin:access'), permissionController.getGroups.bind(permissionController));
router.put('/admin/group/:groupName', authenticate, requirePermission('admin:access'), permissionController.setGroupPermissions.bind(permissionController));
router.put('/admin/maintenance/:featureGroupId', authenticate, requirePermission('admin:access'), permissionController.setMaintenanceFlag.bind(permissionController));
router.get('/admin/matrix', authenticate, requirePermission('admin:view'), permissionController.getMatrix.bind(permissionController));
router.get('/admin/groups', authenticate, requirePermission('admin:view'), permissionController.getGroups.bind(permissionController));
router.get('/admin/unknown-groups', authenticate, requirePermission('admin:view'), permissionController.getUnknownGroups.bind(permissionController));
router.put('/admin/group/:groupName', authenticate, requirePermission('admin:write'), permissionController.setGroupPermissions.bind(permissionController));
router.put('/admin/maintenance/:featureGroupId', authenticate, requirePermission('admin:write'), permissionController.setMaintenanceFlag.bind(permissionController));
export default router;

View File

@@ -4,7 +4,7 @@ import { authenticate } from '../middleware/auth.middleware';
import { requirePermission } from '../middleware/rbac.middleware';
const router = Router();
const auth = [authenticate, requirePermission('admin:access')] as const;
const auth = [authenticate, requirePermission('admin:view')] as const;
// Static routes first (before parameterized :id routes)
router.get('/services/ping', ...auth, serviceMonitorController.pingAll.bind(serviceMonitorController));

View File

@@ -4,7 +4,7 @@ import { authenticate } from '../middleware/auth.middleware';
import { requirePermission } from '../middleware/rbac.middleware';
const router = Router();
const auth = [authenticate, requirePermission('admin:access')] as const;
const auth = [authenticate, requirePermission('admin:write')] as const;
router.get('/', ...auth, settingsController.getAll.bind(settingsController));
router.get('/preferences', authenticate, settingsController.getUserPreferences.bind(settingsController));

View File

@@ -91,12 +91,12 @@ router.get(
/**
* POST /api/training
* Create a new training event.
* Requires Gruppenführer or above (requirePermission('kalender:create_training')).
* Requires Gruppenführer or above (requirePermission('kalender:create')).
*/
router.post(
'/',
authenticate,
requirePermission('kalender:create_training'),
requirePermission('kalender:create'),
trainingController.createEvent
);
@@ -108,7 +108,7 @@ router.post(
router.patch(
'/:id',
authenticate,
requirePermission('kalender:create_training'),
requirePermission('kalender:create'),
trainingController.updateEvent
);
@@ -120,7 +120,7 @@ router.patch(
router.delete(
'/:id',
authenticate,
requirePermission('kalender:cancel_training'),
requirePermission('kalender:cancel'),
trainingController.cancelEvent
);