From 5b81e336b3f72e5f9625e14cbb159b1e16b88bf0 Mon Sep 17 00:00:00 2001 From: Vinit Date: Wed, 26 Apr 2023 10:47:01 +0530 Subject: [PATCH 01/36] Added dependsOn on new collection --- controllers/tasks.js | 31 ++++++++++++++++++++++++++----- models/tasks.js | 32 +++++++++++++++++++++++++++++++- routes/tasks.js | 12 +++++++++++- 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index 02fec5bc4..1b41b7c62 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -6,6 +6,7 @@ const { addOrUpdate } = require("../models/users"); const { OLD_ACTIVE, OLD_BLOCKED, OLD_PENDING } = TASK_STATUS_OLD; const { IN_PROGRESS, BLOCKED, SMOKE_TESTING, ASSIGNED } = TASK_STATUS; const { INTERNAL_SERVER_ERROR, SOMETHING_WENT_WRONG } = require("../constants/errorMessages"); +const DependencyModel = require("../models/tasks"); /** * Creates new task * @@ -13,22 +14,41 @@ const { INTERNAL_SERVER_ERROR, SOMETHING_WENT_WRONG } = require("../constants/er * @param req.body {Object} - Task object * @param res {Object} - Express response object */ -const addNewTask = async (req, res) => { +const addNewTask = async (req, res, next) => { try { const { id: createdBy } = req.userData; - const body = { + const updatedBody = { ...req.body, createdBy, }; - const task = await tasks.updateTask(body); - + // console.log("hii"); + delete updatedBody.dependsOn; + const task = await tasks.updateTask(updatedBody); + // console.log("hiii"); + // console.log(next); + req.task = task; + return next(); + } catch (err) { + logger.error(`Error while creating new task: ${err}`); + return res.boom.badImplementation(INTERNAL_SERVER_ERROR); + } +}; +const addDependency = async (req, res) => { + const task = req.task; + // console.log("hiiii"); + // console.log(task); + try { + const body = [...req.body.dependsOn]; + // console.log(body); + const dependsOns = await DependencyModel.addDependency(body); return res.json({ message: "Task created successfully!", task: task.taskDetails, id: task.taskId, + dependsOns, }); } catch (err) { - logger.error(`Error while creating new task: ${err}`); + logger.error(`Error while creating new task dependency: ${err}`); return res.boom.badImplementation(INTERNAL_SERVER_ERROR); } }; @@ -280,4 +300,5 @@ module.exports = { updateTaskStatus, overdueTasks, assignTask, + addDependency, }; diff --git a/models/tasks.js b/models/tasks.js index 470c5139b..99f1a5c3f 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -2,6 +2,7 @@ const firestore = require("../utils/firestore"); const tasksModel = firestore.collection("tasks"); const ItemModel = firestore.collection("itemTags"); const userUtils = require("../utils/users"); +const DependencyModel = firestore.collection("TaskDependencies"); const { fromFirestoreData, toFirestoreData, buildTasks } = require("../utils/tasks"); const { TASK_TYPE, TASK_STATUS, TASK_STATUS_OLD } = require("../constants/tasks"); const { IN_PROGRESS, BLOCKED, SMOKE_TESTING, COMPLETED } = TASK_STATUS; @@ -32,13 +33,41 @@ const updateTask = async (taskData, taskId = null) => { taskId: taskInfo.id, taskDetails: await fromFirestoreData(taskData), }; - return result; } catch (err) { logger.error("Error in updating task", err); throw err; } }; +const addDependency = async (body) => { + // console.log("hi"); + try { + const [dependsOn] = body; + const taskid = tasksModel.doc(); + // const batch = firestore.batch(); + // console.log("body", body, taskid, dependsOn); + const result = await DependencyModel.add({ + taskid, + dependsOn, + }); + // for (const dependId of dependsOn) { + // batch.set(DependencyModel, { + // taskid, + // dependId, + // }); + // } + // await batch.commit(); + // taskData = await toFirestoreData(taskData); + // const taskId = requestData.taskId; + // for(let dependId of dependsOn){ + // createDocument({taskId, dependId}) + // } + return result; + } catch (err) { + logger.error("Error in creating dependency"); + throw err; + } +}; /** * Fetch all tasks @@ -326,4 +355,5 @@ module.exports = { fetchSelfTask, fetchSkillLevelTask, overdueTasks, + addDependency, }; diff --git a/routes/tasks.js b/routes/tasks.js index 62d8fae20..57854f019 100644 --- a/routes/tasks.js +++ b/routes/tasks.js @@ -7,15 +7,25 @@ const authorizeRoles = require("../middlewares/authorizeRoles"); const { APPOWNER, SUPERUSER } = require("../constants/roles"); const assignTask = require("../middlewares/assignTask"); const cache = require("../utils/cache"); +// const { validateDependencyBody } = require("../middlewares/validators/Dependency"); router.get("/", cache(), tasks.fetchTasks); router.get("/self", authenticate, tasks.getSelfTasks); router.get("/overdue", authenticate, authorizeRoles([SUPERUSER]), tasks.overdueTasks); -router.post("/", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), createTask, tasks.addNewTask); +router.post( + "/", + authenticate, + authorizeRoles([APPOWNER, SUPERUSER]), + createTask, + tasks.addNewTask, + tasks.addDependency +); router.patch("/:id", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), updateTask, tasks.updateTask); router.get("/:id/details", tasks.getTask); router.get("/:username", tasks.getUserTasks); router.patch("/self/:id", authenticate, updateSelfTask, tasks.updateTaskStatus, assignTask); router.patch("/assign/self", authenticate, tasks.assignTask); +// router.get("/dependency", authenticate, authorizeRoles([APPOWNER, SUPERUSER])); +// router.post("/dependency", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), validateDependencyBody); module.exports = router; From ff6b07f0d7e9205746e02e8b96efa33af4d8fc60 Mon Sep 17 00:00:00 2001 From: Vinit Date: Thu, 27 Apr 2023 19:55:41 +0530 Subject: [PATCH 02/36] Get taskId --- controllers/tasks.js | 41 ++++++++++++++--------------------------- models/tasks.js | 24 +++++------------------- routes/tasks.js | 12 +----------- 3 files changed, 20 insertions(+), 57 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index 1b41b7c62..dc0026577 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -14,41 +14,29 @@ const DependencyModel = require("../models/tasks"); * @param req.body {Object} - Task object * @param res {Object} - Express response object */ -const addNewTask = async (req, res, next) => { +const addNewTask = async (req, res) => { try { const { id: createdBy } = req.userData; - const updatedBody = { + const dependsOn = req.body.dependsOn; + const body = { ...req.body, createdBy, }; - // console.log("hii"); - delete updatedBody.dependsOn; - const task = await tasks.updateTask(updatedBody); - // console.log("hiii"); - // console.log(next); - req.task = task; - return next(); - } catch (err) { - logger.error(`Error while creating new task: ${err}`); - return res.boom.badImplementation(INTERNAL_SERVER_ERROR); - } -}; -const addDependency = async (req, res) => { - const task = req.task; - // console.log("hiiii"); - // console.log(task); - try { - const body = [...req.body.dependsOn]; - // console.log(body); - const dependsOns = await DependencyModel.addDependency(body); + // console.log("hii", dependsOn); + const { taskId, taskDetails } = await tasks.updateTask(body); + const data = { + taskId, + dependsOn, + }; + const taskDependency = await DependencyModel.addDependency(data); return res.json({ message: "Task created successfully!", - task: task.taskDetails, - id: task.taskId, - dependsOns, + task: taskDetails, + id: taskId, + dependsOn: taskDependency, }); } catch (err) { - logger.error(`Error while creating new task dependency: ${err}`); + logger.error(`Error while creating new task: ${err}`); return res.boom.badImplementation(INTERNAL_SERVER_ERROR); } }; @@ -300,5 +288,4 @@ module.exports = { updateTaskStatus, overdueTasks, assignTask, - addDependency, }; diff --git a/models/tasks.js b/models/tasks.js index 99f1a5c3f..386eed5d0 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -39,29 +39,15 @@ const updateTask = async (taskData, taskId = null) => { throw err; } }; -const addDependency = async (body) => { - // console.log("hi"); +const addDependency = async (data) => { try { - const [dependsOn] = body; - const taskid = tasksModel.doc(); - // const batch = firestore.batch(); - // console.log("body", body, taskid, dependsOn); + const { taskId, dependsOn } = data; + // console.log(dependsOn, taskId); const result = await DependencyModel.add({ - taskid, + taskId, dependsOn, }); - // for (const dependId of dependsOn) { - // batch.set(DependencyModel, { - // taskid, - // dependId, - // }); - // } - // await batch.commit(); - // taskData = await toFirestoreData(taskData); - // const taskId = requestData.taskId; - // for(let dependId of dependsOn){ - // createDocument({taskId, dependId}) - // } + // console.log(result); return result; } catch (err) { logger.error("Error in creating dependency"); diff --git a/routes/tasks.js b/routes/tasks.js index 57854f019..62d8fae20 100644 --- a/routes/tasks.js +++ b/routes/tasks.js @@ -7,25 +7,15 @@ const authorizeRoles = require("../middlewares/authorizeRoles"); const { APPOWNER, SUPERUSER } = require("../constants/roles"); const assignTask = require("../middlewares/assignTask"); const cache = require("../utils/cache"); -// const { validateDependencyBody } = require("../middlewares/validators/Dependency"); router.get("/", cache(), tasks.fetchTasks); router.get("/self", authenticate, tasks.getSelfTasks); router.get("/overdue", authenticate, authorizeRoles([SUPERUSER]), tasks.overdueTasks); -router.post( - "/", - authenticate, - authorizeRoles([APPOWNER, SUPERUSER]), - createTask, - tasks.addNewTask, - tasks.addDependency -); +router.post("/", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), createTask, tasks.addNewTask); router.patch("/:id", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), updateTask, tasks.updateTask); router.get("/:id/details", tasks.getTask); router.get("/:username", tasks.getUserTasks); router.patch("/self/:id", authenticate, updateSelfTask, tasks.updateTaskStatus, assignTask); router.patch("/assign/self", authenticate, tasks.assignTask); -// router.get("/dependency", authenticate, authorizeRoles([APPOWNER, SUPERUSER])); -// router.post("/dependency", authenticate, authorizeRoles([APPOWNER, SUPERUSER]), validateDependencyBody); module.exports = router; From 5e64aaacf9ee4beacb528050980be4fdcdd34bd1 Mon Sep 17 00:00:00 2001 From: Vinit Date: Fri, 28 Apr 2023 12:35:19 +0530 Subject: [PATCH 03/36] Store dependsOn array through batch --- controllers/tasks.js | 6 ++++-- middlewares/validators/tasks.js | 4 ++-- models/tasks.js | 26 +++++++++++++++++++------- routes/tasks.js | 11 +++++++++++ 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index dc0026577..e2e7bc90f 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -6,7 +6,7 @@ const { addOrUpdate } = require("../models/users"); const { OLD_ACTIVE, OLD_BLOCKED, OLD_PENDING } = TASK_STATUS_OLD; const { IN_PROGRESS, BLOCKED, SMOKE_TESTING, ASSIGNED } = TASK_STATUS; const { INTERNAL_SERVER_ERROR, SOMETHING_WENT_WRONG } = require("../constants/errorMessages"); -const DependencyModel = require("../models/tasks"); +const dependencyModel = require("../models/tasks"); /** * Creates new task * @@ -22,13 +22,15 @@ const addNewTask = async (req, res) => { ...req.body, createdBy, }; + // console.log(body); + delete body.dependsOn; // console.log("hii", dependsOn); const { taskId, taskDetails } = await tasks.updateTask(body); const data = { taskId, dependsOn, }; - const taskDependency = await DependencyModel.addDependency(data); + const taskDependency = await dependencyModel.addDependency(data); return res.json({ message: "Task created successfully!", task: taskDetails, diff --git a/middlewares/validators/tasks.js b/middlewares/validators/tasks.js index adf1f5832..4467f20f5 100644 --- a/middlewares/validators/tasks.js +++ b/middlewares/validators/tasks.js @@ -23,7 +23,7 @@ const createTask = async (req, res, next) => { assignee: joi.string().optional(), priority: joi.string().required(), percentCompleted: joi.number().required(), - dependsOn: joi.array().items(joi.string()).optional(), + dependsOn: joi.array().items().optional(), participants: joi.array().items(joi.string()).optional(), category: joi.string().optional(), level: joi.number().optional(), @@ -73,7 +73,7 @@ const updateTask = async (req, res, next) => { .optional(), assignee: joi.string().optional(), percentCompleted: joi.number().optional(), - dependsOn: joi.array().items(joi.string()).optional(), + dependsOn: joi.array().items().optional(), participants: joi.array().items(joi.string()).optional(), completionAward: joi .object() diff --git a/models/tasks.js b/models/tasks.js index 386eed5d0..40bc0054a 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -2,7 +2,7 @@ const firestore = require("../utils/firestore"); const tasksModel = firestore.collection("tasks"); const ItemModel = firestore.collection("itemTags"); const userUtils = require("../utils/users"); -const DependencyModel = firestore.collection("TaskDependencies"); +const dependencyModel = firestore.collection("TaskDependencies"); const { fromFirestoreData, toFirestoreData, buildTasks } = require("../utils/tasks"); const { TASK_TYPE, TASK_STATUS, TASK_STATUS_OLD } = require("../constants/tasks"); const { IN_PROGRESS, BLOCKED, SMOKE_TESTING, COMPLETED } = TASK_STATUS; @@ -42,13 +42,25 @@ const updateTask = async (taskData, taskId = null) => { const addDependency = async (data) => { try { const { taskId, dependsOn } = data; + const batch = firestore.batch(); + // console.log("data", taskId, dependsOn); + for (const dependsId of dependsOn) { + const taskDependOn = { + taskId, + dependsId, + }; + const docid = dependencyModel.doc(); + // console.log(docid); + // console.log("taskdepends", taskDependOn); + batch.set(docid, taskDependOn); + } + await batch.commit(); // console.log(dependsOn, taskId); - const result = await DependencyModel.add({ - taskId, - dependsOn, - }); - // console.log(result); - return result; + // const result = await DependencyModel.add({ + // taskId, + // dependsOn, + // }); + return data; } catch (err) { logger.error("Error in creating dependency"); throw err; diff --git a/routes/tasks.js b/routes/tasks.js index 62d8fae20..0e78feae8 100644 --- a/routes/tasks.js +++ b/routes/tasks.js @@ -19,3 +19,14 @@ router.patch("/self/:id", authenticate, updateSelfTask, tasks.updateTaskStatus, router.patch("/assign/self", authenticate, tasks.assignTask); module.exports = router; +// for (const dependId of dependsOn) { +// batch.set(DependencyModel, { +// taskid,// dependId, +// }); +// } +// await batch.commit(); +// taskData = await toFirestoreData(taskData); +// const taskId = requestData.taskId; +// for(let dependId of dependsOn){ +// createDocument({taskId, dependId}) +// } From b3d05604a9fd964901459e231532f3d9f7f62186 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Fri, 28 Apr 2023 22:15:48 +0530 Subject: [PATCH 04/36] initial commit --- constants/roles.js | 1 + controllers/users.js | 26 ++++++++++++++++++++++++++ models/users.js | 25 +++++++++++++++++++++++++ routes/users.js | 3 +++ 4 files changed, 55 insertions(+) diff --git a/constants/roles.js b/constants/roles.js index 9f80a4968..a4e5f13b5 100644 --- a/constants/roles.js +++ b/constants/roles.js @@ -4,6 +4,7 @@ const ROLES = { APPOWNER: "app_owner", MEMBER: "member", ARCHIVED: "archived", + IN_DISCORD: "inDiscord", }; module.exports = ROLES; diff --git a/controllers/users.js b/controllers/users.js index 88f31ac60..0221977ff 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -12,6 +12,7 @@ const { getPaginationLink, getUsernamesFromPRs } = require("../utils/users"); const { getQualifiers } = require("../utils/helper"); const { SOMETHING_WENT_WRONG, INTERNAL_SERVER_ERROR } = require("../constants/errorMessages"); const { getFilteredPRsOrIssues } = require("../utils/pullRequests"); +const { IN_DISCORD } = require("../constants/roles"); const verifyUser = async (req, res) => { const userId = req.userData.id; @@ -107,6 +108,7 @@ const getUsers = async (req, res) => { */ const getUser = async (req, res) => { + console.log(req.params.username); try { const result = await userQuery.fetchUser({ username: req.params.username }); const { phone, email, ...user } = result.user; @@ -462,6 +464,29 @@ const filterUsers = async (req, res) => { } }; +// const syncInDiscordRole = async (req, res) => { +// try { +// } catch (error) { +// logger.error(`Error while fetching all users: ${error}`); +// return res.boom.serverUnavailable("Something went wrong please contact admin"); +// } +// }; + +const fetchInDiscordUsers = async (req, res) => { + try { + const allUsers = await userQuery.fetchUsersWithRole(IN_DISCORD); + + return res.json({ + message: "Users found successfully!", + users: allUsers, + count: allUsers.length, + }); + } catch (error) { + logger.error(`Error while fetching all users: ${error}`); + return res.boom.serverUnavailable("Something went wrong please contact admin"); + } +}; + module.exports = { verifyUser, generateChaincode, @@ -481,4 +506,5 @@ module.exports = { addDefaultArchivedRole, getUserSkills, filterUsers, + fetchInDiscordUsers, }; diff --git a/models/users.js b/models/users.js index 6b60a9545..660dd12d8 100644 --- a/models/users.js +++ b/models/users.js @@ -409,6 +409,30 @@ const getUsersBasedOnFilter = async (query) => { return userDocs; }; +const fetchUsersWithRole = async (role) => { + try { + // console.log(role); + const snapshot = await userModel.where(`roles.${role}`, "==", true).get(); + const onlyMembers = []; + + if (!snapshot.empty) { + snapshot.forEach((doc) => { + onlyMembers.push({ + id: doc.id, + ...doc.data(), + phone: undefined, + email: undefined, + tokens: undefined, + }); + }); + } + return onlyMembers; + } catch (err) { + logger.error("Error retrieving users data with roles of inDiscord", err); + throw err; + } +}; + module.exports = { addOrUpdate, fetchPaginatedUsers, @@ -424,4 +448,5 @@ module.exports = { getRdsUserInfoByGitHubUsername, fetchUsers, getUsersBasedOnFilter, + fetchUsersWithRole, }; diff --git a/routes/users.js b/routes/users.js index 02b11c475..73ebf8262 100644 --- a/routes/users.js +++ b/routes/users.js @@ -16,6 +16,7 @@ router.get("/self", authenticate, users.getSelfDetails); router.get("/isUsernameAvailable/:username", authenticate, users.getUsernameAvailabilty); router.get("/chaincode", authenticate, users.generateChaincode); router.get("/search", userValidator.validateUserQueryParams, users.filterUsers); +router.get("/InDiscord", authenticate, users.fetchInDiscordUsers); router.get("/:username", users.getUser); router.get("/:userId/intro", authenticate, authorizeRoles([SUPERUSER]), users.getUserIntro); router.put("/self/intro", authenticate, userValidator.validateJoinData, users.addUserIntro); @@ -29,4 +30,6 @@ router.patch("/rejectDiff", authenticate, authorizeRoles([SUPERUSER]), users.rej router.patch("/:userId", authenticate, authorizeRoles([SUPERUSER]), users.updateUser); router.get("/suggestedUsers/:skillId", authenticate, authorizeRoles([SUPERUSER]), users.getSuggestedUsers); +router.post("/syncInDiscord", authenticate, users.getSelfDetails); + module.exports = router; From 088b2e9c6203f8a13efbde016188baab94245ad4 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Tue, 2 May 2023 13:18:34 +0530 Subject: [PATCH 05/36] sync API --- controllers/users.js | 60 +++++++++++++++++++++++++++++++++----------- models/users.js | 36 +++++++++++++++++++++++++- routes/users.js | 6 ++--- utils/users.js | 24 ++++++++++++++++++ 4 files changed, 108 insertions(+), 18 deletions(-) diff --git a/controllers/users.js b/controllers/users.js index 0221977ff..1480182bf 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -5,14 +5,15 @@ const logsQuery = require("../models/logs"); const imageService = require("../services/imageService"); const { profileDiffStatus } = require("../constants/profileDiff"); const { logType } = require("../constants/logs"); -const { fetch } = require("../utils/fetch"); + const logger = require("../utils/logger"); const obfuscate = require("../utils/obfuscate"); -const { getPaginationLink, getUsernamesFromPRs } = require("../utils/users"); +const { getPaginationLink, getUsernamesFromPRs, mapDiscordMembersDataAndSyncRole } = require("../utils/users"); const { getQualifiers } = require("../utils/helper"); const { SOMETHING_WENT_WRONG, INTERNAL_SERVER_ERROR } = require("../constants/errorMessages"); const { getFilteredPRsOrIssues } = require("../utils/pullRequests"); const { IN_DISCORD } = require("../constants/roles"); +const jwt = require("jsonwebtoken"); const verifyUser = async (req, res) => { const userId = req.userData.id; @@ -25,7 +26,11 @@ const verifyUser = async (req, res) => { logger.error(`Error while verifying user: ${error}`); return res.boom.serverUnavailable(SOMETHING_WENT_WRONG); } - fetch(process.env.IDENTITY_SERVICE_URL, "POST", null, { userId }, { "Content-Type": "application/json" }); + fetch(process.env.IDENTITY_SERVICE_URL, { + method: "POST", + body: { userId }, + headers: { "Content-Type": "application/json" }, + }); return res.json({ message: "Your request has been queued successfully", }); @@ -108,7 +113,6 @@ const getUsers = async (req, res) => { */ const getUser = async (req, res) => { - console.log(req.params.username); try { const result = await userQuery.fetchUser({ username: req.params.username }); const { phone, email, ...user } = result.user; @@ -463,23 +467,49 @@ const filterUsers = async (req, res) => { return res.boom.serverUnavailable("Something went wrong please contact admin"); } }; +const DISCORD_BASE_URL = "https://89d4-49-36-233-201.ngrok.io"; +const syncInDiscordRole = async (req, res) => { + try { + const authToken = jwt.sign({}, config.get("botToken.botPrivateKey"), { + algorithm: "RS256", + }); + // console.log(authToken); + const response = await fetch(`${DISCORD_BASE_URL}/discord-members`, { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${authToken}`, + }, + }); + const discordMembers = await response.json(); -// const syncInDiscordRole = async (req, res) => { -// try { -// } catch (error) { -// logger.error(`Error while fetching all users: ${error}`); -// return res.boom.serverUnavailable("Something went wrong please contact admin"); -// } -// }; + const allUsers = await userQuery.getAllUsers(); + mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); + + return res.json({ message: "Synced with discord members " }); + } catch (error) { + logger.error(`Error while fetching all users: ${error}`); + return res.boom.serverUnavailable("Something went wrong please contact admin"); + } +}; + +const fetchVerifiedUsers = async (req, res) => { + try { + const verifiedUsers = await userQuery.fetchUsersWhereFieldNotNull("discordId"); + return res.json(verifiedUsers); + } catch (error) { + logger.error(`Error while fetching all users: ${error}`); + return res.boom.serverUnavailable("Something went wrong please contact admin"); + } +}; const fetchInDiscordUsers = async (req, res) => { try { - const allUsers = await userQuery.fetchUsersWithRole(IN_DISCORD); + const usersInDiscord = await userQuery.fetchUsersWithRole(IN_DISCORD); return res.json({ message: "Users found successfully!", - users: allUsers, - count: allUsers.length, + users: usersInDiscord, + count: usersInDiscord.length, }); } catch (error) { logger.error(`Error while fetching all users: ${error}`); @@ -507,4 +537,6 @@ module.exports = { getUserSkills, filterUsers, fetchInDiscordUsers, + syncInDiscordRole, + fetchVerifiedUsers, }; diff --git a/models/users.js b/models/users.js index 660dd12d8..3d3707d6d 100644 --- a/models/users.js +++ b/models/users.js @@ -408,7 +408,15 @@ const getUsersBasedOnFilter = async (query) => { const userDocs = (await firestore.getAll(...userRefs)).map((doc) => ({ id: doc.id, ...doc.data() })); return userDocs; }; - +const getAllUsers = async () => { + try { + const usersRef = await userModel.get(); + return usersRef; + } catch (err) { + logger.error("Error retrieving users data with roles of inDiscord", err); + throw err; + } +}; const fetchUsersWithRole = async (role) => { try { // console.log(role); @@ -426,12 +434,36 @@ const fetchUsersWithRole = async (role) => { }); }); } + return onlyMembers; } catch (err) { logger.error("Error retrieving users data with roles of inDiscord", err); throw err; } }; +const fetchUsersWhereFieldNotNull = async (field) => { + try { + const snapshot = await userModel.where(field, "!=", null).get(); + const users = []; + + if (!snapshot.empty) { + snapshot.forEach((doc) => { + users.push({ + id: doc.id, + ...doc.data(), + phone: undefined, + email: undefined, + tokens: undefined, + }); + }); + } + + return users; + } catch (err) { + logger.error("Error retrieving users data with roles of inDiscord", err); + throw err; + } +}; module.exports = { addOrUpdate, @@ -449,4 +481,6 @@ module.exports = { fetchUsers, getUsersBasedOnFilter, fetchUsersWithRole, + fetchUsersWhereFieldNotNull, + getAllUsers, }; diff --git a/routes/users.js b/routes/users.js index 73ebf8262..1900bd720 100644 --- a/routes/users.js +++ b/routes/users.js @@ -16,7 +16,9 @@ router.get("/self", authenticate, users.getSelfDetails); router.get("/isUsernameAvailable/:username", authenticate, users.getUsernameAvailabilty); router.get("/chaincode", authenticate, users.generateChaincode); router.get("/search", userValidator.validateUserQueryParams, users.filterUsers); -router.get("/InDiscord", authenticate, users.fetchInDiscordUsers); +router.get("/inDiscord", authenticate, users.fetchInDiscordUsers); +router.post("/syncInDiscord", authenticate, users.syncInDiscordRole); +router.get("/verified", authenticate, users.fetchVerifiedUsers); router.get("/:username", users.getUser); router.get("/:userId/intro", authenticate, authorizeRoles([SUPERUSER]), users.getUserIntro); router.put("/self/intro", authenticate, userValidator.validateJoinData, users.addUserIntro); @@ -30,6 +32,4 @@ router.patch("/rejectDiff", authenticate, authorizeRoles([SUPERUSER]), users.rej router.patch("/:userId", authenticate, authorizeRoles([SUPERUSER]), users.updateUser); router.get("/suggestedUsers/:skillId", authenticate, authorizeRoles([SUPERUSER]), users.getSuggestedUsers); -router.post("/syncInDiscord", authenticate, users.getSelfDetails); - module.exports = router; diff --git a/utils/users.js b/utils/users.js index f3754d74e..f89a0dec3 100644 --- a/utils/users.js +++ b/utils/users.js @@ -142,6 +142,29 @@ function getUsernamesFromPRs(allPRs) { return usernames; } +function mapDiscordMembersDataAndSyncRole(allUsers, discordMembers) { + try { + allUsers.forEach((doc) => { + const user = doc.data(); + + if (user.roles.archived) { + const roles = user.roles ? { ...user.roles, inDiscord: false } : { inDiscord: false }; + doc.ref.update({ roles }); + } else if (user.discordId) { + const discordUserData = discordMembers.find((item) => item.user.id === user.discordId); + if (discordUserData) { + const roles = user.roles ? { ...user.roles, inDiscord: true } : { inDiscord: true }; + doc.ref.update({ roles, joined_RDS: discordUserData.joined_at }); + } else { + const roles = user.roles ? { ...user.roles, inDiscord: false } : { inDiscord: false }; + doc.ref.update({ roles }); + } + } + }); + } catch (err) { + logger.error(err); + } +} module.exports = { addUserToDBForTest, @@ -152,4 +175,5 @@ module.exports = { getLowestLevelSkill, getPaginationLink, getUsernamesFromPRs, + mapDiscordMembersDataAndSyncRole, }; From ad4794479f482a33f18621420746e8e518699f3c Mon Sep 17 00:00:00 2001 From: Vinit Date: Fri, 5 May 2023 19:27:27 +0530 Subject: [PATCH 06/36] Remove console log --- models/tasks.js | 8 -------- routes/tasks.js | 11 ----------- 2 files changed, 19 deletions(-) diff --git a/models/tasks.js b/models/tasks.js index 40bc0054a..a000f8015 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -43,23 +43,15 @@ const addDependency = async (data) => { try { const { taskId, dependsOn } = data; const batch = firestore.batch(); - // console.log("data", taskId, dependsOn); for (const dependsId of dependsOn) { const taskDependOn = { taskId, dependsId, }; const docid = dependencyModel.doc(); - // console.log(docid); - // console.log("taskdepends", taskDependOn); batch.set(docid, taskDependOn); } await batch.commit(); - // console.log(dependsOn, taskId); - // const result = await DependencyModel.add({ - // taskId, - // dependsOn, - // }); return data; } catch (err) { logger.error("Error in creating dependency"); diff --git a/routes/tasks.js b/routes/tasks.js index 0e78feae8..62d8fae20 100644 --- a/routes/tasks.js +++ b/routes/tasks.js @@ -19,14 +19,3 @@ router.patch("/self/:id", authenticate, updateSelfTask, tasks.updateTaskStatus, router.patch("/assign/self", authenticate, tasks.assignTask); module.exports = router; -// for (const dependId of dependsOn) { -// batch.set(DependencyModel, { -// taskid,// dependId, -// }); -// } -// await batch.commit(); -// taskData = await toFirestoreData(taskData); -// const taskId = requestData.taskId; -// for(let dependId of dependsOn){ -// createDocument({taskId, dependId}) -// } From aeabe05640c687f00c7b3e8bc7bd8226edf58db9 Mon Sep 17 00:00:00 2001 From: Vinit Date: Sat, 6 May 2023 05:17:53 +0530 Subject: [PATCH 07/36] Remove console log --- controllers/tasks.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index e2e7bc90f..a4cf25c27 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -22,9 +22,7 @@ const addNewTask = async (req, res) => { ...req.body, createdBy, }; - // console.log(body); delete body.dependsOn; - // console.log("hii", dependsOn); const { taskId, taskDetails } = await tasks.updateTask(body); const data = { taskId, From 56b589e82fd5e87f5064a86f8766c9326cd7ee0c Mon Sep 17 00:00:00 2001 From: Vinit Date: Sun, 7 May 2023 10:56:50 +0530 Subject: [PATCH 08/36] return dependsOn as reponse --- models/tasks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/tasks.js b/models/tasks.js index 713d6b0d4..de578fa24 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -52,7 +52,7 @@ const addDependency = async (data) => { batch.set(docid, taskDependOn); } await batch.commit(); - return data; + return data.dependsOn; } catch (err) { logger.error("Error in creating dependency"); throw err; From c8f88e96740455a9f2117cf5043d218df233b3bc Mon Sep 17 00:00:00 2001 From: Vinit Date: Mon, 8 May 2023 09:26:51 +0530 Subject: [PATCH 09/36] Add test for task-dependency --- test/integration/tasks.test.js | 2 ++ test/unit/models/tasks.test.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/test/integration/tasks.test.js b/test/integration/tasks.test.js index c5ee0af89..08aa98e65 100644 --- a/test/integration/tasks.test.js +++ b/test/integration/tasks.test.js @@ -97,6 +97,7 @@ describe("Tasks", function () { lossRate: { [DINERO]: 1 }, assignee: appOwner.username, participants: [], + dependsOn: [], }) .end((err, res) => { if (err) { @@ -110,6 +111,7 @@ describe("Tasks", function () { expect(res.body.task.createdBy).to.equal(appOwner.username); expect(res.body.task.assignee).to.equal(appOwner.username); expect(res.body.task.participants).to.be.a("array"); + expect(res.body.dependsOn).to.be.a("array"); return done(); }); }); diff --git a/test/unit/models/tasks.test.js b/test/unit/models/tasks.test.js index ac88b8d42..0069920ee 100644 --- a/test/unit/models/tasks.test.js +++ b/test/unit/models/tasks.test.js @@ -10,6 +10,9 @@ const { expect } = chai; const cleanDb = require("../../utils/cleanDb"); const tasksData = require("../../fixtures/tasks/tasks")(); const tasks = require("../../../models/tasks"); +const { addDependency } = require("../../../models/tasks"); +const firestore = require("../../../utils/firestore"); +const dependencyModel = firestore.collection("TaskDependencies"); describe("tasks", function () { afterEach(async function () { @@ -40,4 +43,31 @@ describe("tasks", function () { }); }); }); + + describe("addDependency", function () { + it("should add dependencies to firestore and return dependsOn array", async function () { + const data = { + taskId: "taskId1", + dependsOn: ["taskId2", "taskId3"], + }; + const result = await addDependency(data); + expect(result).to.deep.equal(data.dependsOn); + }); + + it("should throw an error if there is an error while creating dependencies", async function () { + const data = { + taskId: "taskId1", + dependsOn: ["taskId2", "taskId3"], + }; + const expectedError = new Error("test error"); + dependencyModel.doc = () => { + throw expectedError; + }; + try { + await addDependency(data); + } catch (err) { + expect(err).to.deep.equal(expectedError); + } + }); + }); }); From 6ca49f2ea288e85b54ccf4adc1b226c0de15098a Mon Sep 17 00:00:00 2001 From: Vinit Date: Wed, 10 May 2023 06:36:28 +0530 Subject: [PATCH 10/36] change task res.json --- controllers/tasks.js | 9 ++++++--- middlewares/validators/tasks.js | 4 ++-- models/tasks.js | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index 6075eaa95..89548c593 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -29,11 +29,14 @@ const addNewTask = async (req, res) => { dependsOn, }; const taskDependency = await dependencyModel.addDependency(data); + const task = { + ...taskDetails, + dependsOn: taskDependency, + id: taskId, + }; return res.json({ message: "Task created successfully!", - task: taskDetails, - id: taskId, - dependsOn: taskDependency, + task, }); } catch (err) { logger.error(`Error while creating new task: ${err}`); diff --git a/middlewares/validators/tasks.js b/middlewares/validators/tasks.js index eca28accc..2c775cbe7 100644 --- a/middlewares/validators/tasks.js +++ b/middlewares/validators/tasks.js @@ -23,7 +23,7 @@ const createTask = async (req, res, next) => { assignee: joi.string().optional(), priority: joi.string().required(), percentCompleted: joi.number().required(), - dependsOn: joi.array().items().optional(), + dependsOn: joi.array().items(joi.string()).optional(), participants: joi.array().items(joi.string()).optional(), category: joi.string().optional(), level: joi.number().optional(), @@ -84,7 +84,7 @@ const updateTask = async (req, res, next) => { .optional(), assignee: joi.string().optional(), percentCompleted: joi.number().optional(), - dependsOn: joi.array().items().optional(), + dependsOn: joi.array().items(joi.string()).optional(), participants: joi.array().items(joi.string()).optional(), completionAward: joi .object() diff --git a/models/tasks.js b/models/tasks.js index de578fa24..115624be2 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -1,8 +1,8 @@ const firestore = require("../utils/firestore"); const tasksModel = firestore.collection("tasks"); const ItemModel = firestore.collection("itemTags"); +const dependencyModel = firestore.collection("taskDependencies"); const userUtils = require("../utils/users"); -const dependencyModel = firestore.collection("TaskDependencies"); const { fromFirestoreData, toFirestoreData, buildTasks } = require("../utils/tasks"); const { TASK_TYPE, TASK_STATUS, TASK_STATUS_OLD } = require("../constants/tasks"); const { IN_PROGRESS, BLOCKED, SMOKE_TESTING, COMPLETED } = TASK_STATUS; @@ -67,7 +67,8 @@ const addDependency = async (data) => { const fetchTasks = async () => { try { const tasksSnapshot = await tasksModel.get(); - const tasks = buildTasks(tasksSnapshot); + const dependencySnapshot = await dependencyModel.get(); + const tasks = buildTasks(tasksSnapshot, dependencySnapshot); const promises = tasks.map(async (task) => fromFirestoreData(task)); const updatedTasks = await Promise.all(promises); const taskList = updatedTasks.map((task) => { From 206cb796722fbb8ae941a11f284ce84a89f9d3e0 Mon Sep 17 00:00:00 2001 From: Vinit Date: Wed, 10 May 2023 06:39:34 +0530 Subject: [PATCH 11/36] remove unwanted code --- models/tasks.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/models/tasks.js b/models/tasks.js index 115624be2..d8a473473 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -67,8 +67,7 @@ const addDependency = async (data) => { const fetchTasks = async () => { try { const tasksSnapshot = await tasksModel.get(); - const dependencySnapshot = await dependencyModel.get(); - const tasks = buildTasks(tasksSnapshot, dependencySnapshot); + const tasks = buildTasks(tasksSnapshot); const promises = tasks.map(async (task) => fromFirestoreData(task)); const updatedTasks = await Promise.all(promises); const taskList = updatedTasks.map((task) => { From 6c6cd23ae3b4bd1586900253cecffe119c7c4413 Mon Sep 17 00:00:00 2001 From: Vinit Date: Wed, 10 May 2023 07:17:42 +0530 Subject: [PATCH 12/36] Change task test integration --- test/integration/tasks.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/tasks.test.js b/test/integration/tasks.test.js index 08aa98e65..289f38a92 100644 --- a/test/integration/tasks.test.js +++ b/test/integration/tasks.test.js @@ -106,12 +106,12 @@ describe("Tasks", function () { expect(res).to.have.status(200); expect(res.body).to.be.a("object"); expect(res.body.message).to.equal("Task created successfully!"); - expect(res.body.id).to.be.a("string"); + expect(res.body.task.id).to.be.a("string"); expect(res.body.task).to.be.a("object"); expect(res.body.task.createdBy).to.equal(appOwner.username); expect(res.body.task.assignee).to.equal(appOwner.username); expect(res.body.task.participants).to.be.a("array"); - expect(res.body.dependsOn).to.be.a("array"); + expect(res.body.task.dependsOn).to.be.a("array"); return done(); }); }); From a474cd07dcc3c06a50c78ed5a474ca3ec7455e35 Mon Sep 17 00:00:00 2001 From: Vinit Date: Fri, 12 May 2023 06:11:15 +0530 Subject: [PATCH 13/36] change res.json --- controllers/tasks.js | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index 89548c593..bc0b33f3b 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -28,16 +28,25 @@ const addNewTask = async (req, res) => { taskId, dependsOn, }; - const taskDependency = await dependencyModel.addDependency(data); - const task = { - ...taskDetails, - dependsOn: taskDependency, - id: taskId, - }; - return res.json({ - message: "Task created successfully!", - task, - }); + if (data.dependsOn) { + const taskDependency = await dependencyModel.addDependency(data); + return res.json({ + message: "Task created successfully!", + task: { + ...taskDetails, + dependsOn: taskDependency, + id: taskId, + }, + }); + } else { + return res.json({ + message: "Task created successfully!", + task: { + ...taskDetails, + id: taskId, + }, + }); + } } catch (err) { logger.error(`Error while creating new task: ${err}`); return res.boom.badImplementation(INTERNAL_SERVER_ERROR); From c2287e9fe199625f93b09b041078e1b6c51222cf Mon Sep 17 00:00:00 2001 From: Vinit Date: Sat, 13 May 2023 06:14:59 +0530 Subject: [PATCH 14/36] refactor code --- controllers/tasks.js | 28 +++++++++------------------- models/tasks.js | 3 +++ test/integration/tasks.test.js | 2 +- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/controllers/tasks.js b/controllers/tasks.js index bc0b33f3b..1bae555c5 100644 --- a/controllers/tasks.js +++ b/controllers/tasks.js @@ -28,25 +28,15 @@ const addNewTask = async (req, res) => { taskId, dependsOn, }; - if (data.dependsOn) { - const taskDependency = await dependencyModel.addDependency(data); - return res.json({ - message: "Task created successfully!", - task: { - ...taskDetails, - dependsOn: taskDependency, - id: taskId, - }, - }); - } else { - return res.json({ - message: "Task created successfully!", - task: { - ...taskDetails, - id: taskId, - }, - }); - } + const taskDependency = dependsOn && (await dependencyModel.addDependency(data)); + return res.json({ + message: "Task created successfully!", + task: { + ...taskDetails, + ...(taskDependency && { dependsOn: taskDependency }), + id: taskId, + }, + }); } catch (err) { logger.error(`Error while creating new task: ${err}`); return res.boom.badImplementation(INTERNAL_SERVER_ERROR); diff --git a/models/tasks.js b/models/tasks.js index d8a473473..1756e0dcc 100644 --- a/models/tasks.js +++ b/models/tasks.js @@ -43,6 +43,9 @@ const addDependency = async (data) => { try { const { taskId, dependsOn } = data; const batch = firestore.batch(); + if (dependsOn.length > 500) { + throw new Error("Error cannot add more than 500 taskId"); + } for (const dependsId of dependsOn) { const taskDependOn = { taskId, diff --git a/test/integration/tasks.test.js b/test/integration/tasks.test.js index 289f38a92..972d1e7d6 100644 --- a/test/integration/tasks.test.js +++ b/test/integration/tasks.test.js @@ -106,8 +106,8 @@ describe("Tasks", function () { expect(res).to.have.status(200); expect(res.body).to.be.a("object"); expect(res.body.message).to.equal("Task created successfully!"); - expect(res.body.task.id).to.be.a("string"); expect(res.body.task).to.be.a("object"); + expect(res.body.task.id).to.be.a("string"); expect(res.body.task.createdBy).to.equal(appOwner.username); expect(res.body.task.assignee).to.equal(appOwner.username); expect(res.body.task.participants).to.be.a("array"); From 23e594cdf6f6e53683f4ac23f487946314a9cdb1 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Sat, 13 May 2023 18:26:45 +0530 Subject: [PATCH 15/36] func: search roles and verified users --- constants/users.js | 1 + controllers/users.js | 2 +- middlewares/validators/user.js | 5 +++ test/unit/utils/users.test.js | 58 ++++++++++++++++++++++++++++++++++ utils/users.js | 2 +- 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/constants/users.js b/constants/users.js index fea46dd70..bdb5939f9 100644 --- a/constants/users.js +++ b/constants/users.js @@ -13,6 +13,7 @@ const USER_STATUS = { const ALLOWED_FILTER_PARAMS = { ITEM_TAG: ["levelId", "levelName", "levelValue", "tagId"], USER_STATE: ["state"], + ROLE: ["role"], }; module.exports = { profileStatus, USER_STATUS, ALLOWED_FILTER_PARAMS }; diff --git a/controllers/users.js b/controllers/users.js index 30415558a..755eaf9ba 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -473,7 +473,7 @@ const syncInDiscordRole = async (req, res) => { const authToken = jwt.sign({}, config.get("botToken.botPrivateKey"), { algorithm: "RS256", }); - // console.log(authToken); + const response = await fetch(`${DISCORD_BASE_URL}/discord-members`, { headers: { "Content-Type": "application/json", diff --git a/middlewares/validators/user.js b/middlewares/validators/user.js index 8ead61e64..3033f0f30 100644 --- a/middlewares/validators/user.js +++ b/middlewares/validators/user.js @@ -172,6 +172,11 @@ async function validateUserQueryParams(req, res, next) { joi.array().items(joi.string().valid("IDLE", "OOO", "ACTIVE")) ) .optional(), + role: joi + .alternatives() + .try(joi.string().valid("in_discord", "member"), joi.array().items(joi.string().valid("in_discord", "member"))) + .optional(), + verified: joi.string().optional(), }) .messages({ "object.min": "Please provide at least one filter criteria", diff --git a/test/unit/utils/users.test.js b/test/unit/utils/users.test.js index 04298d6c2..5a8fbdaf6 100644 --- a/test/unit/utils/users.test.js +++ b/test/unit/utils/users.test.js @@ -1,6 +1,8 @@ const chai = require("chai"); const { expect } = chai; +const sinon = require("sinon"); + const usersUtils = require("../../../utils/users"); const cleanDb = require("../../utils/cleanDb"); const addUser = require("../../utils/addUser"); @@ -65,4 +67,60 @@ describe("users", function () { expect(participantUserId).to.include(userId); }); }); + + describe("mapDiscordMembersDataAndSyncRole", function () { + it("should update roles and joined_discord fields for users with matching Discord IDs", function () { + const allUsers = [ + { + data: () => ({ roles: { archived: false }, discordId: "123" }), + ref: { update: sinon.spy() }, + }, + ]; + const discordMembers = [ + { + user: { id: "123" }, + joined_at: "2022-05-01T00:00:00.000Z", + }, + ]; + + usersUtils.mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); + + sinon.assert.calledWithExactly(allUsers[0].ref.update, { + roles: { archived: false, inDiscord: true }, + joined_discord: discordMembers[0].joined_at, + }); + }); + + it("should update roles field to inDiscord: false for users with no matching Discord ID", function () { + const allUsers = [ + { + data: () => ({ roles: { archived: false }, discordId: "123" }), + ref: { update: sinon.spy() }, + }, + ]; + const discordMembers = []; + + usersUtils.mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); + + sinon.assert.calledWithExactly(allUsers[0].ref.update, { + roles: { archived: false, inDiscord: false }, + }); + }); + + it("should update roles field to inDiscord: false for users with archived roles", function () { + const allUsers = [ + { + data: () => ({ roles: { archived: true }, discordId: "123" }), + ref: { update: () => sinon.spy() }, + }, + ]; + const discordMembers = []; + + usersUtils.mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); + + expect(allUsers[0].ref.update).to.have.been.calledWith({ + roles: { archived: true, inDiscord: false }, + }); + }); + }); }); diff --git a/utils/users.js b/utils/users.js index f89a0dec3..b24e0336d 100644 --- a/utils/users.js +++ b/utils/users.js @@ -154,7 +154,7 @@ function mapDiscordMembersDataAndSyncRole(allUsers, discordMembers) { const discordUserData = discordMembers.find((item) => item.user.id === user.discordId); if (discordUserData) { const roles = user.roles ? { ...user.roles, inDiscord: true } : { inDiscord: true }; - doc.ref.update({ roles, joined_RDS: discordUserData.joined_at }); + doc.ref.update({ roles, joined_discord: discordUserData.joined_at }); } else { const roles = user.roles ? { ...user.roles, inDiscord: false } : { inDiscord: false }; doc.ref.update({ roles }); From 0df2d1cda93d2242c43bc82be9d212584e6c5264 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Sun, 14 May 2023 15:19:42 +0530 Subject: [PATCH 16/36] adds the route to get a specific document --- constants/progresses.js | 7 +++- controllers/progresses.js | 62 +++++++++++++++++++++++++++- middlewares/validators/progresses.js | 18 ++++++++ models/progresses.js | 27 ++++++++++-- routes/progresses.js | 9 +++- utils/progresses.js | 22 ++++++++++ 6 files changed, 137 insertions(+), 8 deletions(-) diff --git a/constants/progresses.js b/constants/progresses.js index c3170eeb2..a582c384b 100644 --- a/constants/progresses.js +++ b/constants/progresses.js @@ -11,4 +11,9 @@ const RESPONSE_MESSAGES = { PROGRESS_ALREADY_CREATED, }; -module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY }; +const TYPE_MAP = { + user: "userId", + task: "taskId", +}; + +module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY, TYPE_MAP }; diff --git a/controllers/progresses.js b/controllers/progresses.js index ad544514d..0e170e71f 100644 --- a/controllers/progresses.js +++ b/controllers/progresses.js @@ -1,5 +1,10 @@ const { Conflict, NotFound } = require("http-errors"); -const { createProgressDocument, getProgressDocument, getRangeProgressData } = require("../models/progresses"); +const { + createProgressDocument, + getProgressDocument, + getRangeProgressData, + getProgressByDate, +} = require("../models/progresses"); const { RESPONSE_MESSAGES } = require("../constants/progresses"); const { PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED, PROGRESS_DOCUMENT_CREATED_SUCCEEDED } = RESPONSE_MESSAGES; @@ -171,4 +176,57 @@ const getProgressRangeData = async (req, res) => { } }; -module.exports = { createProgress, getProgress, getProgressRangeData }; +/** + * @typedef {Object} progressPathParams + * @property {string} type - The type of progress document user or task. + * @property {string} typeId - The ID of the type. + * @property {string} date - The iso format date of the query. + */ + +/** + * @typedef {Object} ProgressDocument + * @property {string} id - The id of the progress document. + * @property {string} type - The type of progress document. + * @property {string} completed - The completed progress. + * @property {string} planned - The planned progress. + * @property {string} blockers - The blockers. + * @property {string} userId - The User ID + * @property {string} [taskId] - The task ID (optional). + * @property {number} createdAt - The timestamp when the progress document was created. + * @property {number} date - The timestamp for the day the progress document was created. + */ + +/** + * @typedef {Object} GetProgressByDateResponse + * @property {string} message - The success message. + * @property {ProgressDocument} data - An array of progress documents + */ + +/** + * Retrieves the progress documents based on provided query parameters. + * @param {Object} req - The HTTP request object. + * @param {progressPathParams} req.params - The query parameters + * @param {Object} res - The HTTP response object. + * @returns {Promise} A Promise that resolves when the response is sent. + */ + +const getProgressBydDateController = async (req, res) => { + try { + const data = await getProgressByDate(req.params); + return res.json({ + message: PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED, + data, + }); + } catch (error) { + if (error instanceof NotFound) { + return res.status(404).json({ + message: error.message, + }); + } + return res.status(400).json({ + message: error.message, + }); + } +}; + +module.exports = { createProgress, getProgress, getProgressRangeData, getProgressBydDateController }; diff --git a/middlewares/validators/progresses.js b/middlewares/validators/progresses.js index 326a21329..abd584128 100644 --- a/middlewares/validators/progresses.js +++ b/middlewares/validators/progresses.js @@ -92,8 +92,26 @@ const validateGetRangeProgressRecordsParams = async (req, res, next) => { res.boom.badRequest(error.details[0].message); } }; + +const validateGetDayProgressParams = async (req, res, next) => { + const schema = joi.object({ + type: joi.string().valid("user", "task").required().messages({ + "any.only": "Type field is restricted to either 'user' or 'task'.", + }), + typeId: joi.string().required(), + date: joi.date().iso().required(), + }); + try { + await schema.validateAsync(req.params, { abortEarly: false }); + next(); + } catch (error) { + logger.error(`Error validating payload: ${error}`); + res.boom.badRequest(error.details[0].message); + } +}; module.exports = { validateCreateProgressRecords, validateGetProgressRecordsQuery, validateGetRangeProgressRecordsParams, + validateGetDayProgressParams, }; diff --git a/models/progresses.js b/models/progresses.js index 4e7a1e99e..b861da0ab 100644 --- a/models/progresses.js +++ b/models/progresses.js @@ -1,7 +1,7 @@ -const { Conflict } = require("http-errors"); +const { Conflict, NotFound } = require("http-errors"); const fireStore = require("../utils/firestore"); const progressesCollection = fireStore.collection("progresses"); -const { RESPONSE_MESSAGES } = require("../constants/progresses"); +const { RESPONSE_MESSAGES, TYPE_MAP } = require("../constants/progresses"); const { buildQueryToFetchDocs, getProgressDocs, @@ -11,8 +11,9 @@ const { buildQueryForPostingProgress, assertTaskExists, getProgressDateTimestamp, + buildQueryToSearchProgressByDay, } = require("../utils/progresses"); -const { PROGRESS_ALREADY_CREATED } = RESPONSE_MESSAGES; +const { PROGRESS_ALREADY_CREATED, PROGRESS_DOCUMENT_NOT_FOUND } = RESPONSE_MESSAGES; /** * Adds a new progress document for the given user or task, with a limit of one progress document per day. @@ -68,4 +69,22 @@ const getRangeProgressData = async (queryParams) => { }; }; -module.exports = { createProgressDocument, getProgressDocument, getRangeProgressData }; +/** + * This function fetches the progress records for a particular user or task on the specified date. + * @param pathParams {object} This is the data that will be used for querying the db. It should contain type, typeId and date + * @returns {Promise} A Promise that resolves with the progress records of the queried user or task. + * @throws {Error} If the userId or taskId is invalid or does not exist. + **/ +async function getProgressByDate(pathParams) { + const { type, typeId, date } = pathParams; + await assertUserOrTaskExists({ [TYPE_MAP[type]]: typeId }); + const query = buildQueryToSearchProgressByDay({ [TYPE_MAP[type]]: typeId, date }); + const result = await query.get(); + if (!result.size) { + throw new NotFound(PROGRESS_DOCUMENT_NOT_FOUND); + } + const doc = result.docs[0]; + return { id: doc.id, ...doc.data() }; +} + +module.exports = { createProgressDocument, getProgressDocument, getRangeProgressData, getProgressByDate }; diff --git a/routes/progresses.js b/routes/progresses.js index 89e3d46e1..767559443 100644 --- a/routes/progresses.js +++ b/routes/progresses.js @@ -5,11 +5,18 @@ const { validateCreateProgressRecords, validateGetProgressRecordsQuery, validateGetRangeProgressRecordsParams, + validateGetDayProgressParams, } = require("../middlewares/validators/progresses"); -const { createProgress, getProgress, getProgressRangeData } = require("../controllers/progresses"); +const { + createProgress, + getProgress, + getProgressRangeData, + getProgressBydDateController, +} = require("../controllers/progresses"); router.post("/", authenticate, validateCreateProgressRecords, createProgress); router.get("/", validateGetProgressRecordsQuery, getProgress); +router.get("/:type/:typeId/date/:date", validateGetDayProgressParams, getProgressBydDateController); router.get("/range", validateGetRangeProgressRecordsParams, getProgressRangeData); module.exports = router; diff --git a/utils/progresses.js b/utils/progresses.js index e56e6ab74..251616416 100644 --- a/utils/progresses.js +++ b/utils/progresses.js @@ -178,6 +178,27 @@ const getProgressRecords = async (query, queryParams) => { return progressRecords; }; +/** + * Retrieves progress records for a given date range. + * @param {Object} pathParamsObject - An object containing the type , typeId and date. + * @param {string} pathParamsObject.type - The type of the record i.e user or task. + * @param {string} pathParamsObject.typeId - The id of the type i.e user or task. + * @param {string} pathParamsObject.date - The date of the record + * @returns {Query} A Firestore query object that filters progress documents based on the given parameters. + * + */ +const buildQueryToSearchProgressByDay = (pathParams) => { + const { userId, taskId, date } = pathParams; + let query = progressesCollection; + if (userId) { + query = query.where("userId", "==", userId); + } else { + query = query.where("taskId", "==", taskId); + } + const dateTimeStamp = new Date(date).setUTCHours(0, 0, 0, 0); + query = query.where("date", "==", dateTimeStamp).limit(1); + return query; +}; module.exports = { getProgressDateTimestamp, buildQueryForPostingProgress, @@ -188,4 +209,5 @@ module.exports = { getProgressDocs, buildRangeProgressQuery, getProgressRecords, + buildQueryToSearchProgressByDay, }; From 07c0bb0a27855516c2858fec30574c512ea6285f Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Sun, 14 May 2023 20:30:38 +0530 Subject: [PATCH 17/36] feat: search in_discord and verified --- middlewares/validators/user.js | 5 +-- models/users.js | 59 ++++++++++++++-------------------- 2 files changed, 26 insertions(+), 38 deletions(-) diff --git a/middlewares/validators/user.js b/middlewares/validators/user.js index 3033f0f30..d1172f42c 100644 --- a/middlewares/validators/user.js +++ b/middlewares/validators/user.js @@ -172,10 +172,7 @@ async function validateUserQueryParams(req, res, next) { joi.array().items(joi.string().valid("IDLE", "OOO", "ACTIVE")) ) .optional(), - role: joi - .alternatives() - .try(joi.string().valid("in_discord", "member"), joi.array().items(joi.string().valid("in_discord", "member"))) - .optional(), + role: joi.string().valid("in_discord", "member").optional(), verified: joi.string().optional(), }) .messages({ diff --git a/models/users.js b/models/users.js index 78817b2a8..bf28924f7 100644 --- a/models/users.js +++ b/models/users.js @@ -360,6 +360,8 @@ const getRdsUserInfoByGitHubUsername = async (githubUsername) => { * @param {Array} query.levelNumber - Array of levelNumbers to filter the users on * @param {Array} query.tagId - Array of tagIds to filter the users on * @param {Array} query.state - Array of states to filter the users on + * @param {String} query.role - filter the users on + * @param {String} query.verified - filter the users on * @return {Promise} - Array of user documents that match the filter criteria */ @@ -429,46 +431,35 @@ const fetchUsersWithRole = async (role) => { const snapshot = await userModel.where(`roles.${role}`, "==", true).get(); const onlyMembers = []; - if (!snapshot.empty) { - snapshot.forEach((doc) => { - onlyMembers.push({ - id: doc.id, - ...doc.data(), - phone: undefined, - email: undefined, - tokens: undefined, - }); + const roleQuery = query.role; + const verifiedQuery = query.verified; + + if (roleQuery) { + const filteredUsers = []; + const snapshot = await userModel.where(`roles.${roleQuery}`, "==", true).get(); + snapshot.forEach((doc) => { + filteredUsers.push({ + id: doc.id, + ...doc.data(), }); - } + }); - return onlyMembers; - } catch (err) { - logger.error("Error retrieving users data with roles of inDiscord", err); - throw err; + return filteredUsers; } -}; -const fetchUsersWhereFieldNotNull = async (field) => { - try { - const snapshot = await userModel.where(field, "!=", null).get(); - const users = []; - - if (!snapshot.empty) { - snapshot.forEach((doc) => { - users.push({ - id: doc.id, - ...doc.data(), - phone: undefined, - email: undefined, - tokens: undefined, - }); + if (verifiedQuery) { + console.log(typeof verifiedQuery); + const filteredUsers = []; + const snapshot = await userModel.orderBy("discordId").get(); + snapshot.forEach((doc) => { + filteredUsers.push({ + id: doc.id, + ...doc.data(), }); - } + }); - return users; - } catch (err) { - logger.error("Error retrieving users data with roles of inDiscord", err); - throw err; + return filteredUsers; } + return []; }; module.exports = { From 19fe12a5e1cd8940f587a27188d2f3e27028db78 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Sun, 14 May 2023 20:31:04 +0530 Subject: [PATCH 18/36] chore: remove unused code --- constants/roles.js | 2 +- controllers/users.js | 56 +-------------------------------- models/users.js | 20 ------------ routes/users.js | 3 -- test/unit/utils/users.test.js | 58 ----------------------------------- 5 files changed, 2 insertions(+), 137 deletions(-) diff --git a/constants/roles.js b/constants/roles.js index a4e5f13b5..d28e484a0 100644 --- a/constants/roles.js +++ b/constants/roles.js @@ -4,7 +4,7 @@ const ROLES = { APPOWNER: "app_owner", MEMBER: "member", ARCHIVED: "archived", - IN_DISCORD: "inDiscord", + INDISCORD: "in_discord", }; module.exports = ROLES; diff --git a/controllers/users.js b/controllers/users.js index 755eaf9ba..4db6a2ae3 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -8,12 +8,10 @@ const { logType } = require("../constants/logs"); const logger = require("../utils/logger"); const obfuscate = require("../utils/obfuscate"); -const { getPaginationLink, getUsernamesFromPRs, mapDiscordMembersDataAndSyncRole } = require("../utils/users"); +const { getPaginationLink, getUsernamesFromPRs } = require("../utils/users"); const { getQualifiers } = require("../utils/helper"); const { SOMETHING_WENT_WRONG, INTERNAL_SERVER_ERROR } = require("../constants/errorMessages"); const { getFilteredPRsOrIssues } = require("../utils/pullRequests"); -const { IN_DISCORD } = require("../constants/roles"); -const jwt = require("jsonwebtoken"); const verifyUser = async (req, res) => { const userId = req.userData.id; @@ -467,55 +465,6 @@ const filterUsers = async (req, res) => { return res.boom.serverUnavailable("Something went wrong please contact admin"); } }; -const DISCORD_BASE_URL = "https://89d4-49-36-233-201.ngrok.io"; -const syncInDiscordRole = async (req, res) => { - try { - const authToken = jwt.sign({}, config.get("botToken.botPrivateKey"), { - algorithm: "RS256", - }); - - const response = await fetch(`${DISCORD_BASE_URL}/discord-members`, { - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${authToken}`, - }, - }); - const discordMembers = await response.json(); - - const allUsers = await userQuery.getAllUsers(); - mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); - - return res.json({ message: "Synced with discord members " }); - } catch (error) { - logger.error(`Error while fetching all users: ${error}`); - return res.boom.serverUnavailable("Something went wrong please contact admin"); - } -}; - -const fetchVerifiedUsers = async (req, res) => { - try { - const verifiedUsers = await userQuery.fetchUsersWhereFieldNotNull("discordId"); - return res.json(verifiedUsers); - } catch (error) { - logger.error(`Error while fetching all users: ${error}`); - return res.boom.serverUnavailable("Something went wrong please contact admin"); - } -}; - -const fetchInDiscordUsers = async (req, res) => { - try { - const usersInDiscord = await userQuery.fetchUsersWithRole(IN_DISCORD); - - return res.json({ - message: "Users found successfully!", - users: usersInDiscord, - count: usersInDiscord.length, - }); - } catch (error) { - logger.error(`Error while fetching all users: ${error}`); - return res.boom.serverUnavailable("Something went wrong please contact admin"); - } -}; module.exports = { verifyUser, @@ -536,7 +485,4 @@ module.exports = { addDefaultArchivedRole, getUserSkills, filterUsers, - fetchInDiscordUsers, - syncInDiscordRole, - fetchVerifiedUsers, }; diff --git a/models/users.js b/models/users.js index bf28924f7..c52879b2b 100644 --- a/models/users.js +++ b/models/users.js @@ -414,22 +414,6 @@ const getUsersBasedOnFilter = async (query) => { const filteredUserDocs = userDocs.filter((doc) => !doc.roles?.archived); return filteredUserDocs; } - return []; -}; -const getAllUsers = async () => { - try { - const usersRef = await userModel.get(); - return usersRef; - } catch (err) { - logger.error("Error retrieving users data with roles of inDiscord", err); - throw err; - } -}; -const fetchUsersWithRole = async (role) => { - try { - // console.log(role); - const snapshot = await userModel.where(`roles.${role}`, "==", true).get(); - const onlyMembers = []; const roleQuery = query.role; const verifiedQuery = query.verified; @@ -447,7 +431,6 @@ const fetchUsersWithRole = async (role) => { return filteredUsers; } if (verifiedQuery) { - console.log(typeof verifiedQuery); const filteredUsers = []; const snapshot = await userModel.orderBy("discordId").get(); snapshot.forEach((doc) => { @@ -477,7 +460,4 @@ module.exports = { getRdsUserInfoByGitHubUsername, fetchUsers, getUsersBasedOnFilter, - fetchUsersWithRole, - fetchUsersWhereFieldNotNull, - getAllUsers, }; diff --git a/routes/users.js b/routes/users.js index 1900bd720..02b11c475 100644 --- a/routes/users.js +++ b/routes/users.js @@ -16,9 +16,6 @@ router.get("/self", authenticate, users.getSelfDetails); router.get("/isUsernameAvailable/:username", authenticate, users.getUsernameAvailabilty); router.get("/chaincode", authenticate, users.generateChaincode); router.get("/search", userValidator.validateUserQueryParams, users.filterUsers); -router.get("/inDiscord", authenticate, users.fetchInDiscordUsers); -router.post("/syncInDiscord", authenticate, users.syncInDiscordRole); -router.get("/verified", authenticate, users.fetchVerifiedUsers); router.get("/:username", users.getUser); router.get("/:userId/intro", authenticate, authorizeRoles([SUPERUSER]), users.getUserIntro); router.put("/self/intro", authenticate, userValidator.validateJoinData, users.addUserIntro); diff --git a/test/unit/utils/users.test.js b/test/unit/utils/users.test.js index 5a8fbdaf6..04298d6c2 100644 --- a/test/unit/utils/users.test.js +++ b/test/unit/utils/users.test.js @@ -1,8 +1,6 @@ const chai = require("chai"); const { expect } = chai; -const sinon = require("sinon"); - const usersUtils = require("../../../utils/users"); const cleanDb = require("../../utils/cleanDb"); const addUser = require("../../utils/addUser"); @@ -67,60 +65,4 @@ describe("users", function () { expect(participantUserId).to.include(userId); }); }); - - describe("mapDiscordMembersDataAndSyncRole", function () { - it("should update roles and joined_discord fields for users with matching Discord IDs", function () { - const allUsers = [ - { - data: () => ({ roles: { archived: false }, discordId: "123" }), - ref: { update: sinon.spy() }, - }, - ]; - const discordMembers = [ - { - user: { id: "123" }, - joined_at: "2022-05-01T00:00:00.000Z", - }, - ]; - - usersUtils.mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); - - sinon.assert.calledWithExactly(allUsers[0].ref.update, { - roles: { archived: false, inDiscord: true }, - joined_discord: discordMembers[0].joined_at, - }); - }); - - it("should update roles field to inDiscord: false for users with no matching Discord ID", function () { - const allUsers = [ - { - data: () => ({ roles: { archived: false }, discordId: "123" }), - ref: { update: sinon.spy() }, - }, - ]; - const discordMembers = []; - - usersUtils.mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); - - sinon.assert.calledWithExactly(allUsers[0].ref.update, { - roles: { archived: false, inDiscord: false }, - }); - }); - - it("should update roles field to inDiscord: false for users with archived roles", function () { - const allUsers = [ - { - data: () => ({ roles: { archived: true }, discordId: "123" }), - ref: { update: () => sinon.spy() }, - }, - ]; - const discordMembers = []; - - usersUtils.mapDiscordMembersDataAndSyncRole(allUsers, discordMembers); - - expect(allUsers[0].ref.update).to.have.been.calledWith({ - roles: { archived: true, inDiscord: false }, - }); - }); - }); }); From 6b013d7e8c574f7c766a8c722fef868fa3c75834 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Sun, 14 May 2023 21:57:03 +0530 Subject: [PATCH 19/36] chore: remove mapDiscordMembersDataAndSyncRole function --- utils/users.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/utils/users.js b/utils/users.js index b24e0336d..f3754d74e 100644 --- a/utils/users.js +++ b/utils/users.js @@ -142,29 +142,6 @@ function getUsernamesFromPRs(allPRs) { return usernames; } -function mapDiscordMembersDataAndSyncRole(allUsers, discordMembers) { - try { - allUsers.forEach((doc) => { - const user = doc.data(); - - if (user.roles.archived) { - const roles = user.roles ? { ...user.roles, inDiscord: false } : { inDiscord: false }; - doc.ref.update({ roles }); - } else if (user.discordId) { - const discordUserData = discordMembers.find((item) => item.user.id === user.discordId); - if (discordUserData) { - const roles = user.roles ? { ...user.roles, inDiscord: true } : { inDiscord: true }; - doc.ref.update({ roles, joined_discord: discordUserData.joined_at }); - } else { - const roles = user.roles ? { ...user.roles, inDiscord: false } : { inDiscord: false }; - doc.ref.update({ roles }); - } - } - }); - } catch (err) { - logger.error(err); - } -} module.exports = { addUserToDBForTest, @@ -175,5 +152,4 @@ module.exports = { getLowestLevelSkill, getPaginationLink, getUsernamesFromPRs, - mapDiscordMembersDataAndSyncRole, }; From 893d67268072f27175b016d5d925bc067e8e8a9c Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 19:46:25 +0530 Subject: [PATCH 20/36] handles internal server error gracefully --- constants/progresses.js | 4 +++- controllers/progresses.js | 17 ++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/constants/progresses.js b/constants/progresses.js index c3170eeb2..89ccc1d7c 100644 --- a/constants/progresses.js +++ b/constants/progresses.js @@ -3,6 +3,8 @@ const PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED = "Progress document retrieved succe const PROGRESS_DOCUMENT_NOT_FOUND = "No progress records found."; const PROGRESS_ALREADY_CREATED = "Progress for the day has already been created."; const MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000; +const INTERNAL_SERVER_ERROR_MESSAGE = + "The server has encountered an unexpected error. Please contact the administrator for more information."; const RESPONSE_MESSAGES = { PROGRESS_DOCUMENT_CREATED_SUCCEEDED, @@ -11,4 +13,4 @@ const RESPONSE_MESSAGES = { PROGRESS_ALREADY_CREATED, }; -module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY }; +module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY, INTERNAL_SERVER_ERROR_MESSAGE }; diff --git a/controllers/progresses.js b/controllers/progresses.js index ad544514d..68e0cba8d 100644 --- a/controllers/progresses.js +++ b/controllers/progresses.js @@ -1,6 +1,6 @@ const { Conflict, NotFound } = require("http-errors"); const { createProgressDocument, getProgressDocument, getRangeProgressData } = require("../models/progresses"); -const { RESPONSE_MESSAGES } = require("../constants/progresses"); +const { RESPONSE_MESSAGES, INTERNAL_SERVER_ERROR_MESSAGE } = require("../constants/progresses"); const { PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED, PROGRESS_DOCUMENT_CREATED_SUCCEEDED } = RESPONSE_MESSAGES; /** @@ -58,8 +58,9 @@ const createProgress = async (req, res) => { message: error.message, }); } - return res.status(400).json({ - message: error.message, + logger.error(error.message); + return res.status(500).json({ + message: INTERNAL_SERVER_ERROR_MESSAGE, }); } }; @@ -112,8 +113,9 @@ const getProgress = async (req, res) => { message: error.message, }); } - return res.status(400).json({ - message: error.message, + logger.error(error.message); + return res.status(500).json({ + message: INTERNAL_SERVER_ERROR_MESSAGE, }); } }; @@ -165,8 +167,9 @@ const getProgressRangeData = async (req, res) => { message: error.message, }); } - return res.status(400).json({ - message: error.message, + logger.error(error.message); + return res.status(500).json({ + message: INTERNAL_SERVER_ERROR_MESSAGE, }); } }; From 9580d54e0de021f8696ee2451e7f7b68baf152a6 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 20:02:27 +0530 Subject: [PATCH 21/36] add tests for 409 conflict --- test/integration/progressesTasks.test.js | 2 +- test/integration/progressesUsers.test.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/integration/progressesTasks.test.js b/test/integration/progressesTasks.test.js index 5a4f303d7..56aa3ab17 100644 --- a/test/integration/progressesTasks.test.js +++ b/test/integration/progressesTasks.test.js @@ -21,7 +21,7 @@ const cookieName = config.get("userToken.cookieName"); const { expect } = chai; // eslint-disable-next-line mocha/no-skipped-tests -describe.skip("Test Progress Updates API for Tasks", function () { +describe("Test Progress Updates API for Tasks", function () { afterEach(async function () { await cleanDb(); }); diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index ecac4a121..5ace12b16 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -19,7 +19,7 @@ const cookieName = config.get("userToken.cookieName"); const { expect } = chai; // eslint-disable-next-line mocha/no-skipped-tests -describe.skip("Test Progress Updates API for Users", function () { +describe("Test Progress Updates API for Users", function () { afterEach(async function () { await cleanDb(); }); @@ -74,6 +74,10 @@ describe.skip("Test Progress Updates API for Users", function () { }); it("throws Conflict Error 409 if the user tries to update progress multiple times in a single day", function (done) { + const timezoneOffset = new Date().getTimezoneOffset(); + const timeNow = new Date().getTime(); + // eslint-disable-next-line no-console + console.log({ timezoneOffset, timeNow }); chai .request(app) .post(`/progresses`) From 7310985b1684bd1ee6c8caa4a73320bf9f96f995 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 20:54:00 +0530 Subject: [PATCH 22/36] fixes the timezone offset --- test/integration/progressesTasks.test.js | 2 +- test/integration/progressesUsers.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/progressesTasks.test.js b/test/integration/progressesTasks.test.js index 56aa3ab17..2e380ed9c 100644 --- a/test/integration/progressesTasks.test.js +++ b/test/integration/progressesTasks.test.js @@ -34,7 +34,7 @@ describe("Test Progress Updates API for Tasks", function () { let taskId2; beforeEach(async function () { clock = sinon.useFakeTimers({ - now: new Date(2023, 4, 2, 5, 55).getTime(), + now: new Date(Date.UTC(2023, 4, 2, 0, 25)).getTime(), // UTC time equivalent to 5:55 AM IST toFake: ["Date"], }); userId = await addUser(userData[1]); diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index 5ace12b16..40089cf28 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -32,7 +32,7 @@ describe("Test Progress Updates API for Users", function () { let anotherUserToken; beforeEach(async function () { clock = sinon.useFakeTimers({ - now: new Date(2023, 4, 2, 5, 55).getTime(), + now: new Date(Date.UTC(2023, 4, 2, 0, 25)).getTime(), // UTC time equivalent to 5:55 AM IST toFake: ["Date"], }); userId = await addUser(userData[1]); From 3829b53b3b51fd331caf6c677d6b3f44f92a2f51 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 20:56:22 +0530 Subject: [PATCH 23/36] remove the console logs --- test/integration/progressesUsers.test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index 40089cf28..b12102307 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -74,10 +74,6 @@ describe("Test Progress Updates API for Users", function () { }); it("throws Conflict Error 409 if the user tries to update progress multiple times in a single day", function (done) { - const timezoneOffset = new Date().getTimezoneOffset(); - const timeNow = new Date().getTime(); - // eslint-disable-next-line no-console - console.log({ timezoneOffset, timeNow }); chai .request(app) .post(`/progresses`) From 16e15c70ef9cf724f74aaf693c05421b87492103 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 21:29:40 +0530 Subject: [PATCH 24/36] added new line at the end of the file --- controllers/progresses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/progresses.js b/controllers/progresses.js index a0d20ad2a..e0e466736 100644 --- a/controllers/progresses.js +++ b/controllers/progresses.js @@ -233,4 +233,4 @@ const getProgressBydDateController = async (req, res) => { } }; -module.exports = { createProgress, getProgress, getProgressRangeData, getProgressBydDateController }; \ No newline at end of file +module.exports = { createProgress, getProgress, getProgressRangeData, getProgressBydDateController }; From 96946c6d3705fb23e73c62f541ded1ca603e5a14 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 22:28:28 +0530 Subject: [PATCH 25/36] add test for retrieving progress document for the user on a particular date --- test/integration/progressesUsers.test.js | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index b12102307..33e4e5ed9 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -294,4 +294,76 @@ describe("Test Progress Updates API for Users", function () { }); }); }); + + describe("Verify the GET endpoint for retrieving progress document for the user on a particular date", function () { + let userId; + let anotherUserId; + + beforeEach(async function () { + userId = await addUser(userData[0]); + anotherUserId = await addUser(userData[1]); + const progressData = stubbedModelProgressData(userId, 1683072000000, 1682985600000); + await firestore.collection("progresses").doc("progressDoc").set(progressData); + }); + + it("Returns the progress data for a specific user", function (done) { + chai + .request(app) + .get(`/progresses/user/${userId}/date/2023-05-02`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(200); + expect(res.body).to.have.keys(["message", "data"]); + expect(res.body.data).to.be.an("object"); + expect(res.body.message).to.be.equal("Progress document retrieved successfully."); + expect(res.body.data).to.have.keys([ + "id", + "type", + "completed", + "planned", + "blockers", + "userId", + "createdAt", + "date", + ]); + return done(); + }); + }); + + it("Returns 400 for bad request", function (done) { + chai + .request(app) + .get(`/progresses/user/${userId}/date/2023-05-33`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(400); + expect(res.body.message).to.be.equal('"date" must be in ISO 8601 date format'); + return done(); + }); + }); + + it("Returns 404 for invalid user id", function (done) { + chai + .request(app) + .get(`/progresses/user/invalidUserId/date/2023-05-02`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(404); + expect(res.body.message).to.be.equal("User with id invalidUserId does not exist."); + return done(); + }); + }); + + it("Returns 404 if the progress document doesn't exist for the users", function (done) { + chai + .request(app) + .get(`/progresses/user/${anotherUserId}/date/2023-05-02`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(404); + expect(res.body.message).to.be.equal("No progress records found."); + return done(); + }); + }); + }); }); From 7a438977690cb47f3696a6fe8b83419cb96ec2c3 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 22:42:12 +0530 Subject: [PATCH 26/36] add test for retrieving progress document for the task on a particular date --- test/integration/progressesTasks.test.js | 77 ++++++++++++++++++++++++ test/integration/progressesUsers.test.js | 2 +- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/test/integration/progressesTasks.test.js b/test/integration/progressesTasks.test.js index 2e380ed9c..f7b5776f7 100644 --- a/test/integration/progressesTasks.test.js +++ b/test/integration/progressesTasks.test.js @@ -319,4 +319,81 @@ describe("Test Progress Updates API for Tasks", function () { }); }); }); + + describe("Verify the GET endpoint for retrieving progress document for the user on a particular date", function () { + let userId; + let taskId; + let anotherTaskId; + + beforeEach(async function () { + userId = await addUser(userData[0]); + const taskObject = await tasks.updateTask(taskData[0]); + taskId = taskObject.taskId; + const anotherTaskObject = await tasks.updateTask(taskData[0]); + anotherTaskId = anotherTaskObject.taskId; + const progressData = stubbedModelTaskProgressData(userId, taskId, 1683072000000, 1682985600000); + await firestore.collection("progresses").doc("progressDoc").set(progressData); + }); + + it("Returns the progress data for a specific task", function (done) { + chai + .request(app) + .get(`/progresses/task/${taskId}/date/2023-05-02`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(200); + expect(res.body).to.have.keys(["message", "data"]); + expect(res.body.data).to.be.an("object"); + expect(res.body.message).to.be.equal("Progress document retrieved successfully."); + expect(res.body.data).to.have.keys([ + "id", + "type", + "completed", + "planned", + "blockers", + "userId", + "taskId", + "createdAt", + "date", + ]); + return done(); + }); + }); + + it("Returns 400 for bad request", function (done) { + chai + .request(app) + .get(`/progresses/task/${taskId}/date/2023-05-33`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(400); + expect(res.body.message).to.be.equal('"date" must be in ISO 8601 date format'); + return done(); + }); + }); + + it("Returns 404 for invalid task id", function (done) { + chai + .request(app) + .get(`/progresses/task/invalidTaskId/date/2023-05-02`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(404); + expect(res.body.message).to.be.equal("Task with id invalidTaskId does not exist."); + return done(); + }); + }); + + it("Returns 404 if the progress document doesn't exist for the task", function (done) { + chai + .request(app) + .get(`/progresses/task/${anotherTaskId}/date/2023-05-02`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(404); + expect(res.body.message).to.be.equal("No progress records found."); + return done(); + }); + }); + }); }); diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index 33e4e5ed9..6455fe690 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -354,7 +354,7 @@ describe("Test Progress Updates API for Users", function () { }); }); - it("Returns 404 if the progress document doesn't exist for the users", function (done) { + it("Returns 404 if the progress document doesn't exist for the user", function (done) { chai .request(app) .get(`/progresses/user/${anotherUserId}/date/2023-05-02`) From 9f74941056d13b39fbf9a0e17d97d30f972d30e5 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Mon, 15 May 2023 22:49:17 +0530 Subject: [PATCH 27/36] Add test for user,task for 404 No progress records found --- test/integration/progressesTasks.test.js | 14 ++++++++++++++ test/integration/progressesUsers.test.js | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/test/integration/progressesTasks.test.js b/test/integration/progressesTasks.test.js index f7b5776f7..7f18f36ab 100644 --- a/test/integration/progressesTasks.test.js +++ b/test/integration/progressesTasks.test.js @@ -360,6 +360,20 @@ describe("Test Progress Updates API for Tasks", function () { }); }); + it("Should return 404 No progress records found if the document doesn't exist", function (done) { + chai + .request(app) + .get(`/progresses/task/${taskId}/date/2023-05-03`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(404); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.key("message"); + expect(res.body.message).to.be.equal("No progress records found."); + return done(); + }); + }); + it("Returns 400 for bad request", function (done) { chai .request(app) diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index 6455fe690..f5cfea944 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -330,6 +330,20 @@ describe("Test Progress Updates API for Users", function () { }); }); + it("Should return 404 No progress records found if the document doesn't exist", function (done) { + chai + .request(app) + .get(`/progresses/user/${userId}/date/2023-05-03`) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(404); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.key("message"); + expect(res.body.message).to.be.equal("No progress records found."); + return done(); + }); + }); + it("Returns 400 for bad request", function (done) { chai .request(app) From 07d57beb46fd83b29a79f5ea145576c78670d63f Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Tue, 16 May 2023 07:12:02 +0530 Subject: [PATCH 28/36] add 4 more tests to increase the test robustness --- test/integration/progressesTasks.test.js | 32 +++++++++++++++++++++++- test/integration/progressesUsers.test.js | 32 +++++++++++++++++++++++- utils/progresses.js | 2 +- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/test/integration/progressesTasks.test.js b/test/integration/progressesTasks.test.js index 7f18f36ab..89629eec0 100644 --- a/test/integration/progressesTasks.test.js +++ b/test/integration/progressesTasks.test.js @@ -52,7 +52,7 @@ describe("Test Progress Updates API for Tasks", function () { clock.restore(); }); - it("Stores the progress entry for the task", function (done) { + it("Stores the task progress entry", function (done) { chai .request(app) .post(`/progresses`) @@ -80,6 +80,36 @@ describe("Test Progress Updates API for Tasks", function () { }); }); + it("stores the user progress document for the previous day if the update is sent before 6am IST", function (done) { + clock.setSystemTime(new Date(Date.UTC(2023, 4, 2, 0, 29)).getTime()); // 2nd May 2023 05:59 am IST + chai + .request(app) + .post(`/progresses`) + .set("cookie", `${cookieName}=${userToken}`) + .send(taskProgressDay1(taskId2)) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(201); + expect(res.body.data.date).to.be.equal(1682899200000); // 1st May 2023 + return done(); + }); + }); + + it("stores the user progress document for the current day if the update is sent after 6am IST", function (done) { + clock.setSystemTime(new Date(Date.UTC(2023, 4, 2, 0, 31)).getTime()); // 2nd May 2023 06:01 am IST + chai + .request(app) + .post(`/progresses`) + .set("cookie", `${cookieName}=${userToken}`) + .send(taskProgressDay1(taskId2)) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(201); + expect(res.body.data.date).to.be.equal(1682985600000); // 2nd May 2023 + return done(); + }); + }); + it("throws Conflict Error 409 if the task progress is updated multiple times in a day", function (done) { chai .request(app) diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index f5cfea944..523e0f213 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -47,7 +47,7 @@ describe("Test Progress Updates API for Users", function () { clock.restore(); }); - it("stores the user progress document for the first time", function (done) { + it("stores the user progress document", function (done) { chai .request(app) .post(`/progresses`) @@ -73,6 +73,36 @@ describe("Test Progress Updates API for Users", function () { }); }); + it("stores the user progress document for the previous day if the update is sent before 6am IST", function (done) { + clock.setSystemTime(new Date(Date.UTC(2023, 4, 2, 0, 29)).getTime()); // 2nd May 2023 05:59 am IST + chai + .request(app) + .post(`/progresses`) + .set("cookie", `${cookieName}=${userToken}`) + .send(standupProgressDay1) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(201); + expect(res.body.data.date).to.be.equal(1682899200000); // 1st May 2023 + return done(); + }); + }); + + it("stores the user progress document for the current day if the update is sent after 6am IST", function (done) { + clock.setSystemTime(new Date(Date.UTC(2023, 4, 2, 0, 31)).getTime()); // 2nd May 2023 06:01 am IST + chai + .request(app) + .post(`/progresses`) + .set("cookie", `${cookieName}=${userToken}`) + .send(standupProgressDay1) + .end((err, res) => { + if (err) return done(err); + expect(res).to.have.status(201); + expect(res.body.data.date).to.be.equal(1682985600000); // 2nd May 2023 + return done(); + }); + }); + it("throws Conflict Error 409 if the user tries to update progress multiple times in a single day", function (done) { chai .request(app) diff --git a/utils/progresses.js b/utils/progresses.js index 251616416..1eddc8462 100644 --- a/utils/progresses.js +++ b/utils/progresses.js @@ -16,7 +16,7 @@ const progressesCollection = fireStore.collection("progresses"); const getProgressDateTimestamp = () => { // Currently, we are primarily catering to Indian users for our apps, which is why we have implemented support for the IST (Indian Standard Time) timezone for progress updates. const currentHourIST = new Date().getUTCHours() + 5.5; // IST offset is UTC+5:30; - const isBefore6amIST = currentHourIST < 6; + const isBefore6amIST = currentHourIST === 5.5 && new Date().getUTCMinutes() <= 30; return isBefore6amIST ? new Date().setUTCHours(0, 0, 0, 0) - MILLISECONDS_IN_DAY : new Date().setUTCHours(0, 0, 0, 0); }; From 3e75de8a3c99916c769680be8b23c93d0b4447e5 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Tue, 16 May 2023 07:18:53 +0530 Subject: [PATCH 29/36] adds more strict check on time calculation --- utils/progresses.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/progresses.js b/utils/progresses.js index e56e6ab74..acddab941 100644 --- a/utils/progresses.js +++ b/utils/progresses.js @@ -16,7 +16,7 @@ const progressesCollection = fireStore.collection("progresses"); const getProgressDateTimestamp = () => { // Currently, we are primarily catering to Indian users for our apps, which is why we have implemented support for the IST (Indian Standard Time) timezone for progress updates. const currentHourIST = new Date().getUTCHours() + 5.5; // IST offset is UTC+5:30; - const isBefore6amIST = currentHourIST < 6; + const isBefore6amIST = currentHourIST === 5.5 && new Date().getUTCMinutes() <= 30; return isBefore6amIST ? new Date().setUTCHours(0, 0, 0, 0) - MILLISECONDS_IN_DAY : new Date().setUTCHours(0, 0, 0, 0); }; From 4c3be0502fc0031f52d7dc30b80392f787c31c60 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Tue, 16 May 2023 21:16:47 +0530 Subject: [PATCH 30/36] remove es lint warning message --- test/integration/progressesTasks.test.js | 1 - test/integration/progressesUsers.test.js | 1 - 2 files changed, 2 deletions(-) diff --git a/test/integration/progressesTasks.test.js b/test/integration/progressesTasks.test.js index 2e380ed9c..c62aa4fd0 100644 --- a/test/integration/progressesTasks.test.js +++ b/test/integration/progressesTasks.test.js @@ -20,7 +20,6 @@ const taskData = require("../fixtures/tasks/tasks")(); const cookieName = config.get("userToken.cookieName"); const { expect } = chai; -// eslint-disable-next-line mocha/no-skipped-tests describe("Test Progress Updates API for Tasks", function () { afterEach(async function () { await cleanDb(); diff --git a/test/integration/progressesUsers.test.js b/test/integration/progressesUsers.test.js index b12102307..59d7cb783 100644 --- a/test/integration/progressesUsers.test.js +++ b/test/integration/progressesUsers.test.js @@ -18,7 +18,6 @@ const userData = require("../fixtures/user/user")(); const cookieName = config.get("userToken.cookieName"); const { expect } = chai; -// eslint-disable-next-line mocha/no-skipped-tests describe("Test Progress Updates API for Users", function () { afterEach(async function () { await cleanDb(); From cf520e19972242eb920d6f5764bb2c879aa1825c Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Wed, 17 May 2023 18:52:31 +0530 Subject: [PATCH 31/36] write test for brew install redis --- models/users.js | 8 ++++---- test/fixtures/user/user.js | 4 ++++ test/unit/models/users.test.js | 12 ++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/models/users.js b/models/users.js index c52879b2b..f4b158620 100644 --- a/models/users.js +++ b/models/users.js @@ -428,11 +428,11 @@ const getUsersBasedOnFilter = async (query) => { }); }); - return filteredUsers; + return filteredUsers.filter((user) => !user.roles?.archived); } - if (verifiedQuery) { + if (verifiedQuery === "true") { const filteredUsers = []; - const snapshot = await userModel.orderBy("discordId").get(); + const snapshot = await userModel.where("discordId", "!=", null).get(); snapshot.forEach((doc) => { filteredUsers.push({ id: doc.id, @@ -440,7 +440,7 @@ const getUsersBasedOnFilter = async (query) => { }); }); - return filteredUsers; + return filteredUsers.filter((user) => !user.roles?.archived); } return []; }; diff --git a/test/fixtures/user/user.js b/test/fixtures/user/user.js index 94d9d7f9d..e46c6eafe 100644 --- a/test/fixtures/user/user.js +++ b/test/fixtures/user/user.js @@ -21,8 +21,10 @@ module.exports = () => { isMember: true, phone: "1234567890", email: "abc@gmail.com", + joined_discord: "2023-01-13T18:21:09.278000+00:00", roles: { member: true, + in_discord: true, }, tokens: { githubAccessToken: "githubAccessToken", @@ -105,6 +107,7 @@ module.exports = () => { github_display_name: "Ankush Dharkar", phone: "1234567890", email: "ad@amazon.com", + joined_discord: "2023-01-13T18:21:09.278000+00:00", status: "idle", tokens: { githubAccessToken: "githubAccessToken", @@ -112,6 +115,7 @@ module.exports = () => { roles: { super_user: true, archived: false, + in_discord: true, }, picture: { publicId: "profile/mtS4DhUvNYsKqI7oCWVB/aenklfhtjldc5ytei3ar", diff --git a/test/unit/models/users.test.js b/test/unit/models/users.test.js index 728f267c9..04d081d63 100644 --- a/test/unit/models/users.test.js +++ b/test/unit/models/users.test.js @@ -88,4 +88,16 @@ describe("users", function () { expect(userExists).to.equal(true); }); }); + + describe("brew install redis", function () { + it("should return an empty array if no query is provided", async function () { + const result = await users.getUsersBasedOnFilter({}); + expect(result).to.deep.equal([]); + }); + + it("should return an array of verified users", async function () { + const result = await users.getUsersBasedOnFilter({ verified: "true" }); + expect(result).to.deep.equal(userDataArray.filter((user) => user.discordId)); + }); + }); }); From 9e9514808b0d49236c4a44e146f0d1bdd454a134 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Wed, 17 May 2023 19:43:05 +0530 Subject: [PATCH 32/36] resolve comments by @DashDeipayan in the PR --- constants/progresses.js | 10 +++++++++- middlewares/validators/progresses.js | 14 ++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/constants/progresses.js b/constants/progresses.js index 134877315..278e5bc90 100644 --- a/constants/progresses.js +++ b/constants/progresses.js @@ -18,4 +18,12 @@ const TYPE_MAP = { task: "taskId", }; -module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY, INTERNAL_SERVER_ERROR_MESSAGE, TYPE_MAP }; +const VALID_PROGRESS_TYPES = ["task", "user"]; + +module.exports = { + RESPONSE_MESSAGES, + MILLISECONDS_IN_DAY, + INTERNAL_SERVER_ERROR_MESSAGE, + TYPE_MAP, + VALID_PROGRESS_TYPES, +}; diff --git a/middlewares/validators/progresses.js b/middlewares/validators/progresses.js index abd584128..dd5865f10 100644 --- a/middlewares/validators/progresses.js +++ b/middlewares/validators/progresses.js @@ -1,14 +1,20 @@ const joi = require("joi"); +const { VALID_PROGRESS_TYPES } = require("../../constants/progresses"); const validateCreateProgressRecords = async (req, res, next) => { const baseSchema = joi .object() .strict() .keys({ - type: joi.string().trim().valid("user", "task").required().messages({ - "any.required": "Required field 'type' is missing.", - "any.only": "Type field is restricted to either 'user' or 'task'.", - }), + type: joi + .string() + .trim() + .valid(...VALID_PROGRESS_TYPES) + .required() + .messages({ + "any.required": "Required field 'type' is missing.", + "any.only": "Type field is restricted to either 'user' or 'task'.", + }), completed: joi.string().trim().required().messages({ "any.required": "Required field 'completed' is missing.", "string.trim": "completed must not have leading or trailing whitespace", From c8cccd8fe744154aa52af4a63f8c559e2f704927 Mon Sep 17 00:00:00 2001 From: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> Date: Wed, 17 May 2023 19:48:35 +0530 Subject: [PATCH 33/36] fixed the comments by @DashDeipayan in all 3 validator function --- middlewares/validators/progresses.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/middlewares/validators/progresses.js b/middlewares/validators/progresses.js index dd5865f10..2cad2c606 100644 --- a/middlewares/validators/progresses.js +++ b/middlewares/validators/progresses.js @@ -50,9 +50,13 @@ const validateCreateProgressRecords = async (req, res, next) => { const validateGetProgressRecordsQuery = async (req, res, next) => { const schema = joi .object({ - type: joi.string().valid("user", "task").optional().messages({ - "any.only": "Type field is restricted to either 'user' or 'task'.", - }), + type: joi + .string() + .valid(...VALID_PROGRESS_TYPES) + .optional() + .messages({ + "any.only": "Type field is restricted to either 'user' or 'task'.", + }), userId: joi.string().optional().allow("").messages({ "string.base": "userId must be a string", }), @@ -101,9 +105,13 @@ const validateGetRangeProgressRecordsParams = async (req, res, next) => { const validateGetDayProgressParams = async (req, res, next) => { const schema = joi.object({ - type: joi.string().valid("user", "task").required().messages({ - "any.only": "Type field is restricted to either 'user' or 'task'.", - }), + type: joi + .string() + .valid(...VALID_PROGRESS_TYPES) + .required() + .messages({ + "any.only": "Type field is restricted to either 'user' or 'task'.", + }), typeId: joi.string().required(), date: joi.date().iso().required(), }); From e1ef0de07b7b7e5814216f1d0e4ba46b9c5f0895 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Thu, 18 May 2023 20:24:02 +0530 Subject: [PATCH 34/36] chore: change test description --- test/unit/models/users.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/models/users.test.js b/test/unit/models/users.test.js index 04d081d63..747015fed 100644 --- a/test/unit/models/users.test.js +++ b/test/unit/models/users.test.js @@ -89,7 +89,7 @@ describe("users", function () { }); }); - describe("brew install redis", function () { + describe(" search users API: getUsersBasedOnFilter", function () { it("should return an empty array if no query is provided", async function () { const result = await users.getUsersBasedOnFilter({}); expect(result).to.deep.equal([]); From 70a0d199fa13d884451b78b42ca4d5588985c910 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Thu, 18 May 2023 20:57:48 +0530 Subject: [PATCH 35/36] chore: address comments --- models/users.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/models/users.js b/models/users.js index f4b158620..0d4ba5b15 100644 --- a/models/users.js +++ b/models/users.js @@ -360,8 +360,8 @@ const getRdsUserInfoByGitHubUsername = async (githubUsername) => { * @param {Array} query.levelNumber - Array of levelNumbers to filter the users on * @param {Array} query.tagId - Array of tagIds to filter the users on * @param {Array} query.state - Array of states to filter the users on - * @param {String} query.role - filter the users on - * @param {String} query.verified - filter the users on + * @param {String} query.role - filter the users on role + * @param {String} query.verified - filter the users on verified i.e, discordId data * @return {Promise} - Array of user documents that match the filter criteria */ @@ -415,8 +415,7 @@ const getUsersBasedOnFilter = async (query) => { return filteredUserDocs; } - const roleQuery = query.role; - const verifiedQuery = query.verified; + const { role: roleQuery, verified: verifiedQuery } = query; if (roleQuery) { const filteredUsers = []; From 9aa1166a57abf26df8d1e7e7b355d15440229700 Mon Sep 17 00:00:00 2001 From: Bhavika Tibrewal Date: Thu, 18 May 2023 22:05:41 +0530 Subject: [PATCH 36/36] chore: use roles constant in validation --- middlewares/validators/user.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/middlewares/validators/user.js b/middlewares/validators/user.js index d1172f42c..ac91998d0 100644 --- a/middlewares/validators/user.js +++ b/middlewares/validators/user.js @@ -1,5 +1,6 @@ const joi = require("joi"); const { USER_STATUS } = require("../../constants/users"); +const ROLES = require("../../constants/roles"); const updateUser = async (req, res, next) => { const schema = joi @@ -172,7 +173,7 @@ async function validateUserQueryParams(req, res, next) { joi.array().items(joi.string().valid("IDLE", "OOO", "ACTIVE")) ) .optional(), - role: joi.string().valid("in_discord", "member").optional(), + role: joi.string().valid(ROLES.MEMBER, ROLES.INDISCORD).optional(), verified: joi.string().optional(), }) .messages({