generated from Real-Dev-Squad/website-template
-
Notifications
You must be signed in to change notification settings - Fork 264
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2034 from Real-Dev-Squad/develop
Dev to main sync
- Loading branch information
Showing
19 changed files
with
646 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { getRequestByKeyValues } from "../models/requests"; | ||
import { LOG_ACTION, REQUEST_LOG_TYPE, REQUEST_STATE, REQUEST_TYPE } from "../constants/requests"; | ||
import { addLog } from "../models/logs"; | ||
import { createRequest } from "../models/requests"; | ||
import { fetchTask } from "../models/tasks"; | ||
import { CustomResponse } from "../typeDefinitions/global"; | ||
import { ExtensionRequest, ExtensionRequestCreateBody, ExtensionRequestRequest } from "../types/extensionRequests"; | ||
import { getUsernameElseUndefined } from "../utils/users"; | ||
|
||
export const createTaskExtensionRequest = async (req: ExtensionRequestRequest, res: CustomResponse) => { | ||
try { | ||
const { userData } = req; | ||
const { id: requestedBy, roles } = userData || {}; | ||
const { body } = req; | ||
|
||
if (!requestedBy) { | ||
return res.boom.unauthorized(); | ||
} | ||
|
||
const { taskId } = body; | ||
let extensionBody: ExtensionRequestCreateBody = { ...body, requestedBy }; | ||
let assignee: string | undefined = undefined; | ||
|
||
const { taskData: task } = await fetchTask(taskId); | ||
if (!task) { | ||
return res.boom.badRequest("Task Not Found"); | ||
} | ||
|
||
const { assigneeId, endsOn } = task; | ||
if (!assigneeId) { | ||
return res.boom.badRequest("Assignee is not present for this task"); | ||
} | ||
|
||
assignee = await getUsernameElseUndefined(assigneeId); | ||
if (!assignee) { | ||
return res.boom.badRequest("Assignee is not present for this task"); | ||
} else { | ||
extensionBody = { ...extensionBody, assignee }; | ||
} | ||
|
||
if (requestedBy !== assigneeId && !roles?.super_user) { | ||
return res.boom.forbidden("Only assigned user and super user can create an extension request for this task."); | ||
} | ||
|
||
if (endsOn >= body.newEndsOn) { | ||
return res.boom.badRequest("New ETA must be greater than Old ETA"); | ||
} | ||
|
||
if (body.oldEndsOn != endsOn) { | ||
return res.boom.badRequest("Old ETA does not match the task's ETA"); | ||
} | ||
|
||
const latestExtensionRequest: ExtensionRequest | undefined = await getRequestByKeyValues({ | ||
taskId, | ||
state: REQUEST_STATE.PENDING, | ||
type: REQUEST_TYPE.EXTENSION, | ||
}); | ||
|
||
if (latestExtensionRequest && latestExtensionRequest.state === REQUEST_STATE.PENDING) { | ||
return res.boom.badRequest("An extension request for this task already exists."); | ||
} | ||
|
||
let requestNumber: number = latestExtensionRequest?.requestedBy === requestedBy && latestExtensionRequest.requestNumber ? latestExtensionRequest.requestNumber + 1 : 1; | ||
extensionBody = { ...extensionBody, requestNumber }; | ||
|
||
const extensionRequest = await createRequest(extensionBody); | ||
if ("error" in extensionRequest) { | ||
return res.boom.badRequest(extensionRequest.error); | ||
} | ||
|
||
const extensionLog = { | ||
type: REQUEST_LOG_TYPE.REQUEST_CREATED, | ||
meta: { | ||
taskId, | ||
requestId: extensionRequest.id, | ||
action: LOG_ACTION.CREATE, | ||
createdBy: requestedBy, | ||
createdAt: Date.now(), | ||
}, | ||
body: extensionBody, | ||
}; | ||
|
||
await addLog(extensionLog.type, extensionLog.meta, extensionLog.body); | ||
|
||
return res.status(201).json({ | ||
message: "Extension Request created successfully!", | ||
extensionRequest: { ...extensionBody, id: extensionRequest.id }, | ||
}); | ||
} catch (err) { | ||
logger.error(`Error while creating new extension request: ${err}`); | ||
return res.boom.badImplementation('Internal Server Error'); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { | ||
REQUEST_LOG_TYPE, | ||
LOG_ACTION, | ||
REQUEST_CREATED_SUCCESSFULLY, | ||
ERROR_WHILE_CREATING_REQUEST, | ||
REQUEST_ALREADY_PENDING, | ||
REQUEST_STATE, | ||
REQUEST_TYPE, | ||
} from "../constants/requests"; | ||
import { addLog } from "../models/logs"; | ||
import { createRequest, getRequestByKeyValues } from "../models/requests"; | ||
import { CustomResponse } from "../typeDefinitions/global"; | ||
import { OooRequestCreateRequest, OooStatusRequest } from "../types/oooRequest"; | ||
|
||
export const createOooRequestController = async (req: OooRequestCreateRequest, res: CustomResponse) => { | ||
const requestBody = req.body; | ||
const userId = req?.userData?.id; | ||
|
||
if (!userId) { | ||
return res.boom.unauthorized(); | ||
} | ||
|
||
try { | ||
const latestOooRequest:OooStatusRequest = await getRequestByKeyValues({ requestedBy: userId, type: REQUEST_TYPE.OOO , state: REQUEST_STATE.PENDING }); | ||
|
||
if (latestOooRequest && latestOooRequest.state === REQUEST_STATE.PENDING) { | ||
return res.boom.badRequest(REQUEST_ALREADY_PENDING); | ||
} | ||
|
||
const requestResult = await createRequest({ requestedBy: userId, ...requestBody }); | ||
|
||
const requestLog = { | ||
type: REQUEST_LOG_TYPE.REQUEST_CREATED, | ||
meta: { | ||
requestId: requestResult.id, | ||
action: LOG_ACTION.CREATE, | ||
createdBy: userId, | ||
createdAt: Date.now(), | ||
}, | ||
body: requestResult, | ||
}; | ||
await addLog(requestLog.type, requestLog.meta, requestLog.body); | ||
|
||
return res.status(201).json({ | ||
message: REQUEST_CREATED_SUCCESSFULLY, | ||
data: { | ||
id: requestResult.id, | ||
...requestResult, | ||
}, | ||
}); | ||
} catch (err) { | ||
logger.error(ERROR_WHILE_CREATING_REQUEST, err); | ||
return res.boom.badImplementation(ERROR_WHILE_CREATING_REQUEST); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import joi from "joi"; | ||
import { ExtensionRequestRequest, ExtensionRequestResponse } from "../../types/extensionRequests"; | ||
import { NextFunction } from "express"; | ||
import { REQUEST_TYPE,REQUEST_STATE } from "../../constants/requests"; | ||
|
||
export const createExtensionRequestValidator = async ( | ||
req: ExtensionRequestRequest, | ||
res: ExtensionRequestResponse, | ||
next: NextFunction | ||
) => { | ||
|
||
const schema = joi | ||
.object() | ||
.strict() | ||
.keys({ | ||
taskId: joi.string().required().messages({ | ||
"string.empty": "taskId cannot be empty", | ||
"any.required": "taskId is required", | ||
}), | ||
title: joi.string().required().messages({ | ||
"string.empty": "title cannot be empty", | ||
"any.required": "title is required", | ||
}), | ||
oldEndsOn: joi.number().required().messages({ | ||
"number.base": "oldEndsOn must be a number", | ||
"any.required": "oldEndsOn is required", | ||
}), | ||
newEndsOn: joi.number().required().min(joi.ref("oldEndsOn")).messages({ | ||
"number.base": "newEndsOn must be a number", | ||
"any.required": "newEndsOn is required", | ||
}), | ||
message: joi.string().required().messages({ | ||
"string.empty": "message cannot be empty", | ||
}), | ||
state: joi.string().valid(REQUEST_STATE.PENDING).required().messages({ | ||
"string.empty": "state cannot be empty", | ||
"any.required": "state is required", | ||
}), | ||
type: joi.string().valid(REQUEST_TYPE.EXTENSION).required().messages({ | ||
"string.empty": "type cannot be empty", | ||
"any.required": "type is required", | ||
}), | ||
}); | ||
|
||
await schema.validateAsync(req.body, { abortEarly: false }); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.