3c892d02ed
Jenkins Production Deployment
Reviewed-on: #13 Co-authored-by: Patrick Müller <mail@pmueller.me> Co-committed-by: Patrick Müller <mail@pmueller.me>
183 lines
6.2 KiB
TypeScript
183 lines
6.2 KiB
TypeScript
/**
|
|
* 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]
|
|
* security:
|
|
* - AdminSessionCookie: []
|
|
* parameters:
|
|
* - 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
|
|
* 403:
|
|
* description: Signed in without the permission for this app, or account disabled
|
|
* post:
|
|
* summary: Create a question
|
|
* tags: [feedback-admin]
|
|
* security:
|
|
* - AdminSessionCookie: []
|
|
* 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
|
|
* 403:
|
|
* description: Signed in without the permission for this app, or account disabled
|
|
*/
|
|
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]
|
|
* security:
|
|
* - AdminSessionCookie: []
|
|
* parameters:
|
|
* - 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
|
|
* 403:
|
|
* description: Signed in without the permission for this app, or account disabled
|
|
* 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]
|
|
* security:
|
|
* - AdminSessionCookie: []
|
|
* parameters:
|
|
* - in: path
|
|
* name: questionId
|
|
* required: true
|
|
* schema:
|
|
* type: integer
|
|
* responses:
|
|
* 200:
|
|
* description: Archived or deleted
|
|
* 404:
|
|
* description: Unknown question
|
|
* 401:
|
|
* description: Unauthorized
|
|
* 403:
|
|
* description: Signed in without the permission for this app, or account disabled
|
|
*/
|
|
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);
|
|
}
|
|
});
|