diff --git a/controllers/userStatus.js b/controllers/userStatus.js index 1d17b406e..0eacc92ba 100644 --- a/controllers/userStatus.js +++ b/controllers/userStatus.js @@ -240,6 +240,31 @@ const updateUserStatusController = async (req, res, next) => { } }; +const syncUserStatus = async (req, res, next) => { + try { + await updateAllUserStatus(req, res, next); + const usersData = await getTaskBasedUsersStatus(req, res, next); + + if (!usersData?.data?.users || usersData.data.users.length === 0) { + const errorMessage = "Error: Users data is not in the expected format or no users found"; + logger.error(errorMessage); + return res.boom.badImplementation(errorMessage); + } + + const data = await userStatusModel.batchUpdateUsersStatus(usersData.data.users); + + return res.json({ + message: "Users status updated successfully.", + data, + }); + } catch (error) { + logger.error(error.message); + return res.status(500).json({ + message: "An internal server error occurred", + }); + } +}; + module.exports = { deleteUserStatus, getUserStatus, @@ -250,4 +275,5 @@ module.exports = { getUserStatusControllers, batchUpdateUsersStatus, updateUserStatusController, + syncUserStatus, }; diff --git a/routes/userStatus.js b/routes/userStatus.js index 65f6008f1..951218541 100644 --- a/routes/userStatus.js +++ b/routes/userStatus.js @@ -7,6 +7,7 @@ const { batchUpdateUsersStatus, getUserStatusControllers, updateUserStatusController, + syncUserStatus, } = require("../controllers/userStatus"); const router = express.Router(); const authenticate = require("../middlewares/authenticate"); @@ -24,6 +25,8 @@ const { Services } = require("../constants/bot"); router.get("/", validateGetQueryParams, getUserStatusControllers); router.get("/self", authenticate, getUserStatus); router.get("/:userId", getUserStatus); +router.patch("/sync", authorizeAndAuthenticate([ROLES.SUPERUSER], [Services.CRON_JOB_HANDLER]), syncUserStatus); + router.patch("/self", authenticate, validateUserStatus, updateUserStatusController); router.patch("/update", authorizeAndAuthenticate([ROLES.SUPERUSER], [Services.CRON_JOB_HANDLER]), updateAllUserStatus); router.patch( diff --git a/test/integration/userStatus.test.js b/test/integration/userStatus.test.js index 6c62e811c..88faece34 100644 --- a/test/integration/userStatus.test.js +++ b/test/integration/userStatus.test.js @@ -24,6 +24,9 @@ const { userState } = require("../../constants/userStatus"); const cookieName = config.get("userToken.cookieName"); const userStatusModel = require("../../models/userStatus"); const { convertTimestampToUTCStartOrEndOfDay } = require("../../utils/time"); +const bot = require("../utils/generateBotToken"); +const { CRON_JOB_HANDLER } = require("../../constants/bot"); +const userStatusController = require("../../controllers/userStatus"); chai.use(chaiHttp); @@ -32,6 +35,7 @@ describe("UserStatus", function () { let superUserId; let superUserAuthToken; let userId = ""; + let cronjobJwtToken; beforeEach(async function () { userId = await addUser(); @@ -39,6 +43,7 @@ describe("UserStatus", function () { superUserId = await addUser(superUser); superUserAuthToken = authService.generateAuthToken({ userId: superUserId }); await updateUserStatus(userId, userStatusDataForNewUser); + cronjobJwtToken = bot.generateCronJobToken({ name: CRON_JOB_HANDLER }); }); afterEach(async function () { @@ -275,6 +280,65 @@ describe("UserStatus", function () { }); }); + describe("PATCH /users/status/sync", function () { + afterEach(function () { + sinon.restore(); + }); + + it("should return all user statuses", async function () { + const fakeResponse = { + message: "All User Status updated successfully.", + data: { + usersCount: 5, + oooUsersAltered: 0, + oooUsersUnaltered: 0, + nonOooUsersAltered: 3, + nonOooUsersUnaltered: 0, + }, + }; + + const patchStub = sinon.stub().returns({ status: 200, body: fakeResponse }); + sinon.stub(chai, "request").returns({ patch: patchStub }); + + const res = await chai.request(app).patch(`/users/status/sync`).set("Authorization", `Bearer ${cronjobJwtToken}`); + + expect(res).to.have.status(200); + expect(res.body.message).to.equal(fakeResponse.message); + expect(res.body.data).to.deep.equal(fakeResponse.data); + }); + + it("should return 500 error with appropriate message when no users found", async function () { + const updateAllUserStatusStub = sinon.stub().resolves(); + const getTaskBasedUsersStatusStub = sinon.stub().resolves({ data: { users: [] } }); + sinon.replace(userStatusController, "updateAllUserStatus", updateAllUserStatusStub); + sinon.replace(userStatusController, "getTaskBasedUsersStatus", getTaskBasedUsersStatusStub); + + const patchStub = sinon.stub().returns({ + status: 500, + body: { message: "Error: Users data is not in the expected format or no users found" }, + }); + sinon.stub(chai, "request").returns({ patch: patchStub }); + + const res = await chai.request(app).patch("/users/status/sync").set("Authorization", `Bearer ${cronjobJwtToken}`); + + expect(res).to.have.status(500); + expect(res.body.message).to.equal("Error: Users data is not in the expected format or no users found"); + }); + + it("should return 500 error with appropriate message", async function () { + const updateAllUserStatusStub = sinon.stub().rejects(new Error("Failed to update user statuses")); + sinon.replace(userStatusController, "updateAllUserStatus", updateAllUserStatusStub); + + const patchStub = sinon.stub().returns({ status: 500, body: { message: "An internal server error occurred" } }); + sinon.stub(chai, "request").returns({ patch: patchStub }); + + const res = await chai.request(app).patch("/users/status/sync").set("Authorization", `Bearer ${cronjobJwtToken}`); + + expect(res).to.have.status(500); + expect(res.body.message).to.equal("An internal server error occurred"); + }); + }); + describe("PATCH /users/status/:userid", function () { let testUserId; let testUserJwt;