Skip to content

Commit b1c2702

Browse files
committed
feat: acknowledge OOO request
1 parent a7812ee commit b1c2702

File tree

6 files changed

+187
-26
lines changed

6 files changed

+187
-26
lines changed

constants/requests.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const ERROR_WHILE_UPDATING_REQUEST = "Error while updating request";
4141

4242
export const REQUEST_DOES_NOT_EXIST = "Request does not exist";
4343
export const REQUEST_ALREADY_PENDING = "Request already exists please wait for approval or rejection";
44+
export const UNAUTHORIZED_TO_ACKNOWLEDGE_OOO_REQUEST = "Only super users are allowed to acknowledge OOO requests";
4445

4546
export const TASK_REQUEST_MESSAGES = {
4647
NOT_AUTHORIZED_TO_CREATE_REQUEST: "Not authorized to create the request",

controllers/oooRequests.ts

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,21 @@ import {
99
ERROR_WHILE_UPDATING_REQUEST,
1010
REQUEST_APPROVED_SUCCESSFULLY,
1111
REQUEST_REJECTED_SUCCESSFULLY,
12+
REQUEST_DOES_NOT_EXIST,
13+
UNAUTHORIZED_TO_ACKNOWLEDGE_OOO_REQUEST,
14+
REQUEST_ALREADY_APPROVED,
15+
REQUEST_ALREADY_REJECTED,
1216
} from "../constants/requests";
1317
import { statusState } from "../constants/userStatus";
1418
import { addLog } from "../models/logs";
1519
import { createRequest, getRequestByKeyValues, getRequests, updateRequest } from "../models/requests";
1620
import { createUserFutureStatus } from "../models/userFutureStatus";
1721
import { addFutureStatus } from "../models/userStatus";
1822
import { CustomResponse } from "../typeDefinitions/global";
19-
import { OooRequestCreateRequest, OooStatusRequest } from "../types/oooRequest";
23+
import { AcknowledgeOOORequest, AcknowledgeOOORequestBody, OooRequestCreateRequest, OooRequestResponse, OooStatusRequest } from "../types/oooRequest";
2024
import { UpdateRequest } from "../types/requests";
25+
import firestore from "../utils/firestore";
26+
const requestModel = firestore.collection("requests");
2127

2228
export const createOooRequestController = async (req: OooRequestCreateRequest, res: CustomResponse) => {
2329
const requestBody = req.body;
@@ -30,7 +36,7 @@ export const createOooRequestController = async (req: OooRequestCreateRequest, r
3036
try {
3137
const latestOooRequest:OooStatusRequest = await getRequestByKeyValues({ requestedBy: userId, type: REQUEST_TYPE.OOO , state: REQUEST_STATE.PENDING });
3238

33-
if (latestOooRequest && latestOooRequest.state === REQUEST_STATE.PENDING) {
39+
if (latestOooRequest && latestOooRequest.status === REQUEST_STATE.PENDING) {
3440
return res.boom.badRequest(REQUEST_ALREADY_PENDING);
3541
}
3642

@@ -120,3 +126,98 @@ export const updateOooRequestController = async (req: UpdateRequest, res: Custom
120126
return res.boom.badImplementation(ERROR_WHILE_UPDATING_REQUEST);
121127
}
122128
};
129+
130+
export const acknowledgeOOORequestController = async (
131+
req: AcknowledgeOOORequest,
132+
res: OooRequestResponse)
133+
: Promise<OooRequestResponse> => {
134+
135+
const dev = req.query.dev === "true";
136+
137+
if(!dev) return res.boom.notImplemented("Feature not implemented");
138+
139+
const requestBody = req.body;
140+
const userId = req?.userData?.id;
141+
const requestId = req.params.id;
142+
const isSuperuser = req?.userData?.roles?.super_user === true;
143+
144+
if (isSuperuser === false) {
145+
return res.boom.unauthorized(UNAUTHORIZED_TO_ACKNOWLEDGE_OOO_REQUEST);
146+
}
147+
148+
try {
149+
const request = await requestModel.doc(requestId).get();
150+
151+
if (!request.exists) {
152+
return res.boom.notFound(REQUEST_DOES_NOT_EXIST);
153+
}
154+
155+
const requestData = request.data();
156+
157+
if (requestData.status === REQUEST_STATE.APPROVED) {
158+
return res.boom.badRequest(REQUEST_ALREADY_APPROVED);
159+
}
160+
else if (requestData.status === REQUEST_STATE.REJECTED) {
161+
return res.boom.badRequest(REQUEST_ALREADY_REJECTED);
162+
}
163+
164+
if (requestData.type === REQUEST_TYPE.OOO) {
165+
166+
requestBody.type = REQUEST_TYPE.OOO;
167+
168+
const requestResult = await updateRequest(requestId, requestBody, userId, REQUEST_TYPE.OOO);
169+
if ("error" in requestResult) {
170+
return res.boom.badRequest(requestResult.error);
171+
}
172+
const [logType, returnMessage] =
173+
requestResult.status === REQUEST_STATE.APPROVED
174+
? [REQUEST_LOG_TYPE.REQUEST_APPROVED, REQUEST_APPROVED_SUCCESSFULLY]
175+
: [REQUEST_LOG_TYPE.REQUEST_REJECTED, REQUEST_REJECTED_SUCCESSFULLY];
176+
177+
const requestLog = {
178+
type: logType,
179+
meta: {
180+
requestId: requestId,
181+
action: LOG_ACTION.UPDATE,
182+
userId: userId,
183+
createdAt: Date.now(),
184+
},
185+
body: requestResult,
186+
};
187+
await addLog(requestLog.type, requestLog.meta, requestLog.body);
188+
if (requestResult.status === REQUEST_STATE.APPROVED) {
189+
const requestData = await getRequests({ id: requestId });
190+
191+
if (requestData) {
192+
const { from, until, requestedBy, comment } = requestData as any;
193+
const userFutureStatusData = {
194+
requestId,
195+
status: REQUEST_TYPE.OOO,
196+
state: statusState.UPCOMING,
197+
from,
198+
endsOn: until,
199+
userId: requestedBy,
200+
message: comment,
201+
};
202+
await createUserFutureStatus(userFutureStatusData);
203+
await addFutureStatus(userFutureStatusData);
204+
}
205+
206+
return res.status(201).json({
207+
message: REQUEST_APPROVED_SUCCESSFULLY,
208+
});
209+
}
210+
return res.status(201).json({
211+
message: REQUEST_REJECTED_SUCCESSFULLY,
212+
});
213+
214+
} else {
215+
return res.boom.notImplemented("Feature not implemented");
216+
}
217+
}
218+
catch(error){
219+
logger.error(ERROR_WHILE_UPDATING_REQUEST, error);
220+
return res.boom.badImplementation(ERROR_WHILE_UPDATING_REQUEST);
221+
}
222+
223+
}

controllers/requests.ts

Lines changed: 8 additions & 2 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 { createOooRequestController, updateOooRequestController } from "./oooRequests";
9-
import { 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";
@@ -123,6 +123,12 @@ export const getRequestsController = async (req: any, res: any) => {
123123
*/
124124
export const updateRequestBeforeAcknowledgedController = async (req: Request, res: CustomResponse) => {
125125
const type = req.body.type;
126+
127+
if (type === undefined) {
128+
await acknowledgeOOORequestController(req as AcknowledgeOOORequest, res as OooRequestResponse);
129+
return;
130+
}
131+
126132
switch(type){
127133
case REQUEST_TYPE.ONBOARDING:
128134
await updateOnboardingExtensionRequestController(req as UpdateOnboardingExtensionRequest, res as OnboardingExtensionResponse);

middlewares/validators/oooRequests.ts

Lines changed: 33 additions & 1 deletion
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 { OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
4+
import { AcknowledgeOOORequest, OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
55

66
export const createOooStatusRequestValidator = async (
77
req: OooRequestCreateRequest,
@@ -38,3 +38,35 @@ export const createOooStatusRequestValidator = async (
3838

3939
await schema.validateAsync(req.body, { abortEarly: false });
4040
};
41+
42+
export const acknowledgeOOORequestsValidator = async (
43+
req: AcknowledgeOOORequest,
44+
res: OooRequestResponse,
45+
next: NextFunction
46+
) => {
47+
const schema = joi
48+
.object()
49+
.strict()
50+
.keys({
51+
comment: joi.string().optional()
52+
.messages({
53+
"string.empty": "comment cannot be empty",
54+
}),
55+
status: joi
56+
.string()
57+
.valid(REQUEST_STATE.APPROVED, REQUEST_STATE.REJECTED)
58+
.required()
59+
.messages({
60+
"any.only": "status must be APPROVED or REJECTED",
61+
})
62+
});
63+
64+
try {
65+
await schema.validateAsync(req.body, { abortEarly: false });
66+
next();
67+
} catch (error) {
68+
const errorMessages = error.details.map((detail:any) => detail.message);
69+
logger.error(`Error while validating request payload : ${errorMessages}`);
70+
res.boom.badRequest(errorMessages);
71+
}
72+
};

middlewares/validators/requests.ts

Lines changed: 10 additions & 4 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 { OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
5-
import { 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";
@@ -131,11 +131,17 @@ export const getRequestsMiddleware = async (req: OooRequestCreateRequest, res: O
131131
* @returns {Promise<void>} Resolves or sends errors.
132132
*/
133133
export const updateRequestValidator = async (
134-
req: UpdateOnboardingExtensionRequest,
134+
req: UpdateOnboardingExtensionRequest | AcknowledgeOOORequest,
135135
res: CustomResponse,
136136
next: NextFunction
137137
): Promise<void> => {
138138
const type = req.body.type;
139+
140+
if (type === undefined) {
141+
await acknowledgeOOORequestsValidator(req, res as OooRequestResponse, next);
142+
return;
143+
}
144+
139145
switch (type) {
140146
case REQUEST_TYPE.ONBOARDING:
141147
await updateOnboardingExtensionRequestValidator(
@@ -145,4 +151,4 @@ export const updateRequestValidator = async (
145151
default:
146152
return res.boom.badRequest("Invalid type");
147153
}
148-
};
154+
};

types/oooRequest.d.ts

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,23 @@ export type OooStatusRequest = {
99
id: string;
1010
type: REQUEST_TYPE.OOO;
1111
from: number;
12-
until?: number;
13-
message?: string;
14-
status: userState;
15-
state?: REQUEST_STATE;
16-
lastModifiedBy?: string;
17-
requestedBy?: string;
18-
createdAt?: Timestamp;
19-
updatedAt?: Timestamp;
20-
reason?: string;
12+
until: number;
13+
reason: string;
14+
userState: userState;
15+
status: REQUEST_STATE;
16+
lastModifiedBy?: string | null;
17+
requestedBy: string;
18+
userId: string;
19+
createdAt: Timestamp;
20+
updatedAt: Timestamp;
21+
comment?: string | null;
2122
};
22-
export type OooStatusRequestBody = {
23-
type: REQUEST_TYPE.OOO;
24-
requestedBy?: string;
23+
24+
export type CreateOooRequestBody = {
2525
from: number;
2626
until: number;
27-
message: string;
28-
state: REQUEST_STATE.PENDING;
29-
createdAt?: Timestamp;
30-
updatedAt?: Timestamp;
27+
type: REQUEST_TYPE.OOO;
28+
reason: string;
3129
};
3230

3331
export type OooRequestUpdateBody = {
@@ -40,6 +38,23 @@ export type OooRequestUpdateBody = {
4038
};
4139

4240
export type OooRequestResponse = Response & { boom: Boom };
43-
export type OooRequestCreateRequest = Request & { OooStatusRequestBody , userData: userData , query: RequestQuery };
41+
export type OooRequestCreateRequest = Request & { OooStatusRequestBody; userData: userData; query: RequestQuery };
4442

4543
export type OooRequestUpdateRequest = Request & { oooRequestUpdateBody , userData: userData , query: RequestQuery , params: RequestParams };
44+
45+
46+
export type AcknowledgeOOORequestQuery = RequestQuery & {
47+
dev?: string
48+
};
49+
50+
export type AcknowledgeOOORequestBody = {
51+
comment?: string;
52+
status: REQUEST_STATE.APPROVED | REQUEST_STATE.REJECTED;
53+
}
54+
55+
export type AcknowledgeOOORequest = Request & {
56+
body: AcknowledgeOOORequestBody;
57+
userData: userData;
58+
query: AcknowledgeOOORequestQuery;
59+
params: RequestParams;
60+
}

0 commit comments

Comments
 (0)