|
| 1 | +import joi from "joi"; |
| 2 | +import { TaskRequestResponse, TaskRequestRequest } from "../../types/taskRequests"; |
| 3 | +import { NextFunction } from "express"; |
| 4 | +import { REQUEST_TYPE, REQUEST_STATE } from "../../constants/requests"; |
| 5 | +import { GITHUB_URL } from "../../constants/urls"; |
| 6 | + |
| 7 | +import config from "config"; |
| 8 | +import { TASK_REQUEST_TYPE } from "../../constants/taskRequests"; |
| 9 | +const githubOrg = config.get("githubApi.org"); |
| 10 | +const githubBaseUrl = config.get("githubApi.baseUrl"); |
| 11 | +const githubIssuerUrlPattern = new RegExp(`^${githubBaseUrl}/repos/${githubOrg}/.+/issues/\\d+$`); |
| 12 | +const githubIssueHtmlUrlPattern = new RegExp(`^${GITHUB_URL}/${githubOrg}/.+/issues/\\d+$`); // Example: https://github.com/Real-Dev-Squad/website-status/issues/1050 |
| 13 | + |
| 14 | +export const createTaskRequestValidator = async ( |
| 15 | + req: TaskRequestRequest, |
| 16 | + res: TaskRequestResponse, |
| 17 | + next: NextFunction |
| 18 | +) => { |
| 19 | + const schema = joi |
| 20 | + .object() |
| 21 | + .strict() |
| 22 | + .keys({ |
| 23 | + requestType: joi.string().valid(TASK_REQUEST_TYPE.CREATION, TASK_REQUEST_TYPE.ASSIGNMENT).required().messages({ |
| 24 | + "string.empty": "requestType cannot be empty", |
| 25 | + "any.required": "requestType is required", |
| 26 | + }), |
| 27 | + externalIssueUrl: joi.string().required().regex(githubIssuerUrlPattern).required().messages({ |
| 28 | + "string.empty": "externalIssueUrl cannot be empty", |
| 29 | + "any.required": "externalIssueUrl is required", |
| 30 | + }), |
| 31 | + externalIssueHtmlUrl: joi.string().required().regex(githubIssueHtmlUrlPattern).messages({ |
| 32 | + "string.empty": "externalIssueHtmlUrl cannot be empty", |
| 33 | + "any.required": "externalIssueHtmlUrl is required", |
| 34 | + }), |
| 35 | + type: joi.string().valid(REQUEST_TYPE.TASK).required().messages({ |
| 36 | + "string.empty": "type cannot be empty", |
| 37 | + "any.required": "type is required", |
| 38 | + }), |
| 39 | + state: joi.string().valid(REQUEST_STATE.PENDING).required().messages({ |
| 40 | + "string.empty": "state cannot be empty", |
| 41 | + "any.required": "state is required", |
| 42 | + }), |
| 43 | + proposedStartDate: joi.number().required().messages({ |
| 44 | + "number.base": "proposedStartDate must be a number", |
| 45 | + "any.required": "proposedStartDate is required", |
| 46 | + }), |
| 47 | + proposedDeadline: joi.number().required().greater(joi.ref("proposedStartDate")). |
| 48 | + messages({ |
| 49 | + "number.base": "proposedDeadline must be a number", |
| 50 | + "any.required": "proposedDeadline is required", |
| 51 | + }), |
| 52 | + description: joi.string().optional().messages({ |
| 53 | + "string.empty": "description cannot be empty", |
| 54 | + }), |
| 55 | + markdownEnabled: joi.boolean().optional().messages({ |
| 56 | + "boolean.base": "markdownEnabled must be a boolean", |
| 57 | + }), |
| 58 | + taskId: joi.when('requestType', { |
| 59 | + is: TASK_REQUEST_TYPE.ASSIGNMENT, |
| 60 | + then: joi.string().required().messages({ |
| 61 | + "string.empty": "taskId cannot be empty", |
| 62 | + "any.required": "taskId is required when requestType is ASSIGNMENT", |
| 63 | + }), |
| 64 | + otherwise: joi.forbidden() |
| 65 | + }), |
| 66 | + userId: joi.when('requestType', { |
| 67 | + is: TASK_REQUEST_TYPE.CREATION, |
| 68 | + then: joi.string().required().messages({ |
| 69 | + "string.empty": "userId cannot be empty", |
| 70 | + "any.required": "userId is required when requestType is CREATION", |
| 71 | + }), |
| 72 | + otherwise: joi.forbidden() |
| 73 | + }), |
| 74 | + }); |
| 75 | + await schema.validateAsync(req.body, { abortEarly: false }); |
| 76 | +}; |
0 commit comments