/** * Required External Modules and Interfaces */ import express, {Request, Response} from 'express'; import * as QuestionsAdminService from './questions.admin.service.js'; import {sendServerError} from '../feedback.errors.js'; /** * Router Definition */ export const questionsAdminRouter = express.Router(); /** * @swagger * /feedback/admin/questions: * get: * summary: List the question library * tags: [feedback-admin] * parameters: * - $ref: '#/components/parameters/SessionIdHeader' * - $ref: '#/components/parameters/SessionKeyHeader' * - in: query * name: includeArchived * schema: * type: boolean * responses: * 200: * description: Success * content: * application/json: * schema: * type: array * items: * $ref: '#/components/schemas/AdminQuestion' * 401: * description: Unauthorized * post: * summary: Create a question * tags: [feedback-admin] * parameters: * - $ref: '#/components/parameters/SessionIdHeader' * - $ref: '#/components/parameters/SessionKeyHeader' * requestBody: * required: true * content: * application/json: * schema: * type: object * required: [label, questionType] * properties: * label: * type: string * helpText: * type: string * questionType: * $ref: '#/components/schemas/QuestionType' * responses: * 201: * description: Created * 400: * description: Missing or invalid fields * 401: * description: Unauthorized */ questionsAdminRouter.get('/', async (req: Request, res: Response) => { try { const includeArchived = req.query.includeArchived === 'true'; res.status(200).send(await QuestionsAdminService.listQuestions(includeArchived)); } catch (e: any) { sendServerError(res, e); } }); const VALID_TYPES = ['SONG_PICK', 'SONG_RATING', 'FREE_TEXT']; questionsAdminRouter.post('/', async (req: Request, res: Response) => { try { const {label, helpText, questionType} = req.body || {}; if (!label || !VALID_TYPES.includes(questionType)) { res.status(400).send({status: 'BAD_REQUEST', message: 'label and a valid questionType are required'}); return; } const questionId = await QuestionsAdminService.createQuestion(label, helpText || null, questionType); res.status(201).send({questionId}); } catch (e: any) { sendServerError(res, e); } }); /** * @swagger * /feedback/admin/questions/{questionId}: * put: * summary: Edit a question's label/help text * description: question_type is immutable after creation - the admin UI offers "archive and create new" instead. * tags: [feedback-admin] * parameters: * - $ref: '#/components/parameters/SessionIdHeader' * - $ref: '#/components/parameters/SessionKeyHeader' * - in: path * name: questionId * required: true * schema: * type: integer * requestBody: * required: true * content: * application/json: * schema: * type: object * required: [label] * properties: * label: * type: string * helpText: * type: string * responses: * 200: * description: Updated * 400: * description: Missing label * 404: * description: Unknown question * 401: * description: Unauthorized * delete: * summary: Archive (or hard-delete) a question * description: Archives the question if it has ever been used; hard-deletes it if it has never been assigned to any event. * tags: [feedback-admin] * parameters: * - $ref: '#/components/parameters/SessionIdHeader' * - $ref: '#/components/parameters/SessionKeyHeader' * - in: path * name: questionId * required: true * schema: * type: integer * responses: * 200: * description: Archived or deleted * 404: * description: Unknown question * 401: * description: Unauthorized */ questionsAdminRouter.put('/:questionId', async (req: Request, res: Response) => { try { const {label, helpText} = req.body || {}; if (!label) { res.status(400).send({status: 'BAD_REQUEST', message: 'label is required'}); return; } const updated = await QuestionsAdminService.updateQuestion(Number(req.params.questionId), label, helpText || null); if (!updated) { res.status(404).send({status: 'NOT_FOUND'}); return; } res.status(200).send({status: 'OK'}); } catch (e: any) { sendServerError(res, e); } }); questionsAdminRouter.delete('/:questionId', async (req: Request, res: Response) => { try { const result = await QuestionsAdminService.removeQuestion(Number(req.params.questionId)); if (result === 'NOT_FOUND') { res.status(404).send({status: 'NOT_FOUND'}); return; } res.status(200).send({status: result}); } catch (e: any) { sendServerError(res, e); } });