Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Integrate userData into Progresses API to reduce redundant calls #2311

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
2 changes: 1 addition & 1 deletion controllers/progresses.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ const getProgressRangeData = async (req, res) => {

const getProgressBydDateController = async (req, res) => {
try {
const data = await getProgressByDate(req.params);
const data = await getProgressByDate(req.params, req.query);
return res.json({
message: PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED,
data,
Expand Down
5 changes: 5 additions & 0 deletions middlewares/validators/progresses.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ const validateGetProgressRecordsQuery = async (req, res, next) => {
taskId: joi.string().optional().allow("").messages({
"string.base": "taskId must be a string",
}),
dev: joi.boolean().optional().messages({
"boolean.base": "dev must be a boolean value (true or false).",
}),
orderBy: joi
.string()
.optional()
Expand Down Expand Up @@ -92,6 +95,7 @@ const validateGetRangeProgressRecordsParams = async (req, res, next) => {
taskId: joi.string().optional(),
startDate: joi.date().iso().required(),
endDate: joi.date().iso().min(joi.ref("startDate")).required(),
dev: joi.boolean().optional(),
})
.xor("userId", "taskId")
.messages({
Expand Down Expand Up @@ -121,6 +125,7 @@ const validateGetDayProgressParams = async (req, res, next) => {
}),
typeId: joi.string().required(),
date: joi.date().iso().required(),
dev: joi.boolean().optional(),
});
try {
await schema.validateAsync(req.params, { abortEarly: false });
Expand Down
34 changes: 32 additions & 2 deletions models/progresses.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
getProgressDateTimestamp,
buildQueryToSearchProgressByDay,
} = require("../utils/progresses");
const { fetchUser } = require("./users");
const { PROGRESS_ALREADY_CREATED, PROGRESS_DOCUMENT_NOT_FOUND } = PROGRESSES_RESPONSE_MESSAGES;

/**
Expand Down Expand Up @@ -47,9 +48,31 @@
* @throws {Error} If the userId or taskId is invalid or does not exist.
**/
const getProgressDocument = async (queryParams) => {
const { dev } = queryParams;
await assertUserOrTaskExists(queryParams);
const query = buildQueryToFetchDocs(queryParams);
const progressDocs = await getProgressDocs(query);

if (dev) {
try {
const uniqueUserIds = [...new Set(progressDocs.map((doc) => doc.userId))];
const usersData = await Promise.all(uniqueUserIds.map((userId) => fetchUser({ userId })));

Achintya-Chatterjee marked this conversation as resolved.
Show resolved Hide resolved
const userLookupMap = usersData.reduce((lookup, { user }) => {
if (user) lookup[user.id] = user;
return lookup;
}, {});

const progressDocsWithUserDetails = progressDocs.map((doc) => {
const userDetails = userLookupMap[doc.userId] || null;
return { ...doc, userData: userDetails };
});

return progressDocsWithUserDetails;
} catch (err) {
return progressDocs.map((doc) => ({ ...doc, userData: null }));
}
}
return progressDocs;
};

Expand Down Expand Up @@ -77,16 +100,23 @@
* @returns {Promise<object>} 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) {
async function getProgressByDate(pathParams, queryParams) {
const { type, typeId, date } = pathParams;
const { dev } = queryParams;
await assertUserOrTaskExists({ [TYPE_MAP[type]]: typeId });

Check warning on line 106 in models/progresses.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Generic Object Injection Sink
const query = buildQueryToSearchProgressByDay({ [TYPE_MAP[type]]: typeId, date });

Check warning on line 107 in models/progresses.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Generic Object Injection Sink
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() };
const docData = doc.data();
if (dev) {
const { user: userData } = await fetchUser({ userId: docData.userId });
return { id: doc.id, ...docData, userData };
}

return { id: doc.id, ...docData };
}

module.exports = { createProgressDocument, getProgressDocument, getRangeProgressData, getProgressByDate };
57 changes: 57 additions & 0 deletions test/integration/progressesTasks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,34 @@ describe("Test Progress Updates API for Tasks", function () {
});
});

it("Returns the progress array for the task with userData object", function (done) {
chai
.request(app)
Achintya-Chatterjee marked this conversation as resolved.
Show resolved Hide resolved
.get(`/progresses?taskId=${taskId1}&dev=true`)
.end((err, res) => {
if (err) return done(err);
expect(res).to.have.status(200);
expect(res.body).to.have.keys(["message", "data", "count"]);
expect(res.body.data).to.be.an("array");
expect(res.body.message).to.be.equal("Progress document retrieved successfully.");
res.body.data.forEach((progress) => {
expect(progress).to.have.keys([
"id",
"taskId",
"type",
"completed",
"planned",
"blockers",
"userData",
"userId",
"createdAt",
"date",
]);
});
return done();
});
});

it("Gives 400 status when anything other than -date or date is supplied", function (done) {
chai
.request(app)
Expand Down Expand Up @@ -311,6 +339,35 @@ describe("Test Progress Updates API for Tasks", function () {
});
});

it("Returns the progress array for all the tasks with userData object", function (done) {
chai
.request(app)
.get(`/progresses?type=task&dev=true`)
.end((err, res) => {
if (err) return done(err);
expect(res).to.have.status(200);
expect(res.body).to.have.keys(["message", "data", "count"]);
expect(res.body.data).to.be.an("array");
expect(res.body.message).to.be.equal("Progress document retrieved successfully.");
expect(res.body.count).to.be.equal(4);
res.body.data.forEach((progress) => {
expect(progress).to.have.keys([
"id",
"taskId",
"type",
"completed",
"planned",
"blockers",
"userData",
"userId",
"createdAt",
"date",
]);
});
return done();
});
});

it("Returns 400 for bad request", function (done) {
chai
.request(app)
Expand Down
79 changes: 79 additions & 0 deletions test/integration/progressesUsers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,60 @@ describe("Test Progress Updates API for Users", function () {
});
});

it("Returns the progress array for a specific user with userData object", function (done) {
chai
.request(app)
.get(`/progresses?userId=${userId1}&dev=true`)
.end((err, res) => {
if (err) return done(err);
expect(res).to.have.status(200);
expect(res.body).to.have.keys(["message", "data", "count"]);
expect(res.body.data).to.be.an("array");
expect(res.body.message).to.be.equal("Progress document retrieved successfully.");
res.body.data.forEach((progress) => {
expect(progress).to.have.keys([
"id",
"type",
"completed",
"planned",
"blockers",
"userId",
"userData",
"createdAt",
"date",
]);
});
return done();
});
});

it("Returns the progress array for all the user with userData object when dev is true", function (done) {
chai
.request(app)
.get(`/progresses?type=user&dev=true`)
.end((err, res) => {
if (err) return done(err);
expect(res).to.have.status(200);
expect(res.body).to.have.keys(["message", "data", "count"]);
expect(res.body.data).to.be.an("array");
expect(res.body.message).to.be.equal("Progress document retrieved successfully.");
res.body.data.forEach((progress) => {
expect(progress).to.have.keys([
"id",
"type",
"completed",
"planned",
"blockers",
"userId",
"userData",
"createdAt",
"date",
]);
});
return done();
});
});

it("Returns 400 for bad request", function (done) {
chai
.request(app)
Expand Down Expand Up @@ -370,6 +424,31 @@ describe("Test Progress Updates API for Users", function () {
});
});

it("Returns the progress data for a specific user with userData object", function (done) {
chai
.request(app)
.get(`/progresses/user/${userId}/date/2023-05-02?dev=true`)
.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",
"userData",
"userId",
"createdAt",
"date",
]);
return done();
});
});

it("Should return 404 No progress records found if the document doesn't exist", function (done) {
chai
.request(app)
Expand Down
Loading