"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.shiftsVolunteerRouter = exports.shiftsPublicRouter = exports.shiftsAdminRouter = void 0; const express_1 = require("express"); const shifts_service_1 = require("./shifts.service"); const shifts_schemas_1 = require("./shifts.schemas"); const validate_1 = require("../../../middleware/validate"); const auth_middleware_1 = require("../../../middleware/auth.middleware"); const rbac_middleware_1 = require("../../../middleware/rbac.middleware"); const rate_limit_1 = require("../../../middleware/rate-limit"); const database_1 = require("../../../config/database"); const redis_1 = require("../../../config/redis"); const roles_1 = require("../../../utils/roles"); // --- Admin Router --- const adminRouter = (0, express_1.Router)(); exports.shiftsAdminRouter = adminRouter; adminRouter.use(auth_middleware_1.authenticate); adminRouter.use((0, rbac_middleware_1.requireRole)(...roles_1.SCHEDULING_ROLES)); // GET /api/map/shifts — list paginated adminRouter.get('/', (0, validate_1.validate)(shifts_schemas_1.listShiftsSchema, 'query'), async (req, res, next) => { try { const result = await shifts_service_1.shiftsService.findAll(req.query); res.json(result); } catch (err) { next(err); } }); // GET /api/map/shifts/stats — statistics adminRouter.get('/stats', async (_req, res, next) => { try { const stats = await shifts_service_1.shiftsService.getStats(); res.json(stats); } catch (err) { next(err); } }); // GET /api/map/shifts/calendar — calendar data adminRouter.get('/calendar', async (req, res, next) => { try { const { startDate, endDate } = req.query; if (!startDate || !endDate) { return res.status(400).json({ error: 'startDate and endDate required' }); } const data = await shifts_service_1.shiftsService.getCalendarData(startDate, endDate); res.json(data); } catch (err) { next(err); } }); // GET /api/map/shifts/:id — single shift with signups adminRouter.get('/:id', async (req, res, next) => { try { const id = req.params.id; const shift = await shifts_service_1.shiftsService.findById(id); res.json(shift); } catch (err) { next(err); } }); // POST /api/map/shifts — create adminRouter.post('/', (0, validate_1.validate)(shifts_schemas_1.createShiftSchema), async (req, res, next) => { try { const shift = await shifts_service_1.shiftsService.create(req.body, req.user.id); res.status(201).json(shift); } catch (err) { next(err); } }); // PUT /api/map/shifts/:id — update adminRouter.put('/:id', (0, validate_1.validate)(shifts_schemas_1.updateShiftSchema), async (req, res, next) => { try { const id = req.params.id; const shift = await shifts_service_1.shiftsService.update(id, req.body); res.json(shift); } catch (err) { next(err); } }); // DELETE /api/map/shifts/:id — delete adminRouter.delete('/:id', async (req, res, next) => { try { const id = req.params.id; await shifts_service_1.shiftsService.delete(id); res.status(204).send(); } catch (err) { next(err); } }); // POST /api/map/shifts/:id/signups — admin add volunteer adminRouter.post('/:id/signups', (0, validate_1.validate)(shifts_schemas_1.addSignupSchema), async (req, res, next) => { try { const id = req.params.id; const signup = await shifts_service_1.shiftsService.addSignup(id, req.body); res.status(201).json(signup); } catch (err) { next(err); } }); // DELETE /api/map/shifts/:id/signups/:signupId — admin remove volunteer adminRouter.delete('/:id/signups/:signupId', async (req, res, next) => { try { const signupId = req.params.signupId; await shifts_service_1.shiftsService.removeSignup(signupId); res.status(204).send(); } catch (err) { next(err); } }); // POST /api/map/shifts/:id/meeting — create and link a video briefing meeting adminRouter.post('/:id/meeting', async (req, res, next) => { try { const id = req.params.id; const meeting = await shifts_service_1.shiftsService.createMeetingForShift(id, req.user.id); res.status(201).json(meeting); } catch (err) { next(err); } }); // DELETE /api/map/shifts/:id/meeting — remove video briefing from shift adminRouter.delete('/:id/meeting', async (req, res, next) => { try { const id = req.params.id; await shifts_service_1.shiftsService.removeMeetingFromShift(id); res.status(204).send(); } catch (err) { next(err); } }); // POST /api/map/shifts/:id/email-details — email all volunteers adminRouter.post('/:id/email-details', async (req, res, next) => { try { const id = req.params.id; const result = await shifts_service_1.shiftsService.emailShiftDetails(id); res.json(result); } catch (err) { next(err); } }); // --- Volunteer Router --- const volunteerRouter = (0, express_1.Router)(); exports.shiftsVolunteerRouter = volunteerRouter; volunteerRouter.use(auth_middleware_1.authenticate); // GET /api/map/shifts/volunteer/upcoming — upcoming shifts with signup status volunteerRouter.get('/volunteer/upcoming', async (req, res, next) => { try { const shifts = await shifts_service_1.shiftsService.getUpcomingForVolunteer(req.user.id); res.json(shifts); } catch (err) { next(err); } }); // GET /api/map/shifts/volunteer/my-signups — own confirmed signups volunteerRouter.get('/volunteer/my-signups', async (req, res, next) => { try { const signups = await shifts_service_1.shiftsService.getMySignups(req.user.id); res.json(signups); } catch (err) { next(err); } }); // POST /api/map/shifts/volunteer/:id/signup — sign up for shift volunteerRouter.post('/volunteer/:id/signup', rate_limit_1.shiftSignupRateLimit, async (req, res, next) => { try { const id = req.params.id; const signup = await shifts_service_1.shiftsService.volunteerSignup(id, req.user.id); res.status(201).json(signup); } catch (err) { next(err); } }); // DELETE /api/map/shifts/volunteer/:id/signup — cancel own signup volunteerRouter.delete('/volunteer/:id/signup', async (req, res, next) => { try { const id = req.params.id; await shifts_service_1.shiftsService.cancelVolunteerSignup(id, req.user.id); res.status(204).send(); } catch (err) { next(err); } }); // --- Public Router --- const publicRouter = (0, express_1.Router)(); exports.shiftsPublicRouter = publicRouter; // GET /api/map/shifts/public — list upcoming public shifts publicRouter.get('/public', async (_req, res, next) => { try { const shifts = await shifts_service_1.shiftsService.getPublicShifts(); res.json(shifts); } catch (err) { next(err); } }); // POST /api/map/shifts/public/:id/signup — public signup publicRouter.post('/public/:id/signup', rate_limit_1.shiftSignupRateLimit, (0, validate_1.validate)(shifts_schemas_1.publicSignupSchema), async (req, res, next) => { try { const id = req.params.id; const result = await shifts_service_1.shiftsService.publicSignup(id, req.body); res.status(201).json(result); } catch (err) { next(err); } }); // GET /api/map/shifts/public/related — related active campaigns publicRouter.get('/public/related', async (_req, res, next) => { try { const cacheKey = 'shifts:related:campaigns'; try { const cached = await redis_1.redis.get(cacheKey); if (cached) { res.json(JSON.parse(cached)); return; } } catch { /* cache miss */ } const campaigns = await database_1.prisma.campaign.findMany({ where: { status: 'ACTIVE' }, select: { id: true, slug: true, title: true, description: true, _count: { select: { emails: true } }, }, orderBy: { createdAt: 'desc' }, take: 3, }); const result = { campaigns: campaigns.map(c => ({ id: c.id, slug: c.slug, title: c.title, description: c.description?.slice(0, 150) ?? null, emailCount: c._count.emails, })), }; try { await redis_1.redis.setex(cacheKey, 300, JSON.stringify(result)); } catch { /* non-critical */ } res.json(result); } catch (err) { next(err); } }); //# sourceMappingURL=shifts.routes.js.map