Skip to content

Commit 2cd6aab

Browse files
authored
Merge pull request #1878 from Real-Dev-Squad/develop
Dev to main sync
2 parents fca65b4 + f968e2e commit 2cd6aab

26 files changed

+1005
-421
lines changed

constants/oooRequest.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export const OOO_REQUEST_ALREADY_PENDING =
2+
"You already have a pending request. Please wait for it to be approved or rejected.";
3+
export const ERROR_WHILE_CREATING_OOO_REQUEST = "Error while creating OOO request";
4+
export const ERROR_WHILE_UPDATING_OOO_REQUEST = "Error while updating OOO request";
5+
export const OOO_STATUS_REQUEST_CREATED_SUCCESSFULLY = "OOO status requested successfully";
6+
export const OOO_STATUS_REQUEST_UPDATED_SUCCESSFULLY = "OOO status request updated successfully";
7+
8+
export const OOO_LOG_TYPE = {
9+
OOO_REQUEST_CREATED: "OOO_REQUEST_CREATED",
10+
OOO_REQUEST_APPROVED: "OOO_REQUEST_APPROVED",
11+
OOO_REQUEST_REJECTED: "OOO_REQUEST_REJECTED",
12+
OOO_REQUEST_BLOCKED: "OOO_REQUEST_BLOCKED",
13+
OOO_REQUEST_CANCELLED: "OOO_REQUEST_CANCELLED",
14+
};
15+
16+
export const LOG_ACTION={
17+
CREATE:"create",
18+
ERRORS:"errors",
19+
UPDATE:"update",
20+
}

constants/request.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
export const REQUEST_STATE = {
2-
APPROVED: "APPROVED",
3-
PENDING: "PENDING",
4-
REJECTED: "REJECTED",
5-
};
2+
APPROVED: "APPROVED",
3+
PENDING: "PENDING",
4+
REJECTED: "REJECTED",
5+
};
6+
7+
export const REQUEST_TYPE = {
8+
OOO: "OOO",
9+
};

constants/tasks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const TASK_STATUS = {
2121
VERIFIED: "VERIFIED",
2222
DONE: "DONE",
2323
OVERDUE: "OVERDUE",
24+
BACKLOG: "BACKLOG",
2425
};
2526

2627
// TODO: convert this to new task status

controllers/oooRequests.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { createOooRequest, updateOooRequest } from "../models/oooRequests";
2+
import { OooRequestCreateRequest, OooRequestResponse, OooRequestUpdateRequest } from "../types/oooRequest";
3+
import { addLog } from "../models/logs";
4+
import {
5+
ERROR_WHILE_CREATING_OOO_REQUEST,
6+
ERROR_WHILE_UPDATING_OOO_REQUEST,
7+
LOG_ACTION,
8+
OOO_LOG_TYPE,
9+
OOO_STATUS_REQUEST_CREATED_SUCCESSFULLY,
10+
OOO_STATUS_REQUEST_UPDATED_SUCCESSFULLY,
11+
} from "../constants/oooRequest";
12+
import { REQUEST_STATE } from "../constants/request";
13+
14+
export const createOooRequestController = async (
15+
req: OooRequestCreateRequest, res: OooRequestResponse) => {
16+
const oooRequestBody = req.body;
17+
const userId = req?.userData?.id;
18+
if (!userId) {
19+
return res.boom.unauthorized();
20+
}
21+
22+
try {
23+
const oooRequestResult = await createOooRequest({ requestedBy: userId, ...oooRequestBody });
24+
if ('error' in oooRequestResult) {
25+
const oooRequestLog = {
26+
type: OOO_LOG_TYPE.OOO_REQUEST_BLOCKED,
27+
meta: {
28+
action: LOG_ACTION.ERRORS,
29+
createdBy: userId,
30+
createdAt: Date.now(),
31+
},
32+
body: {
33+
error: oooRequestResult.error,
34+
...oooRequestBody,
35+
},
36+
};
37+
await addLog(oooRequestLog.type, oooRequestLog.meta, oooRequestLog.body);
38+
39+
return res.boom.badRequest(oooRequestResult.error);
40+
} else {
41+
const oooRequestLog = {
42+
type: OOO_LOG_TYPE.OOO_REQUEST_CREATED,
43+
meta: {
44+
oooRequestId: oooRequestResult.id,
45+
action: LOG_ACTION.CREATE,
46+
createdBy: userId,
47+
createdAt: Date.now(),
48+
},
49+
body: oooRequestResult,
50+
};
51+
await addLog(oooRequestLog.type, oooRequestLog.meta, oooRequestLog.body);
52+
return res.status(201).json({
53+
message: OOO_STATUS_REQUEST_CREATED_SUCCESSFULLY,
54+
data: {
55+
id: oooRequestResult.id,
56+
...oooRequestResult,
57+
},
58+
});
59+
}
60+
} catch (err) {
61+
logger.error(ERROR_WHILE_CREATING_OOO_REQUEST, err);
62+
return res.boom.badImplementation(ERROR_WHILE_CREATING_OOO_REQUEST);
63+
}
64+
}
65+
66+
export const updateOooRequestController = async (req: OooRequestUpdateRequest, res: OooRequestResponse) => {
67+
const oooRequestBody = req.body;
68+
const userId = req?.userData?.id;
69+
const oooRequestId = req.params.id;
70+
if (!userId) {
71+
return res.boom.unauthorized();
72+
}
73+
74+
try {
75+
const oooRequestResult = await updateOooRequest(oooRequestId, oooRequestBody, userId);
76+
if ('error' in oooRequestResult) {
77+
return res.boom.badRequest(oooRequestResult.error);
78+
}
79+
if (oooRequestResult.state === REQUEST_STATE.REJECTED) {
80+
return res.boom.badRequest(oooRequestResult.error);
81+
} else {
82+
const oooRequestLog = {
83+
type: OOO_LOG_TYPE.OOO_REQUEST_APPROVED,
84+
meta: {
85+
oooRequestId: oooRequestId,
86+
action: LOG_ACTION.UPDATE,
87+
createdBy: userId,
88+
createdAt: Date.now(),
89+
},
90+
body: oooRequestResult,
91+
};
92+
await addLog(oooRequestLog.type, oooRequestLog.meta, oooRequestLog.body);
93+
return res.status(201).json({
94+
message: OOO_STATUS_REQUEST_UPDATED_SUCCESSFULLY,
95+
data: {
96+
id: oooRequestId,
97+
...oooRequestResult,
98+
},
99+
});
100+
}
101+
} catch (err) {
102+
logger.error(ERROR_WHILE_UPDATING_OOO_REQUEST, err);
103+
return res.boom.badImplementation(ERROR_WHILE_UPDATING_OOO_REQUEST);
104+
}
105+
};

controllers/requests.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { OooRequestResponse, OooRequestCreateRequest, OooRequestUpdateRequest } from "../types/oooRequest";
2+
import { REQUEST_TYPE } from "../constants/request";
3+
import { createOooRequestController, updateOooRequestController } from "./oooRequests";
4+
5+
export const createRequestController = async (
6+
req: OooRequestCreateRequest,
7+
res: OooRequestResponse
8+
) => {
9+
const type = req.body.type;
10+
switch (type) {
11+
case REQUEST_TYPE.OOO:
12+
return await createOooRequestController(req as OooRequestCreateRequest, res as OooRequestResponse);
13+
default:
14+
return res.boom.badRequest("Invalid request type");
15+
}
16+
};
17+
18+
export const updateRequestController = async (
19+
req: OooRequestUpdateRequest,
20+
res: OooRequestResponse
21+
) => {
22+
const type = req.body.type;
23+
switch (type) {
24+
case REQUEST_TYPE.OOO:
25+
return await updateOooRequestController(req as OooRequestUpdateRequest, res as OooRequestResponse);
26+
default:
27+
return res.boom.badRequest("Invalid request type");
28+
}
29+
};

controllers/tasks.js

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -289,18 +289,6 @@ const updateTask = async (req, res) => {
289289
}
290290
}
291291

292-
// currently the task is assigned to a user and the superuser is trying to un assign this task from them.
293-
if (
294-
requestData?.status === TASK_STATUS.AVAILABLE &&
295-
task.taskData.status !== TASK_STATUS.AVAILABLE &&
296-
Object.keys(req.body).length === 1
297-
) {
298-
requestData.assignee = null;
299-
requestData.percentCompleted = 0;
300-
requestData.startedOn = null;
301-
requestData.endsOn = null;
302-
}
303-
304292
await tasks.updateTask(requestData, req.params.id);
305293
if (requestData.assignee) {
306294
// New Assignee Status Update
@@ -334,38 +322,40 @@ const updateTaskStatus = async (req, res, next) => {
334322
let userStatusUpdate;
335323
const taskId = req.params.id;
336324
const { userStatusFlag } = req.query;
325+
const status = req.body?.status;
337326
const { id: userId, username } = req.userData;
338327
const task = await tasks.fetchSelfTask(taskId, userId);
339328

340329
if (task.taskNotFound) return res.boom.notFound("Task doesn't exist");
341330
if (task.notAssignedToYou) return res.boom.forbidden("This task is not assigned to you");
342-
if (task.taskData.status === TASK_STATUS.VERIFIED || req.body.status === TASK_STATUS.MERGED)
331+
if (
332+
task.taskData.status === TASK_STATUS.VERIFIED ||
333+
status === TASK_STATUS.MERGED ||
334+
status === TASK_STATUS.BACKLOG
335+
)
343336
return res.boom.forbidden("Status cannot be updated. Please contact admin.");
344337

345338
if (userStatusFlag) {
346339
if (task.taskData.status === TASK_STATUS.DONE && req.body.percentCompleted < 100) {
347-
if (req.body.status === TASK_STATUS.DONE || !req.body.status) {
340+
if (status === TASK_STATUS.DONE || !status) {
348341
return res.boom.badRequest("Task percentCompleted can't updated as status is DONE");
349342
}
350343
}
351344

352-
if (
353-
(req.body.status === TASK_STATUS.DONE || req.body.status === TASK_STATUS.VERIFIED) &&
354-
task.taskData.percentCompleted !== 100
355-
) {
345+
if ((status === TASK_STATUS.DONE || status === TASK_STATUS.VERIFIED) && task.taskData.percentCompleted !== 100) {
356346
if (req.body.percentCompleted !== 100) {
357347
return res.boom.badRequest("Status cannot be updated. Task is not done yet");
358348
}
359349
}
360350
}
361351

362352
if (task.taskData.status === TASK_STATUS.COMPLETED && req.body.percentCompleted < 100) {
363-
if (req.body.status === TASK_STATUS.COMPLETED || !req.body.status) {
353+
if (status === TASK_STATUS.COMPLETED || !status) {
364354
return res.boom.badRequest("Task percentCompleted can't updated as status is COMPLETED");
365355
}
366356
}
367357
if (
368-
(req.body.status === TASK_STATUS.COMPLETED || req.body.status === TASK_STATUS.VERIFIED) &&
358+
(status === TASK_STATUS.COMPLETED || status === TASK_STATUS.VERIFIED) &&
369359
task.taskData.percentCompleted !== 100
370360
) {
371361
if (req.body.percentCompleted !== 100) {
@@ -386,16 +376,16 @@ const updateTaskStatus = async (req, res, next) => {
386376
},
387377
};
388378

389-
if (req.body.status && !req.body.percentCompleted) {
390-
taskLog.body.new.status = req.body.status;
379+
if (status && !req.body.percentCompleted) {
380+
taskLog.body.new.status = status;
391381
}
392-
if (req.body.percentCompleted && !req.body.status) {
382+
if (req.body.percentCompleted && !status) {
393383
taskLog.body.new.percentCompleted = req.body.percentCompleted;
394384
}
395385

396-
if (req.body.percentCompleted && req.body.status) {
386+
if (req.body.percentCompleted && status) {
397387
taskLog.body.new.percentCompleted = req.body.percentCompleted;
398-
taskLog.body.new.status = req.body.status;
388+
taskLog.body.new.status = status;
399389
}
400390

401391
const [, taskLogResult] = await Promise.all([
@@ -404,7 +394,7 @@ const updateTaskStatus = async (req, res, next) => {
404394
]);
405395
taskLog.id = taskLogResult.id;
406396

407-
if (req.body.status) {
397+
if (status) {
408398
userStatusUpdate = await updateStatusOnTaskCompletion(userId);
409399
}
410400
return res.json({

controllers/users.js

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const { getOverdueTasks } = require("../models/tasks");
2020
const { getQualifiers } = require("../utils/helper");
2121
const { parseSearchQuery } = require("../utils/users");
2222
const { getFilteredPRsOrIssues } = require("../utils/pullRequests");
23-
23+
const { getFilteredPaginationLink } = require("../utils/userStatus");
2424
const {
2525
USERS_PATCH_HANDLER_ACTIONS,
2626
USERS_PATCH_HANDLER_ERROR_MESSAGES,
@@ -732,16 +732,45 @@ const addDefaultArchivedRole = async (req, res) => {
732732
* @param res {Object} - Express response object
733733
*/
734734

735+
const calculatePagination = (pageNumber, totalPages, reqQuery, limitNumber) => {
736+
const nextPage = pageNumber < totalPages - 1 ? pageNumber + 1 : null;
737+
const prevPage = pageNumber > 0 ? pageNumber - 1 : null;
738+
739+
return {
740+
next: nextPage ? getFilteredPaginationLink(reqQuery, nextPage, limitNumber) : null,
741+
prev: prevPage ? getFilteredPaginationLink(reqQuery, prevPage, limitNumber) : null,
742+
};
743+
};
744+
735745
const filterUsers = async (req, res) => {
736746
try {
737747
if (!Object.keys(req.query).length) {
738748
return res.boom.badRequest("filter for item not provided");
739749
}
750+
const dev = req.query.dev;
751+
if (dev !== "true") {
752+
const users = await dataAccess.retreiveFilteredUsers(req.query);
753+
return res.json({
754+
message: users.length ? "Users found successfully!" : "No users found",
755+
users: users,
756+
count: users.length,
757+
});
758+
}
759+
const { page, size } = req.query;
760+
const pageNumber = parseInt(page) || 0;
761+
const limitNumber = parseInt(size) || 100;
762+
const skip = (pageNumber - 1) * limitNumber;
763+
764+
const users = await dataAccess.retreiveFilteredUsers(req.query, skip, limitNumber);
765+
const totalCount = users.length;
766+
const totalPages = Math.ceil(totalCount / limitNumber);
767+
768+
const paginationLinks = calculatePagination(pageNumber, totalPages, req.query, limitNumber);
740769

741-
const users = await dataAccess.retreiveFilteredUsers(req.query);
742770
return res.json({
743771
message: users.length ? "Users found successfully!" : "No users found",
744772
users: users,
773+
links: paginationLinks,
745774
count: users.length,
746775
});
747776
} catch (error) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import joi from "joi";
2+
import { NextFunction } from "express";
3+
import { REQUEST_STATE, REQUEST_TYPE } from "../../constants/request";
4+
import { OooRequestCreateRequest, OooRequestResponse,OooRequestUpdateRequest } from "../../types/oooRequest";
5+
6+
export const createOooStatusRequestValidator = async (
7+
req: OooRequestCreateRequest,
8+
res: OooRequestResponse,
9+
next: NextFunction
10+
) => {
11+
const schema = joi
12+
.object()
13+
.strict()
14+
.keys({
15+
from: joi
16+
.number()
17+
.min(Date.now())
18+
.messages({
19+
"number.min": "from date must be greater than or equal to Today's date",
20+
})
21+
.required(),
22+
until: joi
23+
.number()
24+
.min(joi.ref("from"))
25+
.messages({
26+
"number.min": "until date must be greater than or equal to from date",
27+
})
28+
.required(),
29+
message: joi.string().required().messages({
30+
"any.required": "message is required",
31+
"string.empty": "message cannot be empty",
32+
}),
33+
state: joi.string().valid(REQUEST_STATE.PENDING).required().messages({
34+
"any.only": "state must be PENDING",
35+
}),
36+
type: joi.string().valid(REQUEST_TYPE.OOO).required(),
37+
});
38+
39+
await schema.validateAsync(req.body, { abortEarly: false });
40+
};
41+
42+
43+
export const updateOooStatusRequestValidator = async (
44+
req: OooRequestUpdateRequest,
45+
46+
) => {
47+
const schema = joi
48+
.object()
49+
.strict()
50+
.keys({
51+
reason: joi.string().optional(),
52+
state: joi
53+
.string()
54+
.valid(REQUEST_STATE.APPROVED, REQUEST_STATE.REJECTED)
55+
.required()
56+
.messages({
57+
"any.only": "state must be APPROVED or REJECTED",
58+
}),
59+
type: joi.string().valid(REQUEST_TYPE.OOO).required(),
60+
});
61+
62+
await schema.validateAsync(req.body, { abortEarly: false });
63+
};

0 commit comments

Comments
 (0)