Skip to content

Commit 46a6179

Browse files
Merge pull request #1104 from Real-Dev-Squad/develop
dev to main sync
2 parents c1722bc + a4952ed commit 46a6179

File tree

19 files changed

+550
-40
lines changed

19 files changed

+550
-40
lines changed

constants/progresses.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ const PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED = "Progress document retrieved succe
33
const PROGRESS_DOCUMENT_NOT_FOUND = "No progress records found.";
44
const PROGRESS_ALREADY_CREATED = "Progress for the day has already been created.";
55
const MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
6+
const INTERNAL_SERVER_ERROR_MESSAGE =
7+
"The server has encountered an unexpected error. Please contact the administrator for more information.";
68

79
const RESPONSE_MESSAGES = {
810
PROGRESS_DOCUMENT_CREATED_SUCCEEDED,
@@ -11,4 +13,17 @@ const RESPONSE_MESSAGES = {
1113
PROGRESS_ALREADY_CREATED,
1214
};
1315

14-
module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY };
16+
const TYPE_MAP = {
17+
user: "userId",
18+
task: "taskId",
19+
};
20+
21+
const VALID_PROGRESS_TYPES = ["task", "user"];
22+
23+
module.exports = {
24+
RESPONSE_MESSAGES,
25+
MILLISECONDS_IN_DAY,
26+
INTERNAL_SERVER_ERROR_MESSAGE,
27+
TYPE_MAP,
28+
VALID_PROGRESS_TYPES,
29+
};

constants/roles.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const ROLES = {
44
APPOWNER: "app_owner",
55
MEMBER: "member",
66
ARCHIVED: "archived",
7+
INDISCORD: "in_discord",
78
};
89

910
module.exports = ROLES;

constants/users.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const USER_STATUS = {
1313
const ALLOWED_FILTER_PARAMS = {
1414
ITEM_TAG: ["levelId", "levelName", "levelValue", "tagId"],
1515
USER_STATE: ["state"],
16+
ROLE: ["role"],
1617
};
1718

1819
module.exports = { profileStatus, USER_STATUS, ALLOWED_FILTER_PARAMS };

controllers/progresses.js

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
const { Conflict, NotFound } = require("http-errors");
2-
const { createProgressDocument, getProgressDocument, getRangeProgressData } = require("../models/progresses");
3-
const { RESPONSE_MESSAGES } = require("../constants/progresses");
2+
const {
3+
createProgressDocument,
4+
getProgressDocument,
5+
getRangeProgressData,
6+
getProgressByDate,
7+
} = require("../models/progresses");
8+
const { RESPONSE_MESSAGES, INTERNAL_SERVER_ERROR_MESSAGE } = require("../constants/progresses");
49
const { PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED, PROGRESS_DOCUMENT_CREATED_SUCCEEDED } = RESPONSE_MESSAGES;
510

611
/**
@@ -58,8 +63,9 @@ const createProgress = async (req, res) => {
5863
message: error.message,
5964
});
6065
}
61-
return res.status(400).json({
62-
message: error.message,
66+
logger.error(error.message);
67+
return res.status(500).json({
68+
message: INTERNAL_SERVER_ERROR_MESSAGE,
6369
});
6470
}
6571
};
@@ -112,8 +118,9 @@ const getProgress = async (req, res) => {
112118
message: error.message,
113119
});
114120
}
115-
return res.status(400).json({
116-
message: error.message,
121+
logger.error(error.message);
122+
return res.status(500).json({
123+
message: INTERNAL_SERVER_ERROR_MESSAGE,
117124
});
118125
}
119126
};
@@ -165,10 +172,65 @@ const getProgressRangeData = async (req, res) => {
165172
message: error.message,
166173
});
167174
}
168-
return res.status(400).json({
169-
message: error.message,
175+
logger.error(error.message);
176+
return res.status(500).json({
177+
message: INTERNAL_SERVER_ERROR_MESSAGE,
170178
});
171179
}
172180
};
173181

174-
module.exports = { createProgress, getProgress, getProgressRangeData };
182+
/**
183+
* @typedef {Object} progressPathParams
184+
* @property {string} type - The type of progress document user or task.
185+
* @property {string} typeId - The ID of the type.
186+
* @property {string} date - The iso format date of the query.
187+
*/
188+
189+
/**
190+
* @typedef {Object} ProgressDocument
191+
* @property {string} id - The id of the progress document.
192+
* @property {string} type - The type of progress document.
193+
* @property {string} completed - The completed progress.
194+
* @property {string} planned - The planned progress.
195+
* @property {string} blockers - The blockers.
196+
* @property {string} userId - The User ID
197+
* @property {string} [taskId] - The task ID (optional).
198+
* @property {number} createdAt - The timestamp when the progress document was created.
199+
* @property {number} date - The timestamp for the day the progress document was created.
200+
*/
201+
202+
/**
203+
* @typedef {Object} GetProgressByDateResponse
204+
* @property {string} message - The success message.
205+
* @property {ProgressDocument} data - An array of progress documents
206+
*/
207+
208+
/**
209+
* Retrieves the progress documents based on provided query parameters.
210+
* @param {Object} req - The HTTP request object.
211+
* @param {progressPathParams} req.params - The query parameters
212+
* @param {Object} res - The HTTP response object.
213+
* @returns {Promise<void>} A Promise that resolves when the response is sent.
214+
*/
215+
216+
const getProgressBydDateController = async (req, res) => {
217+
try {
218+
const data = await getProgressByDate(req.params);
219+
return res.json({
220+
message: PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED,
221+
data,
222+
});
223+
} catch (error) {
224+
if (error instanceof NotFound) {
225+
return res.status(404).json({
226+
message: error.message,
227+
});
228+
}
229+
logger.error(error.message);
230+
return res.status(500).json({
231+
message: INTERNAL_SERVER_ERROR_MESSAGE,
232+
});
233+
}
234+
};
235+
236+
module.exports = { createProgress, getProgress, getProgressRangeData, getProgressBydDateController };

controllers/tasks.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { addOrUpdate, getRdsUserInfoByGitHubUsername } = require("../models/users
66
const { OLD_ACTIVE, OLD_BLOCKED, OLD_PENDING } = TASK_STATUS_OLD;
77
const { IN_PROGRESS, BLOCKED, SMOKE_TESTING, ASSIGNED } = TASK_STATUS;
88
const { INTERNAL_SERVER_ERROR, SOMETHING_WENT_WRONG } = require("../constants/errorMessages");
9+
const dependencyModel = require("../models/tasks");
910
/**
1011
* Creates new task
1112
*
@@ -16,17 +17,25 @@ const { INTERNAL_SERVER_ERROR, SOMETHING_WENT_WRONG } = require("../constants/er
1617
const addNewTask = async (req, res) => {
1718
try {
1819
const { id: createdBy } = req.userData;
20+
const dependsOn = req.body.dependsOn;
1921
const body = {
2022
...req.body,
2123
createdBy,
2224
};
23-
24-
const task = await tasks.updateTask(body);
25-
25+
delete body.dependsOn;
26+
const { taskId, taskDetails } = await tasks.updateTask(body);
27+
const data = {
28+
taskId,
29+
dependsOn,
30+
};
31+
const taskDependency = dependsOn && (await dependencyModel.addDependency(data));
2632
return res.json({
2733
message: "Task created successfully!",
28-
task: task.taskDetails,
29-
id: task.taskId,
34+
task: {
35+
...taskDetails,
36+
...(taskDependency && { dependsOn: taskDependency }),
37+
id: taskId,
38+
},
3039
});
3140
} catch (err) {
3241
logger.error(`Error while creating new task: ${err}`);

controllers/users.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const logsQuery = require("../models/logs");
55
const imageService = require("../services/imageService");
66
const { profileDiffStatus } = require("../constants/profileDiff");
77
const { logType } = require("../constants/logs");
8-
const { fetch } = require("../utils/fetch");
8+
99
const logger = require("../utils/logger");
1010
const obfuscate = require("../utils/obfuscate");
1111
const { getPaginationLink, getUsernamesFromPRs } = require("../utils/users");
@@ -24,7 +24,11 @@ const verifyUser = async (req, res) => {
2424
logger.error(`Error while verifying user: ${error}`);
2525
return res.boom.serverUnavailable(SOMETHING_WENT_WRONG);
2626
}
27-
fetch(process.env.IDENTITY_SERVICE_URL, "POST", null, { userId }, { "Content-Type": "application/json" });
27+
fetch(process.env.IDENTITY_SERVICE_URL, {
28+
method: "POST",
29+
body: { userId },
30+
headers: { "Content-Type": "application/json" },
31+
});
2832
return res.json({
2933
message: "Your request has been queued successfully",
3034
});

middlewares/validators/progresses.js

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
const joi = require("joi");
2+
const { VALID_PROGRESS_TYPES } = require("../../constants/progresses");
23

34
const validateCreateProgressRecords = async (req, res, next) => {
45
const baseSchema = joi
56
.object()
67
.strict()
78
.keys({
8-
type: joi.string().trim().valid("user", "task").required().messages({
9-
"any.required": "Required field 'type' is missing.",
10-
"any.only": "Type field is restricted to either 'user' or 'task'.",
11-
}),
9+
type: joi
10+
.string()
11+
.trim()
12+
.valid(...VALID_PROGRESS_TYPES)
13+
.required()
14+
.messages({
15+
"any.required": "Required field 'type' is missing.",
16+
"any.only": "Type field is restricted to either 'user' or 'task'.",
17+
}),
1218
completed: joi.string().trim().required().messages({
1319
"any.required": "Required field 'completed' is missing.",
1420
"string.trim": "completed must not have leading or trailing whitespace",
@@ -44,9 +50,13 @@ const validateCreateProgressRecords = async (req, res, next) => {
4450
const validateGetProgressRecordsQuery = async (req, res, next) => {
4551
const schema = joi
4652
.object({
47-
type: joi.string().valid("user", "task").optional().messages({
48-
"any.only": "Type field is restricted to either 'user' or 'task'.",
49-
}),
53+
type: joi
54+
.string()
55+
.valid(...VALID_PROGRESS_TYPES)
56+
.optional()
57+
.messages({
58+
"any.only": "Type field is restricted to either 'user' or 'task'.",
59+
}),
5060
userId: joi.string().optional().allow("").messages({
5161
"string.base": "userId must be a string",
5262
}),
@@ -92,8 +102,30 @@ const validateGetRangeProgressRecordsParams = async (req, res, next) => {
92102
res.boom.badRequest(error.details[0].message);
93103
}
94104
};
105+
106+
const validateGetDayProgressParams = async (req, res, next) => {
107+
const schema = joi.object({
108+
type: joi
109+
.string()
110+
.valid(...VALID_PROGRESS_TYPES)
111+
.required()
112+
.messages({
113+
"any.only": "Type field is restricted to either 'user' or 'task'.",
114+
}),
115+
typeId: joi.string().required(),
116+
date: joi.date().iso().required(),
117+
});
118+
try {
119+
await schema.validateAsync(req.params, { abortEarly: false });
120+
next();
121+
} catch (error) {
122+
logger.error(`Error validating payload: ${error}`);
123+
res.boom.badRequest(error.details[0].message);
124+
}
125+
};
95126
module.exports = {
96127
validateCreateProgressRecords,
97128
validateGetProgressRecordsQuery,
98129
validateGetRangeProgressRecordsParams,
130+
validateGetDayProgressParams,
99131
};

middlewares/validators/user.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const joi = require("joi");
22
const { USER_STATUS } = require("../../constants/users");
3+
const ROLES = require("../../constants/roles");
34

45
const updateUser = async (req, res, next) => {
56
const schema = joi
@@ -172,6 +173,8 @@ async function validateUserQueryParams(req, res, next) {
172173
joi.array().items(joi.string().valid("IDLE", "OOO", "ACTIVE"))
173174
)
174175
.optional(),
176+
role: joi.string().valid(ROLES.MEMBER, ROLES.INDISCORD).optional(),
177+
verified: joi.string().optional(),
175178
})
176179
.messages({
177180
"object.min": "Please provide at least one filter criteria",

models/progresses.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
const { Conflict } = require("http-errors");
1+
const { Conflict, NotFound } = require("http-errors");
22
const fireStore = require("../utils/firestore");
33
const progressesCollection = fireStore.collection("progresses");
4-
const { RESPONSE_MESSAGES } = require("../constants/progresses");
4+
const { RESPONSE_MESSAGES, TYPE_MAP } = require("../constants/progresses");
55
const {
66
buildQueryToFetchDocs,
77
getProgressDocs,
@@ -11,8 +11,9 @@ const {
1111
buildQueryForPostingProgress,
1212
assertTaskExists,
1313
getProgressDateTimestamp,
14+
buildQueryToSearchProgressByDay,
1415
} = require("../utils/progresses");
15-
const { PROGRESS_ALREADY_CREATED } = RESPONSE_MESSAGES;
16+
const { PROGRESS_ALREADY_CREATED, PROGRESS_DOCUMENT_NOT_FOUND } = RESPONSE_MESSAGES;
1617

1718
/**
1819
* 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) => {
6869
};
6970
};
7071

71-
module.exports = { createProgressDocument, getProgressDocument, getRangeProgressData };
72+
/**
73+
* This function fetches the progress records for a particular user or task on the specified date.
74+
* @param pathParams {object} This is the data that will be used for querying the db. It should contain type, typeId and date
75+
* @returns {Promise<object>} A Promise that resolves with the progress records of the queried user or task.
76+
* @throws {Error} If the userId or taskId is invalid or does not exist.
77+
**/
78+
async function getProgressByDate(pathParams) {
79+
const { type, typeId, date } = pathParams;
80+
await assertUserOrTaskExists({ [TYPE_MAP[type]]: typeId });
81+
const query = buildQueryToSearchProgressByDay({ [TYPE_MAP[type]]: typeId, date });
82+
const result = await query.get();
83+
if (!result.size) {
84+
throw new NotFound(PROGRESS_DOCUMENT_NOT_FOUND);
85+
}
86+
const doc = result.docs[0];
87+
return { id: doc.id, ...doc.data() };
88+
}
89+
90+
module.exports = { createProgressDocument, getProgressDocument, getRangeProgressData, getProgressByDate };

models/tasks.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const firestore = require("../utils/firestore");
22
const tasksModel = firestore.collection("tasks");
33
const ItemModel = firestore.collection("itemTags");
4+
const dependencyModel = firestore.collection("taskDependencies");
45
const userUtils = require("../utils/users");
56
const { fromFirestoreData, toFirestoreData, buildTasks } = require("../utils/tasks");
67
const { TASK_TYPE, TASK_STATUS, TASK_STATUS_OLD } = require("../constants/tasks");
@@ -32,13 +33,34 @@ const updateTask = async (taskData, taskId = null) => {
3233
taskId: taskInfo.id,
3334
taskDetails: await fromFirestoreData(taskData),
3435
};
35-
3636
return result;
3737
} catch (err) {
3838
logger.error("Error in updating task", err);
3939
throw err;
4040
}
4141
};
42+
const addDependency = async (data) => {
43+
try {
44+
const { taskId, dependsOn } = data;
45+
const batch = firestore.batch();
46+
if (dependsOn.length > 500) {
47+
throw new Error("Error cannot add more than 500 taskId");
48+
}
49+
for (const dependsId of dependsOn) {
50+
const taskDependOn = {
51+
taskId,
52+
dependsId,
53+
};
54+
const docid = dependencyModel.doc();
55+
batch.set(docid, taskDependOn);
56+
}
57+
await batch.commit();
58+
return data.dependsOn;
59+
} catch (err) {
60+
logger.error("Error in creating dependency");
61+
throw err;
62+
}
63+
};
4264

4365
/**
4466
* Fetch all tasks
@@ -352,5 +374,6 @@ module.exports = {
352374
fetchSelfTask,
353375
fetchSkillLevelTask,
354376
overdueTasks,
377+
addDependency,
355378
fetchTaskByIssueId,
356379
};

0 commit comments

Comments
 (0)