Skip to content

Commit f3b50a9

Browse files
authored
Merge pull request #1307 from Real-Dev-Squad/feat/include-active-user-batch-script
Update Batch Script to include active users
2 parents 3ca9d7c + dedc3c0 commit f3b50a9

File tree

8 files changed

+158
-162
lines changed

8 files changed

+158
-162
lines changed

controllers/userStatus.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,16 @@ const updateAllUserStatus = async (req, res) => {
146146
};
147147

148148
/**
149-
* Retrieve idle users based on task status where the status is not assigned and in progress
149+
* Retrieve users status based on task status
150150
* @param req {Object} - Express request object
151151
* @param res {Object} - Express response object
152152
*/
153153

154-
const getIdleUsers = async (req, res) => {
154+
const getTaskBasedUsersStatus = async (req, res) => {
155155
try {
156-
const data = await userStatusModel.getIdleUsers();
156+
const data = await userStatusModel.getTaskBasedUsersStatus();
157157
return res.json({
158-
message: "All idle users found successfully.",
158+
message: "All users based on tasks found successfully.",
159159
data,
160160
});
161161
} catch (error) {
@@ -167,8 +167,8 @@ const getIdleUsers = async (req, res) => {
167167
};
168168

169169
const getUserStatusControllers = async (req, res, next) => {
170-
if (Object.keys(req.query).includes("taskStatus")) {
171-
await getIdleUsers(req, res, next);
170+
if (Object.keys(req.query).includes("aggregate")) {
171+
await getTaskBasedUsersStatus(req, res, next);
172172
} else {
173173
await getAllUserStatus(req, res, next);
174174
}
@@ -180,9 +180,9 @@ const getUserStatusControllers = async (req, res, next) => {
180180
* @param req {Object} - Express request object
181181
* @param res {Object} - Express response object
182182
*/
183-
const massUpdateIdleUsers = async (req, res) => {
183+
const batchUpdateUsersStatus = async (req, res) => {
184184
try {
185-
const data = await userStatusModel.massUpdateIdleUsers(req.body.users);
185+
const data = await userStatusModel.batchUpdateUsersStatus(req.body.users);
186186
return res.json({
187187
message: "users status updated successfully.",
188188
data,
@@ -242,8 +242,8 @@ module.exports = {
242242
getAllUserStatus,
243243
updateUserStatus,
244244
updateAllUserStatus,
245-
getIdleUsers,
245+
getTaskBasedUsersStatus,
246246
getUserStatusControllers,
247-
massUpdateIdleUsers,
247+
batchUpdateUsersStatus,
248248
updateUserStatusController,
249249
};

middlewares/validators/userStatus.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,15 @@ const validateMassUpdate = async (req, res, next) => {
9797
const schema = Joi.object()
9898
.keys({
9999
users: Joi.array()
100-
.items(Joi.string().trim())
100+
.items(
101+
Joi.object({
102+
userId: Joi.string().trim().required(),
103+
state: Joi.string().valid(userState.IDLE, userState.ACTIVE).required(),
104+
})
105+
)
101106
.min(1)
102107
.required()
103-
.error(new Error(`Invalid state value passed for users.`)),
108+
.error(new Error(`Invalid object passed in users.`)),
104109
})
105110
.messages({
106111
"object.unknown": "Invalid key in Request payload.",
@@ -118,10 +123,7 @@ const validateMassUpdate = async (req, res, next) => {
118123
const validateGetQueryParams = async (req, res, next) => {
119124
const schema = Joi.object()
120125
.keys({
121-
taskStatus: Joi.string()
122-
.trim()
123-
.valid(userState.IDLE)
124-
.error(new Error(`Invalid state value passed for taskStatus.`)),
126+
aggregate: Joi.boolean().valid(true).error(new Error(`Invalid boolean value passed for aggregate.`)),
125127
state: Joi.string()
126128
.trim()
127129
.valid(userState.IDLE, userState.ACTIVE, userState.OOO, userState.ONBOARDING)

models/userStatus.js

Lines changed: 93 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -327,101 +327,111 @@ const updateStatusOnTaskCompletion = async (userId) => {
327327
}
328328
};
329329

330-
const massUpdateIdleUsers = async (users) => {
330+
const batchUpdateUsersStatus = async (users) => {
331331
const currentTimeStamp = new Date().getTime();
332332
const batch = firestore.batch();
333-
let usersWithStatusUnchanged = 0;
334-
335-
await Promise.all(
336-
users.map(async (userId) => {
337-
let latestStatusData;
338-
try {
339-
latestStatusData = await getUserStatus(userId);
340-
} catch (error) {
341-
usersWithStatusUnchanged++;
342-
return batch;
343-
}
344-
const { id, userStatusExists, data } = latestStatusData;
333+
const summary = {
334+
totalUsers: users.length,
335+
totalUnprocessedUsers: 0,
336+
totalOnboardingUsersAltered: 0,
337+
totalOnboardingUsersUnAltered: 0,
338+
totalActiveUsersAltered: 0,
339+
totalActiveUsersUnAltered: 0,
340+
totalIdleUsersAltered: 0,
341+
totalIdleUsersUnAltered: 0,
342+
};
345343

346-
if (!userStatusExists || !data?.currentStatus) {
347-
const newUserStatusRef = userStatusModel.doc();
348-
const newUserStatusData = {
349-
userId,
350-
currentStatus: {
351-
state: userState.IDLE,
352-
message: "",
353-
from: currentTimeStamp,
354-
until: "",
355-
updatedAt: currentTimeStamp,
356-
},
357-
};
358-
batch.set(newUserStatusRef, newUserStatusData);
359-
} else {
360-
const {
361-
currentStatus: { state, until },
362-
} = data;
344+
for (const { userId, state } of users) {
345+
let latestStatusData;
346+
try {
347+
latestStatusData = await getUserStatus(userId);
348+
} catch (error) {
349+
summary.totalUnprocessedUsers++;
350+
continue;
351+
}
352+
const { id, userStatusExists, data } = latestStatusData;
353+
const statusToUpdate = {
354+
state,
355+
message: "",
356+
from: currentTimeStamp,
357+
until: "",
358+
updatedAt: currentTimeStamp,
359+
};
363360

364-
if (state === userState.OOO || state === userState.ACTIVE) {
365-
const docRef = userStatusModel.doc(id);
366-
const updatedStatusData =
367-
state === userState.OOO
368-
? {
369-
futureStatus: {
370-
state: userState.IDLE,
371-
message: "",
372-
from: until,
373-
until: "",
374-
updatedAt: currentTimeStamp,
375-
},
376-
}
377-
: {
378-
currentStatus: {
379-
state: userState.IDLE,
380-
message: "",
381-
from: currentTimeStamp,
382-
until: "",
383-
updatedAt: currentTimeStamp,
384-
},
385-
};
361+
if (!userStatusExists || !data?.currentStatus) {
362+
const newUserStatusRef = userStatusModel.doc();
363+
const newUserStatusData = {
364+
userId,
365+
currentStatus: statusToUpdate,
366+
};
367+
state === userState.ACTIVE ? summary.totalActiveUsersAltered++ : summary.totalIdleUsersAltered++;
368+
batch.set(newUserStatusRef, newUserStatusData);
369+
} else {
370+
const {
371+
currentStatus: { state: currentState, until },
372+
} = data;
373+
if (currentState === state) {
374+
currentState === userState.ACTIVE ? summary.totalActiveUsersUnAltered++ : summary.totalIdleUsersUnAltered++;
375+
continue;
376+
}
377+
if (currentState === userState.ONBOARDING) {
378+
const docRef = userStatusModel.doc(id);
379+
if (state === userState.ACTIVE) {
380+
const updatedStatusData = {
381+
currentStatus: statusToUpdate,
382+
};
383+
summary.totalOnboardingUsersAltered++;
386384
batch.update(docRef, updatedStatusData);
387385
} else {
388-
usersWithStatusUnchanged++;
386+
summary.totalOnboardingUsersUnAltered++;
389387
}
388+
} else {
389+
state === userState.ACTIVE ? summary.totalActiveUsersAltered++ : summary.totalIdleUsersAltered++;
390+
const docRef = userStatusModel.doc(id);
391+
const updatedStatusData =
392+
currentState === userState.OOO
393+
? {
394+
futureStatus: {
395+
...statusToUpdate,
396+
from: until,
397+
},
398+
}
399+
: {
400+
currentStatus: statusToUpdate,
401+
};
402+
batch.update(docRef, updatedStatusData);
390403
}
391-
return batch;
392-
})
393-
);
404+
}
405+
}
394406

395407
try {
396408
await batch.commit();
397-
return {
398-
totalUsers: users.length,
399-
usersWithStatusUpdated: users.length - usersWithStatusUnchanged,
400-
usersOnboardingOrAlreadyIdle: usersWithStatusUnchanged,
401-
};
409+
return summary;
402410
} catch (error) {
403411
throw new Error("Batch operation failed");
404412
}
405413
};
406414

407-
const getIdleUsers = async () => {
408-
const idleUsers = [];
409-
const usersNotProcessed = [];
415+
const getTaskBasedUsersStatus = async () => {
416+
const users = [];
417+
let totalIdleUsers = 0;
418+
let totalActiveUsers = 0;
419+
const unprocessedUsers = [];
410420
let errorCount = 0;
411-
let discordActiveNonArchivedUsersQuerySnapshot;
421+
let usersSnapshot;
412422
try {
413-
discordActiveNonArchivedUsersQuerySnapshot = await usersCollection
423+
usersSnapshot = await usersCollection
414424
.where("roles.in_discord", "==", true)
415425
.where("roles.archived", "==", false)
416426
.get();
417427
} catch (error) {
418428
logger.error(`unable to get users ${error.message}`);
419429
throw new Error("unable to get users");
420430
}
421-
const totalValidUsersCount = discordActiveNonArchivedUsersQuerySnapshot.size;
422-
if (totalValidUsersCount) {
431+
const totalUsers = usersSnapshot.size;
432+
if (totalUsers) {
423433
await Promise.all(
424-
discordActiveNonArchivedUsersQuerySnapshot.docs.map(async (userDoc) => {
434+
usersSnapshot.docs.map(async (userDoc) => {
425435
const assigneeId = userDoc.id;
426436
try {
427437
const tasksQuerySnapshot = await firestore
@@ -430,23 +440,28 @@ const getIdleUsers = async () => {
430440
.where("status", "in", [TASK_STATUS.ASSIGNED, TASK_STATUS.IN_PROGRESS])
431441
.get();
432442
if (tasksQuerySnapshot.empty) {
433-
idleUsers.push(assigneeId);
443+
totalIdleUsers++;
444+
users.push({ userId: assigneeId, state: userState.IDLE });
445+
} else {
446+
totalActiveUsers++;
447+
users.push({ userId: assigneeId, state: userState.ACTIVE });
434448
}
435449
} catch (error) {
436450
errorCount++;
437-
usersNotProcessed.push(assigneeId);
451+
unprocessedUsers.push(assigneeId);
438452
logger.error(`Error retrieving tasks for user ${assigneeId}: ${error.message}`);
439453
}
440454
})
441455
);
442456
}
443457

444458
return {
445-
totalValidUsersCount,
446-
idleUsersCount: idleUsers.length,
447-
idleUsers,
448-
usersNotProcessedCount: errorCount,
449-
usersNotProcessed,
459+
totalUsers,
460+
totalIdleUsers,
461+
totalActiveUsers,
462+
totalUnprocessedUsers: errorCount,
463+
unprocessedUsers,
464+
users,
450465
};
451466
};
452467

@@ -503,7 +518,7 @@ module.exports = {
503518
updateUserStatusOnNewTaskAssignment,
504519
updateUserStatusOnTaskUpdate,
505520
updateStatusOnTaskCompletion,
506-
massUpdateIdleUsers,
507-
getIdleUsers,
521+
batchUpdateUsersStatus,
522+
getTaskBasedUsersStatus,
508523
cancelOooStatus,
509524
};

routes/userStatus.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const {
44
getUserStatus,
55
updateUserStatus,
66
updateAllUserStatus,
7-
massUpdateIdleUsers,
7+
batchUpdateUsersStatus,
88
getUserStatusControllers,
99
updateUserStatusController,
1010
} = require("../controllers/userStatus");
@@ -23,7 +23,7 @@ router.get("/self", authenticate, getUserStatus);
2323
router.get("/:userId", getUserStatus);
2424
router.patch("/self", authenticate, validateUserStatus, updateUserStatusController);
2525
router.patch("/update", authenticate, authorizeRoles([SUPERUSER]), updateAllUserStatus);
26-
router.patch("/batch", authenticate, authorizeRoles([SUPERUSER]), validateMassUpdate, massUpdateIdleUsers);
26+
router.patch("/batch", authenticate, authorizeRoles([SUPERUSER]), validateMassUpdate, batchUpdateUsersStatus);
2727
router.patch("/:userId", authenticate, authorizeRoles([SUPERUSER]), validateUserStatus, updateUserStatus);
2828
router.delete("/:userId", authenticate, authorizeRoles([SUPERUSER]), deleteUserStatus);
2929

0 commit comments

Comments
 (0)