add features
This commit is contained in:
149
backend/src/routes/training.routes.ts
Normal file
149
backend/src/routes/training.routes.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { Router, Request, Response, NextFunction } from 'express';
|
||||
import trainingController from '../controllers/training.controller';
|
||||
import { authenticate, optionalAuth } from '../middleware/auth.middleware';
|
||||
import { requirePermission, getUserRole } from '../middleware/rbac.middleware';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// injectTeilnahmenFlag
|
||||
//
|
||||
// Sets req.canSeeTeilnahmen = true for Gruppenführer and above.
|
||||
// Regular Mitglieder see only attendance counts; officers see the full list.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function injectTeilnahmenFlag(
|
||||
req: Request,
|
||||
_res: Response,
|
||||
next: NextFunction
|
||||
): Promise<void> {
|
||||
try {
|
||||
if (req.user) {
|
||||
const role = await getUserRole(req.user.id);
|
||||
const ROLE_ORDER: Record<string, number> = {
|
||||
bewerber: -1, mitglied: 0, gruppenfuehrer: 1, kommandant: 2, admin: 3,
|
||||
};
|
||||
(req as any).canSeeTeilnahmen =
|
||||
(ROLE_ORDER[role] ?? 0) >= ROLE_ORDER.gruppenfuehrer;
|
||||
}
|
||||
} catch (_err) {
|
||||
// Non-fatal — default to restricted view
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Routes
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* GET /api/training
|
||||
* Public list of upcoming events (limit param).
|
||||
* Optional auth to include own RSVP status.
|
||||
*/
|
||||
router.get('/', optionalAuth, trainingController.getUpcoming);
|
||||
|
||||
/**
|
||||
* GET /api/training/calendar?from=<ISO>&to=<ISO>
|
||||
* Events in a date range for the calendar view.
|
||||
* Optional auth to include own RSVP status.
|
||||
*/
|
||||
router.get('/calendar', optionalAuth, trainingController.getCalendarRange);
|
||||
|
||||
/**
|
||||
* GET /api/training/calendar.ics?token=<calendarToken>
|
||||
* iCal export — authenticated via per-user calendar token OR Bearer JWT.
|
||||
* No `authenticate` enforced here; controller resolves auth itself.
|
||||
* See training.controller.ts for full auth tradeoff discussion.
|
||||
*/
|
||||
router.get('/calendar.ics', optionalAuth, trainingController.getIcalExport);
|
||||
|
||||
/**
|
||||
* GET /api/training/calendar-token
|
||||
* Returns (or creates) the user's personal iCal subscribe token + URL.
|
||||
* Requires authentication.
|
||||
*/
|
||||
router.get('/calendar-token', authenticate, trainingController.getCalendarToken);
|
||||
|
||||
/**
|
||||
* GET /api/training/stats?year=<YYYY>
|
||||
* Annual participation stats.
|
||||
* Requires Kommandant or above (requirePermission('reports:read')).
|
||||
*/
|
||||
router.get(
|
||||
'/stats',
|
||||
authenticate,
|
||||
requirePermission('reports:read'),
|
||||
trainingController.getStats
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /api/training/:id
|
||||
* Single event with attendance counts.
|
||||
* Gruppenführer+ also gets the full attendee list.
|
||||
*/
|
||||
router.get(
|
||||
'/:id',
|
||||
authenticate,
|
||||
injectTeilnahmenFlag,
|
||||
trainingController.getById
|
||||
);
|
||||
|
||||
/**
|
||||
* POST /api/training
|
||||
* Create a new training event.
|
||||
* Requires Gruppenführer or above (requirePermission('training:write')).
|
||||
*/
|
||||
router.post(
|
||||
'/',
|
||||
authenticate,
|
||||
requirePermission('training:write'),
|
||||
trainingController.createEvent
|
||||
);
|
||||
|
||||
/**
|
||||
* PATCH /api/training/:id
|
||||
* Update an existing event.
|
||||
* Requires Gruppenführer or above.
|
||||
*/
|
||||
router.patch(
|
||||
'/:id',
|
||||
authenticate,
|
||||
requirePermission('training:write'),
|
||||
trainingController.updateEvent
|
||||
);
|
||||
|
||||
/**
|
||||
* DELETE /api/training/:id
|
||||
* Soft-cancel an event (sets abgesagt=true, records reason).
|
||||
* Requires Kommandant or above.
|
||||
*/
|
||||
router.delete(
|
||||
'/:id',
|
||||
authenticate,
|
||||
requirePermission('training:cancel'),
|
||||
trainingController.cancelEvent
|
||||
);
|
||||
|
||||
/**
|
||||
* PATCH /api/training/:id/attendance
|
||||
* Any authenticated member updates their own RSVP.
|
||||
*/
|
||||
router.patch(
|
||||
'/:id/attendance',
|
||||
authenticate,
|
||||
trainingController.updateRsvp
|
||||
);
|
||||
|
||||
/**
|
||||
* POST /api/training/:id/attendance/mark
|
||||
* Gruppenführer bulk-marks who actually appeared.
|
||||
*/
|
||||
router.post(
|
||||
'/:id/attendance/mark',
|
||||
authenticate,
|
||||
requirePermission('training:mark_attendance'),
|
||||
trainingController.markAttendance
|
||||
);
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user