Skip to content

Commit a87f032

Browse files
committed
feat: acknowledge OOO request
2 parents e33183a + b3b4c17 commit a87f032

File tree

16 files changed

+338
-200
lines changed

16 files changed

+338
-200
lines changed

constants/logs.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export const logType = {
2222
INVALID_REQUEST_TYPE: "INVALID_REQUEST_TYPE",
2323
PENDING_REQUEST_CAN_BE_UPDATED: "PENDING_REQUEST_CAN_BE_UPDATED",
2424
INVALID_REQUEST_DEADLINE: "INVALID_REQUEST_DEADLINE",
25+
USER_STATUS_NOT_FOUND: "USER_STATUS_NOT_FOUND",
26+
OOO_STATUS_FOUND: "OOO_STATUS_FOUND",
2527
...REQUEST_LOG_TYPE,
2628
};
2729

constants/requests.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const REQUEST_LOG_TYPE = {
2525
REQUEST_BLOCKED: "REQUEST_BLOCKED",
2626
REQUEST_CANCELLED: "REQUEST_CANCELLED",
2727
REQUEST_UPDATED: "REQUEST_UPDATED",
28+
PENDING_REQUEST_FOUND: "PENDING_REQUEST_FOUND",
2829
REQUEST_ALREADY_APPROVED: "REQUEST_ALREADY_APPROVED",
2930
REQUEST_ALREADY_REJECTED: "REQUEST_ALREADY_REJECTED",
3031
};
@@ -44,6 +45,9 @@ export const ERROR_WHILE_ACKNOWLEDGING_REQUEST = "Error while acknowledging requ
4445

4546
export const REQUEST_DOES_NOT_EXIST = "Request does not exist";
4647
export const REQUEST_ALREADY_PENDING = "Request already exists please wait for approval or rejection";
48+
export const UNAUTHORIZED_TO_CREATE_OOO_REQUEST = "Unauthorized to create OOO request";
49+
export const USER_STATUS_NOT_FOUND = "User status not found";
50+
export const OOO_STATUS_ALREADY_EXIST = "Your status is already OOO. Please cancel OOO to raise new one";
4751
export const UNAUTHORIZED_TO_ACKNOWLEDGE_OOO_REQUEST = "Only super users are allowed to acknowledge OOO requests";
4852

4953
export const TASK_REQUEST_MESSAGES = {

controllers/oooRequests.ts

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ import {
33
LOG_ACTION,
44
REQUEST_CREATED_SUCCESSFULLY,
55
ERROR_WHILE_CREATING_REQUEST,
6-
REQUEST_ALREADY_PENDING,
76
REQUEST_STATE,
87
REQUEST_TYPE,
98
ERROR_WHILE_UPDATING_REQUEST,
109
REQUEST_APPROVED_SUCCESSFULLY,
1110
REQUEST_REJECTED_SUCCESSFULLY,
11+
UNAUTHORIZED_TO_CREATE_OOO_REQUEST,
12+
REQUEST_ALREADY_PENDING,
13+
USER_STATUS_NOT_FOUND,
14+
OOO_STATUS_ALREADY_EXIST,
1215
UNAUTHORIZED_TO_ACKNOWLEDGE_OOO_REQUEST,
1316
ERROR_WHILE_ACKNOWLEDGING_REQUEST,
1417
REQUEST_DOES_NOT_EXIST,
@@ -17,50 +20,74 @@ import {
1720
REQUEST_ALREADY_REJECTED,
1821
} from "../constants/requests";
1922
import { statusState } from "../constants/userStatus";
23+
import { logType } from "../constants/logs";
2024
import { addLog } from "../models/logs";
21-
import { createRequest, getRequestByKeyValues, getRequests, updateRequest } from "../models/requests";
25+
import { getRequestByKeyValues, getRequests, updateRequest } from "../models/requests";
2226
import { createUserFutureStatus } from "../models/userFutureStatus";
23-
import { addFutureStatus } from "../models/userStatus";
24-
import { acknowledgeOOORequest } from "../services/oooRequest";
27+
import { getUserStatus, addFutureStatus } from "../models/userStatus";
28+
import { createOooRequest, validateUserStatus, acknowledgeOooRequest } from "../services/oooRequest";
2529
import { CustomResponse } from "../typeDefinitions/global";
26-
import { AcknowledgeOOORequest, OooRequestCreateRequest, OooRequestResponse, OooStatusRequest } from "../types/oooRequest";
30+
import { AcknowledgeOooRequest, OooRequestCreateRequest, OooRequestResponse, OooStatusRequest } from "../types/oooRequest";
2731
import { UpdateRequest } from "../types/requests";
2832

29-
export const createOooRequestController = async (req: OooRequestCreateRequest, res: CustomResponse) => {
33+
/**
34+
* Controller to handle the creation of OOO requests.
35+
*
36+
* This function processes the request to create an OOO request,
37+
* validates the user status, checks existing requests,
38+
* and stores the new request in the database with logging.
39+
*
40+
* @param {OooRequestCreateRequest} req - The Express request object containing the body with OOO details.
41+
* @param {CustomResponse} res - The Express response object used to send back the response.
42+
* @returns {Promise<OooRequestResponse>} Resolves to a response with the success or an error message.
43+
*/
44+
export const createOooRequestController = async (
45+
req: OooRequestCreateRequest,
46+
res: OooRequestResponse
47+
): Promise<OooRequestResponse> => {
48+
3049
const requestBody = req.body;
31-
const userId = req?.userData?.id;
50+
const { id: userId, username } = req.userData;
51+
const isUserPartOfDiscord = req.userData.roles.in_discord;
52+
const dev = req.query.dev === "true";
3253

33-
if (!userId) {
34-
return res.boom.unauthorized();
54+
if (!dev) return res.boom.notImplemented("Feature not implemented");
55+
56+
if (!isUserPartOfDiscord) {
57+
return res.boom.forbidden(UNAUTHORIZED_TO_CREATE_OOO_REQUEST);
3558
}
3659

3760
try {
38-
const latestOooRequest:OooStatusRequest = await getRequestByKeyValues({ requestedBy: userId, type: REQUEST_TYPE.OOO , state: REQUEST_STATE.PENDING });
61+
const userStatus = await getUserStatus(userId);
62+
const validationResponse = await validateUserStatus(userId, userStatus);
3963

40-
if (latestOooRequest && latestOooRequest.status === REQUEST_STATE.PENDING) {
41-
return res.boom.badRequest(REQUEST_ALREADY_PENDING);
64+
if (validationResponse) {
65+
if (validationResponse.error === USER_STATUS_NOT_FOUND) {
66+
return res.boom.notFound(validationResponse.error);
67+
}
68+
if (validationResponse.error === OOO_STATUS_ALREADY_EXIST) {
69+
return res.boom.forbidden(validationResponse.error);
70+
}
4271
}
4372

44-
const requestResult = await createRequest({ requestedBy: userId, ...requestBody });
73+
const latestOooRequest: OooStatusRequest = await getRequestByKeyValues({
74+
userId,
75+
type: REQUEST_TYPE.OOO,
76+
status: REQUEST_STATE.PENDING,
77+
});
78+
79+
if (latestOooRequest) {
80+
await addLog(logType.PENDING_REQUEST_FOUND,
81+
{ userId, oooRequestId: latestOooRequest.id },
82+
{ message: REQUEST_ALREADY_PENDING }
83+
);
84+
return res.boom.conflict(REQUEST_ALREADY_PENDING);
85+
}
4586

46-
const requestLog = {
47-
type: REQUEST_LOG_TYPE.REQUEST_CREATED,
48-
meta: {
49-
requestId: requestResult.id,
50-
action: LOG_ACTION.CREATE,
51-
userId: userId,
52-
createdAt: Date.now(),
53-
},
54-
body: requestResult,
55-
};
56-
await addLog(requestLog.type, requestLog.meta, requestLog.body);
87+
await createOooRequest(requestBody, username, userId);
5788

5889
return res.status(201).json({
5990
message: REQUEST_CREATED_SUCCESSFULLY,
60-
data: {
61-
id: requestResult.id,
62-
...requestResult,
63-
},
6491
});
6592
} catch (err) {
6693
logger.error(ERROR_WHILE_CREATING_REQUEST, err);
@@ -131,12 +158,12 @@ export const updateOooRequestController = async (req: UpdateRequest, res: Custom
131158
/**
132159
* Acknowledges an Out-of-Office (OOO) request
133160
*
134-
* @param {AcknowledgeOOORequest} req - The request object.
161+
* @param {AcknowledgeOooRequest} req - The request object.
135162
* @param {OooRequestResponse} res - The response object.
136163
* @returns {Promise<OooRequestResponse>} Resolves with success or failure.
137164
*/
138-
export const acknowledgeOOORequestController = async (
139-
req: AcknowledgeOOORequest,
165+
export const acknowledgeOooRequestController = async (
166+
req: AcknowledgeOooRequest,
140167
res: OooRequestResponse,
141168
)
142169
: Promise<OooRequestResponse> => {
@@ -156,7 +183,7 @@ export const acknowledgeOOORequestController = async (
156183

157184
try {
158185

159-
const response = await acknowledgeOOORequest(requestId, requestBody, superUserId);
186+
const response = await acknowledgeOooRequest(requestId, requestBody, superUserId);
160187

161188
if (response.error === REQUEST_DOES_NOT_EXIST) {
162189
return res.boom.notFound(REQUEST_DOES_NOT_EXIST);

controllers/requests.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {
55
} from "../constants/requests";
66
import { getRequests } from "../models/requests";
77
import { getPaginatedLink } from "../utils/helper";
8-
import { acknowledgeOOORequestController, createOooRequestController, updateOooRequestController } from "./oooRequests";
9-
import { AcknowledgeOOORequest, OooRequestCreateRequest, OooRequestResponse } from "../types/oooRequest";
8+
import { acknowledgeOooRequestController, createOooRequestController, updateOooRequestController } from "./oooRequests";
9+
import { AcknowledgeOooRequest, OooRequestCreateRequest, OooRequestResponse } from "../types/oooRequest";
1010
import { CustomResponse } from "../typeDefinitions/global";
1111
import { ExtensionRequestRequest, ExtensionRequestResponse } from "../types/extensionRequests";
1212
import { createTaskExtensionRequest, updateTaskExtensionRequest } from "./extensionRequestsv2";
@@ -125,7 +125,7 @@ export const updateRequestBeforeAcknowledgedController = async (req: Request, re
125125

126126
switch(type){
127127
case REQUEST_TYPE.OOO:
128-
await acknowledgeOOORequestController(req as AcknowledgeOOORequest, res as OooRequestResponse);
128+
await acknowledgeOooRequestController(req as AcknowledgeOooRequest, res as OooRequestResponse);
129129
break;
130130
case REQUEST_TYPE.ONBOARDING:
131131
await updateOnboardingExtensionRequestController(req as UpdateOnboardingExtensionRequest, res as OnboardingExtensionResponse);

middlewares/validators/oooRequests.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import joi from "joi";
22
import { NextFunction } from "express";
33
import { REQUEST_STATE, REQUEST_TYPE } from "../../constants/requests";
4-
import { AcknowledgeOOORequest, OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
4+
import { AcknowledgeOooRequest, OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
55

66
export const createOooStatusRequestValidator = async (
77
req: OooRequestCreateRequest,
@@ -26,14 +26,14 @@ export const createOooStatusRequestValidator = async (
2626
"number.min": "until date must be greater than or equal to from date",
2727
})
2828
.required(),
29-
message: joi.string().required().messages({
30-
"any.required": "message is required",
31-
"string.empty": "message cannot be empty",
29+
reason: joi.string().required().messages({
30+
"any.required": "reason is required",
31+
"string.empty": "reason cannot be empty",
3232
}),
33-
state: joi.string().valid(REQUEST_STATE.PENDING).required().messages({
34-
"any.only": "state must be PENDING",
33+
type: joi.string().valid(REQUEST_TYPE.OOO).required().messages({
34+
"string.empty": "type cannot be empty",
35+
"any.required": "type is required",
3536
}),
36-
type: joi.string().valid(REQUEST_TYPE.OOO).required(),
3737
});
3838

3939
await schema.validateAsync(req.body, { abortEarly: false });
@@ -42,13 +42,13 @@ export const createOooStatusRequestValidator = async (
4242
/**
4343
* Middleware to validate the acknowledge Out-Of-Office (OOO) request payload.
4444
*
45-
* @param {AcknowledgeOOORequest} req - The request object containing the body to be validated.
45+
* @param {AcknowledgeOooRequest} req - The request object containing the body to be validated.
4646
* @param {OooRequestResponse} res - The response object used to send error responses if validation fails.
4747
* @param {NextFunction} next - The next middleware function to call if validation succeeds.
4848
* @returns {Promise<void>} Resolves or sends errors.
4949
*/
50-
export const acknowledgeOOORequestsValidator = async (
51-
req: AcknowledgeOOORequest,
50+
export const acknowledgeOooRequestsValidator = async (
51+
req: AcknowledgeOooRequest,
5252
res: OooRequestResponse,
5353
next: NextFunction
5454
): Promise<void> => {

middlewares/validators/requests.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import joi from "joi";
22
import { NextFunction } from "express";
33
import { REQUEST_STATE, REQUEST_TYPE } from "../../constants/requests";
4-
import { AcknowledgeOOORequest, OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
5-
import { acknowledgeOOORequestsValidator, createOooStatusRequestValidator } from "./oooRequests";
4+
import { AcknowledgeOooRequest, OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
5+
import { acknowledgeOooRequestsValidator, createOooStatusRequestValidator } from "./oooRequests";
66
import { createExtensionRequestValidator } from "./extensionRequestsv2";
77
import {createTaskRequestValidator} from "./taskRequests";
88
import { ExtensionRequestRequest, ExtensionRequestResponse } from "../../types/extensionRequests";
@@ -125,21 +125,21 @@ export const getRequestsMiddleware = async (req: OooRequestCreateRequest, res: O
125125
/**
126126
* Validates update requests based on their type.
127127
*
128-
* @param {UpdateOnboardingExtensionRequest | AcknowledgeOOORequest} req - Request object.
128+
* @param {UpdateOnboardingExtensionRequest | AcknowledgeOooRequest} req - Request object.
129129
* @param {CustomResponse} res - Response object.
130130
* @param {NextFunction} next - Next middleware if valid.
131131
* @returns {Promise<void>} Resolves or sends errors.
132132
*/
133133
export const updateRequestValidator = async (
134-
req: UpdateOnboardingExtensionRequest | AcknowledgeOOORequest,
134+
req: UpdateOnboardingExtensionRequest | AcknowledgeOooRequest,
135135
res: CustomResponse,
136136
next: NextFunction
137137
): Promise<void> => {
138138
const type = req.body.type;
139139

140140
switch (type) {
141141
case REQUEST_TYPE.OOO:
142-
await acknowledgeOOORequestsValidator(
142+
await acknowledgeOooRequestsValidator(
143143
req,
144144
res as OooRequestResponse, next);
145145
break;

models/discordactions.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,7 +1019,7 @@ const getMissedProgressUpdatesUsers = async (options = {}) => {
10191019
usersMap.set(taskAssignee, {
10201020
tasksCount: 1,
10211021
latestProgressCount: dateGap + 1,
1022-
isActive: false,
1022+
isOOO: false,
10231023
});
10241024
}
10251025
const updateTasksIdMap = async () => {
@@ -1038,10 +1038,7 @@ const getMissedProgressUpdatesUsers = async (options = {}) => {
10381038
const userIdChunks = chunks(Array.from(usersMap.keys()), FIRESTORE_IN_CLAUSE_SIZE);
10391039
const userStatusSnapshotPromise = userIdChunks.map(
10401040
async (userIdList) =>
1041-
await userStatusModel
1042-
.where("currentStatus.state", "==", userState.ACTIVE)
1043-
.where("userId", "in", userIdList)
1044-
.get()
1041+
await userStatusModel.where("currentStatus.state", "==", userState.OOO).where("userId", "in", userIdList).get()
10451042
);
10461043
const userDetailsPromise = userIdChunks.map(
10471044
async (userIdList) =>
@@ -1055,7 +1052,7 @@ const getMissedProgressUpdatesUsers = async (options = {}) => {
10551052

10561053
userStatusChunks.forEach((userStatusList) =>
10571054
userStatusList.forEach((doc) => {
1058-
usersMap.get(doc.data().userId).isActive = true;
1055+
usersMap.get(doc.data().userId).isOOO = true;
10591056
})
10601057
);
10611058

@@ -1097,7 +1094,7 @@ const getMissedProgressUpdatesUsers = async (options = {}) => {
10971094
const isDiscordMember = !!discordUserData;
10981095
const shouldAddRole =
10991096
userData.latestProgressCount === 0 &&
1100-
userData.isActive &&
1097+
!userData.isOOO &&
11011098
isDiscordMember &&
11021099
discordUserData.isDeveloper &&
11031100
!discordUserData.isMaven &&

0 commit comments

Comments
 (0)