changemaker.lite/api/src/modules/social/impact-stories.routes.ts
2026-03-08 18:11:26 -06:00

104 lines
3.1 KiB
TypeScript

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;