import { Router } from 'express'; import { requireRole } from '../../middleware/rbac.middleware'; import { INFLUENCE_ROLES } from '../../utils/roles'; import { impactStoriesService } from './impact-stories.service'; import { createStorySchema, updateStorySchema, listStoriesSchema } from './impact-stories.schemas'; const router = Router(); // --- Admin routes (require admin role) --- router.post('/', requireRole(...INFLUENCE_ROLES), async (req, res, next) => { try { const data = createStorySchema.parse(req.body); const story = await impactStoriesService.create(data, req.user!.id); res.status(201).json(story); } catch (err) { next(err); } }); router.put('/:id', requireRole(...INFLUENCE_ROLES), async (req, res, next) => { try { const data = updateStorySchema.parse(req.body); const story = await impactStoriesService.update(req.params.id as string, data); res.json(story); } catch (err) { next(err); } }); router.delete('/:id', requireRole(...INFLUENCE_ROLES), async (req, res, next) => { try { const result = await impactStoriesService.delete(req.params.id as string); res.json(result); } catch (err) { next(err); } }); router.post('/:id/publish', requireRole(...INFLUENCE_ROLES), async (req, res, next) => { try { const story = await impactStoriesService.publish(req.params.id as string); // Fire-and-forget: notify participants impactStoriesService.notifyParticipants(story.id).catch(() => {}); res.json(story); } catch (err) { next(err); } }); router.post('/:id/archive', requireRole(...INFLUENCE_ROLES), async (req, res, next) => { try { const story = await impactStoriesService.archive(req.params.id as string); res.json(story); } catch (err) { next(err); } }); // --- Authenticated routes (any logged-in user) --- router.get('/', async (req, res, next) => { try { const { page, limit, campaignId, status } = listStoriesSchema.parse(req.query); // Admin users can filter by status; regular users see published only const userRoles = req.user!.roles || [req.user!.role]; const isAdmin = userRoles.some((r: string) => (INFLUENCE_ROLES as string[]).includes(r), ); if (isAdmin && (campaignId || status)) { const result = await impactStoriesService.listAdmin(page, limit, campaignId, status); res.json(result); } else { const result = await impactStoriesService.listPublished(page, limit); res.json(result); } } catch (err) { next(err); } }); router.get('/campaign/:campaignId', async (req, res, next) => { try { const { page, limit } = listStoriesSchema.parse(req.query); const campaignId = req.params.campaignId as string; const result = await impactStoriesService.listByCampaign(campaignId, page, limit); res.json(result); } catch (err) { next(err); } }); router.get('/:id', async (req, res, next) => { try { const story = await impactStoriesService.findById(req.params.id as string); res.json(story); } catch (err) { next(err); } }); export const impactStoriesRouter = router;