"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.responsesAdminRouter = exports.responsesPublicRouter = exports.responseCampaignPublicRouter = void 0; const express_1 = require("express"); const responses_service_1 = require("./responses.service"); const responses_schemas_1 = require("./responses.schemas"); const validate_1 = require("../../../middleware/validate"); const auth_middleware_1 = require("../../../middleware/auth.middleware"); const auth_middleware_2 = require("../../../middleware/auth.middleware"); const rbac_middleware_1 = require("../../../middleware/rbac.middleware"); const rate_limit_1 = require("../../../middleware/rate-limit"); const roles_1 = require("../../../utils/roles"); // --- Campaign-scoped public routes (mount at /api/campaigns) --- const campaignPublicRouter = (0, express_1.Router)(); exports.responseCampaignPublicRouter = campaignPublicRouter; // GET /api/campaigns/:slug/responses campaignPublicRouter.get('/:slug/responses', (0, validate_1.validate)(responses_schemas_1.listPublicResponsesSchema, 'query'), async (req, res, next) => { try { const slug = req.params.slug; const result = await responses_service_1.responsesService.listApproved(slug, req.query); res.json(result); } catch (err) { next(err); } }); // GET /api/campaigns/:slug/response-stats campaignPublicRouter.get('/:slug/response-stats', async (req, res, next) => { try { const slug = req.params.slug; const stats = await responses_service_1.responsesService.getStats(slug); res.json(stats); } catch (err) { next(err); } }); // POST /api/campaigns/:slug/responses campaignPublicRouter.post('/:slug/responses', rate_limit_1.responseRateLimit, (0, validate_1.validate)(responses_schemas_1.submitResponseSchema), async (req, res, next) => { try { const slug = req.params.slug; const senderIp = req.ip || req.socket.remoteAddress; const result = await responses_service_1.responsesService.submitResponse(slug, req.body, senderIp); res.status(201).json(result); } catch (err) { next(err); } }); // --- Response-scoped public routes (mount at /api/responses) --- const responsesPublicRouter = (0, express_1.Router)(); exports.responsesPublicRouter = responsesPublicRouter; // POST /api/responses/:id/upvote responsesPublicRouter.post('/:id/upvote', auth_middleware_2.optionalAuth, async (req, res, next) => { try { const id = req.params.id; const userIp = req.ip || req.socket.remoteAddress; const userId = req.user?.id; const result = await responses_service_1.responsesService.upvote(id, userIp, userId); res.json(result); } catch (err) { next(err); } }); // DELETE /api/responses/:id/upvote responsesPublicRouter.delete('/:id/upvote', auth_middleware_2.optionalAuth, async (req, res, next) => { try { const id = req.params.id; const userIp = req.ip || req.socket.remoteAddress; const userId = req.user?.id; const result = await responses_service_1.responsesService.removeUpvote(id, userIp, userId); res.json(result); } catch (err) { next(err); } }); // GET /api/responses/:id/verify/:token — returns HTML page responsesPublicRouter.get('/:id/verify/:token', async (req, res, next) => { try { const id = req.params.id; const token = req.params.token; const result = await responses_service_1.responsesService.verify(id, token); const html = result.success ? buildResultPage('Response Verified', `Thank you for verifying this response for the "${result.campaignTitle}" campaign. The response has been approved and will now appear on the public response wall.`, '#16a34a') : buildResultPage('Verification Failed', result.reason || 'Unable to verify this response.', '#dc2626'); res.type('html').send(html); } catch (err) { next(err); } }); // GET /api/responses/:id/report/:token — returns HTML page responsesPublicRouter.get('/:id/report/:token', async (req, res, next) => { try { const id = req.params.id; const token = req.params.token; const result = await responses_service_1.responsesService.report(id, token); const html = result.success ? buildResultPage('Response Reported', `This response for the "${result.campaignTitle}" campaign has been flagged as invalid and removed from the public response wall. Thank you for letting us know.`, '#dc2626') : buildResultPage('Report Failed', result.reason || 'Unable to process this report.', '#dc2626'); res.type('html').send(html); } catch (err) { next(err); } }); // --- Admin routes (mount at /api/responses) --- const responsesAdminRouter = (0, express_1.Router)(); exports.responsesAdminRouter = responsesAdminRouter; responsesAdminRouter.use(auth_middleware_1.authenticate); responsesAdminRouter.use((0, rbac_middleware_1.requireRole)(...roles_1.INFLUENCE_ROLES)); // GET /api/responses responsesAdminRouter.get('/', (0, validate_1.validate)(responses_schemas_1.listAdminResponsesSchema, 'query'), async (req, res, next) => { try { const result = await responses_service_1.responsesService.findAll(req.query); res.json(result); } catch (err) { next(err); } }); // PATCH /api/responses/:id/status responsesAdminRouter.patch('/:id/status', (0, validate_1.validate)(responses_schemas_1.updateResponseStatusSchema), async (req, res, next) => { try { const id = req.params.id; const result = await responses_service_1.responsesService.updateStatus(id, req.body); res.json(result); } catch (err) { next(err); } }); // POST /api/responses/:id/resend-verification responsesAdminRouter.post('/:id/resend-verification', async (req, res, next) => { try { const id = req.params.id; const result = await responses_service_1.responsesService.resendVerification(id); res.json(result); } catch (err) { next(err); } }); // DELETE /api/responses/:id responsesAdminRouter.delete('/:id', async (req, res, next) => { try { const id = req.params.id; await responses_service_1.responsesService.deleteResponse(id); res.status(204).send(); } catch (err) { next(err); } }); // --- HTML page builder for verify/report endpoints --- function escapeHtml(unsafe) { return unsafe .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function buildResultPage(title, message, accentColor) { const escapedTitle = escapeHtml(title); const escapedMessage = escapeHtml(message); return `
${escapedMessage}