From 7fb0e0e5dc6616310a537906604b60022ce1482f Mon Sep 17 00:00:00 2001 From: Sunny Sahsi Date: Thu, 11 Apr 2024 03:16:12 +0530 Subject: [PATCH] Add OOO request approved data to user future status (#2001) * added all changes * create new status if user not have any status * refactor: result schema * test: add test for user future status model functions * test: add test for add futire staus to user status model. * refactor addFutureStatus user status model function --------- Co-authored-by: Amit Prakash <34869115+iamitprakash@users.noreply.github.com> --- constants/userStatus.ts | 10 +++- controllers/requests.ts | 22 ++++++++ models/requests.ts | 8 +-- models/userFutureStatus.ts | 56 +++++++++++++++++++ models/userStatus.js | 32 +++++++++++ .../userFutureStatus/userFutureStatusData.ts | 12 ++++ test/unit/models/requests.test.ts | 4 +- test/unit/models/userFutureStatus.test.ts | 34 +++++++++++ test/unit/models/userStatus.js | 9 ++- types/oooRequest.d.ts | 6 +- types/userFutureStatus.d.ts | 13 +++++ 11 files changed, 191 insertions(+), 15 deletions(-) create mode 100644 models/userFutureStatus.ts create mode 100644 test/fixtures/userFutureStatus/userFutureStatusData.ts create mode 100644 test/unit/models/userFutureStatus.test.ts create mode 100644 types/userFutureStatus.d.ts diff --git a/constants/userStatus.ts b/constants/userStatus.ts index 1c37cf4f2..f37e95734 100644 --- a/constants/userStatus.ts +++ b/constants/userStatus.ts @@ -1,10 +1,14 @@ -const userState = { +export const userState = { ACTIVE: "ACTIVE", IDLE: "IDLE", OOO: "OOO", ONBOARDING: "ONBOARDING", }; -const CANCEL_OOO = "cancelOoo"; +export const statusState = { + UPCOMING: "UPCOMING", + APPLIED: "APPLIED", + NOT_APPLIED: "NOT_APPLIED", +}; -module.exports = { userState, CANCEL_OOO }; +export const CANCEL_OOO = "cancelOoo"; diff --git a/controllers/requests.ts b/controllers/requests.ts index a463315f8..a5d0708c4 100644 --- a/controllers/requests.ts +++ b/controllers/requests.ts @@ -9,7 +9,11 @@ import { REQUEST_STATE, LOG_ACTION, REQUEST_LOG_TYPE, + REQUEST_TYPE, } from "../constants/requests"; +import { statusState } from "../constants/userStatus"; +import {addFutureStatus} from "../models/userStatus"; +import { createUserFutureStatus } from "../models/userFutureStatus"; import { createRequest, getRequests, updateRequest } from "../models/requests"; import { addLog } from "../models/logs"; import { getPaginatedLink } from "../utils/helper"; @@ -94,6 +98,24 @@ export const updateRequestController = async (req: any, res: any) => { body: requestResult, }; await addLog(requestLog.type, requestLog.meta, requestLog.body); + if (requestResult.state === REQUEST_STATE.APPROVED) { + const requestData = await getRequests({ id: requestId }); + + if (requestData) { + const { from, until, requestedBy, message } = requestData as any; + const userFutureStatusData = { + requestId, + status: REQUEST_TYPE.OOO, + state: statusState.UPCOMING, + from, + endsOn: until, + userId: requestedBy, + message, + }; + await createUserFutureStatus(userFutureStatusData); + await addFutureStatus(userFutureStatusData); + } + } return res.status(201).json({ message: returnMessage, data: { diff --git a/models/requests.ts b/models/requests.ts index 939e9cfc2..c34f360d0 100644 --- a/models/requests.ts +++ b/models/requests.ts @@ -91,12 +91,8 @@ export const getRequests = async (query: any) => { return null; } return { - allRequests: [ - { - id: requestDoc.id, - ...requestDoc.data(), - }, - ], + id: requestDoc.id, + ...requestDoc.data(), }; } diff --git a/models/userFutureStatus.ts b/models/userFutureStatus.ts new file mode 100644 index 000000000..b1e003ba4 --- /dev/null +++ b/models/userFutureStatus.ts @@ -0,0 +1,56 @@ +import firestore from "../utils/firestore"; +const userFutureStatusModel = firestore.collection("userFutureStatus"); +import { UserFutureStatusType } from "../types/userFutureStatus"; +import * as admin from "firebase-admin"; + +/** + * Function to create user future status + * @param body: UserFutureStatusType + * @returns UserFutureStatusType + */ +export const createUserFutureStatus = async (body: UserFutureStatusType) => { + try { + const statusBody: UserFutureStatusType = { + createdAt: Date.now(), + ...body, + }; + const resultDoc = await userFutureStatusModel.add(statusBody); + return { + id: resultDoc.id, + ...body, + }; + } catch (error) { + logger.error("Error while creating user future status", error); + throw error; + } +}; + +/** + * Function to get user future status + * @param: id: string, status: string, state: string + * @returns Array of user future status + **/ +export const getUserFutureStatus = async (userId: string, status: string, state: string) => { + try { + let resultArray = []; + let query: admin.firestore.Query = userFutureStatusModel; + + if (userId) { + query = query.where("userId", "==", userId); + } + if (status) { + query = query.where("status", "==", status); + } + if (state) { + query = query.where("state", "==", state); + } + const resultDoc = await query.get(); + resultDoc.forEach((doc) => { + resultArray.push({ id: doc.id, ...doc.data() }); + }); + return resultArray; + } catch (error) { + logger.error("Error while fetching user future status", error); + throw error; + } +}; \ No newline at end of file diff --git a/models/userStatus.js b/models/userStatus.js index 75599971e..4f7288d7c 100644 --- a/models/userStatus.js +++ b/models/userStatus.js @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ const { Forbidden, NotFound } = require("http-errors"); const admin = require("firebase-admin"); const firestore = require("../utils/firestore"); @@ -673,6 +674,36 @@ const cancelOooStatus = async (userId) => { } }; +const addFutureStatus = async (futureStatusData) => { + try { + const userStatusDocs = await userStatusModel.where("userId", "==", futureStatusData.userId).limit(1).get(); + const [userStatusDoc] = userStatusDocs.docs; + let docId; + let userStatusData; + + if (userStatusDoc) { + docId = userStatusDoc.id; + userStatusData = userStatusDoc.data(); + } else { + const newUserStatusRef = userStatusModel.doc(); + await newUserStatusRef.set({ userId: futureStatusData.userId }); + docId = newUserStatusRef.id; + userStatusData = { userId: futureStatusData.userId }; + } + + delete futureStatusData.userId; + const newStatusData = { + ...userStatusData, + futureStatus: futureStatusData, + }; + await userStatusModel.doc(docId).update(newStatusData); + return { id: docId, userStatusExists: true, data: newStatusData }; + } catch (error) { + logger.error(`error in updating User Status Document ${error}`); + throw error; + } +}; + module.exports = { deleteUserStatus, getUserStatus, @@ -686,4 +717,5 @@ module.exports = { getTaskBasedUsersStatus, cancelOooStatus, getGroupRole, + addFutureStatus, }; diff --git a/test/fixtures/userFutureStatus/userFutureStatusData.ts b/test/fixtures/userFutureStatus/userFutureStatusData.ts new file mode 100644 index 000000000..50408284a --- /dev/null +++ b/test/fixtures/userFutureStatus/userFutureStatusData.ts @@ -0,0 +1,12 @@ +import { REQUEST_TYPE } from "../../../constants/requests"; +import { statusState } from "../../../constants/userStatus"; + +export const userFutureStatusData = { + requestId: "randomId", + status: REQUEST_TYPE.OOO, + state: statusState.UPCOMING, + from: 1712277700000, + endsOn: 1712277700000, + userId: "randomUserId", + message: "I am out of office", +}; diff --git a/test/unit/models/requests.test.ts b/test/unit/models/requests.test.ts index ed26bcafd..eab4ed9f0 100644 --- a/test/unit/models/requests.test.ts +++ b/test/unit/models/requests.test.ts @@ -101,9 +101,7 @@ describe("models/oooRequests", () => { const oooRequest = await createRequest(createOooRequests2); const query = { id: oooRequest.id, dev: "true" }; const oooRequestData: any = await getRequests(query); - expect(oooRequestData).to.have.property("allRequests"); - expect(oooRequestData.allRequests[0].id).to.be.equal(oooRequest.id); - expect(oooRequestData.allRequests).to.have.lengthOf(1); + expect(oooRequestData.id).to.be.equal(oooRequest.id); }); it("Should return null if the request with the specified ID does not exist", async () => { diff --git a/test/unit/models/userFutureStatus.test.ts b/test/unit/models/userFutureStatus.test.ts new file mode 100644 index 000000000..42a089b20 --- /dev/null +++ b/test/unit/models/userFutureStatus.test.ts @@ -0,0 +1,34 @@ +import { createUserFutureStatus, getUserFutureStatus } from "../../../models/userFutureStatus"; +import { expect } from "chai"; +import cleanDb from "../../utils/cleanDb"; +import { UserFutureStatusType } from "../../../types/userFutureStatus"; +import { userFutureStatusData } from "../../fixtures/userFutureStatus/userFutureStatusData"; + +describe("models/userFutureStatus", () => { + afterEach(async () => { + await cleanDb(); + }); + + describe("createUserFutureStatus ", () => { + it("should successfully create a new user future status", async () => { + const userFutureStatus = await createUserFutureStatus(userFutureStatusData as UserFutureStatusType); + expect(userFutureStatus).to.not.be.null; + expect(userFutureStatus).to.have.property("id"); + expect(userFutureStatus).to.have.property("userId"); + }); + }); + + describe("getUserFutureStatus", () => { + it("should successfully get user future status", async () => { + await createUserFutureStatus(userFutureStatusData as UserFutureStatusType); + const userFutureStatus = await getUserFutureStatus( + userFutureStatusData.userId, + userFutureStatusData.status, + userFutureStatusData.state + ); + expect(userFutureStatus).to.not.be.null; + expect(userFutureStatus).to.be.an("array"); + expect(userFutureStatus).to.have.length(1); + }); + }); +}); diff --git a/test/unit/models/userStatus.js b/test/unit/models/userStatus.js index 57fdb1953..d537ce829 100644 --- a/test/unit/models/userStatus.js +++ b/test/unit/models/userStatus.js @@ -1,3 +1,4 @@ +import { userFutureStatusData } from "../../fixtures/userFutureStatus/userFutureStatusData"; const chai = require("chai"); const sinon = require("sinon"); const { NotFound, Forbidden } = require("http-errors"); @@ -5,7 +6,7 @@ const { expect } = chai; const firestore = require("../../../utils/firestore"); const userStatusModel = firestore.collection("usersStatus"); const tasksModel = firestore.collection("tasks"); -const { cancelOooStatus } = require("../../../models/userStatus"); +const { cancelOooStatus, addFutureStatus } = require("../../../models/userStatus"); const cleanDb = require("../../utils/cleanDb"); const addUser = require("../../utils/addUser"); const { userState } = require("../../../constants/userStatus"); @@ -79,4 +80,10 @@ describe("tasks", function () { expect(err.message).to.be.equal("Task not found"); }); }); + + it("Should add future status to the User", async function () { + const response = await addFutureStatus(userFutureStatusData); + expect(response.userStatusExists).to.equal(true); + expect(response.data.futureStatus.state).to.equal("UPCOMING"); + }); }); diff --git a/types/oooRequest.d.ts b/types/oooRequest.d.ts index 74cc84c09..46cf45c27 100644 --- a/types/oooRequest.d.ts +++ b/types/oooRequest.d.ts @@ -1,9 +1,10 @@ import { Request, Response } from "express"; -import { REQUEST_STATE, REQUEST_TYPE } from "../constants/request"; +import { REQUEST_STATE, REQUEST_TYPE } from "../constants/requests"; import { userState } from "../constants/userStatus"; import { Boom } from "express-boom"; export type OooStatusRequest = { + id: string; type: REQUEST_TYPE.OOO; from: number; until?: number; @@ -11,6 +12,7 @@ export type OooStatusRequest = { status: userState; state?: REQUEST_STATE; lastModifiedBy?: string; + requestedBy?: string; createdAt?: Timestamp; updatedAt?: Timestamp; reason?: string; @@ -40,7 +42,7 @@ export type userData= { }; export type RequestQuery = { - dev: string; + dev?: string; type?: string; requestedBy?: string; state?: REQUEST_STATE.APPROVED | REQUEST_STATE.PENDING | REQUEST_STATE.REJECTED; diff --git a/types/userFutureStatus.d.ts b/types/userFutureStatus.d.ts new file mode 100644 index 000000000..271a7ddde --- /dev/null +++ b/types/userFutureStatus.d.ts @@ -0,0 +1,13 @@ +import { userState, statusState } from "../constants/userStatus"; + +export type UserFutureStatusType = { + id?: string; + requestId?: string; + status: userState.OOO | userState.IDLE | userState.ACTIVE; + state: statusState.UPCOMING | statusState.APPLIED | statusState.NOT_APPLIED; + from: number; + endsOn?: number; + userId: string; + message?: string; + createdAt?: number; +}; \ No newline at end of file