Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5b81e33
Added dependsOn on new collection
vinit717 Apr 26, 2023
ff6b07f
Get taskId
vinit717 Apr 27, 2023
5e64aaa
Store dependsOn array through batch
vinit717 Apr 28, 2023
b3d0560
initial commit
bhtibrewal Apr 28, 2023
088b2e9
sync API
bhtibrewal May 2, 2023
ad47944
Remove console log
vinit717 May 5, 2023
aeabe05
Remove console log
vinit717 May 5, 2023
803acfe
Merge branch 'develop' into task-dependency-v2
vinit717 May 6, 2023
1a45af3
Merge branch 'develop' into feature/inDiscord
bhtibrewal May 6, 2023
56b589e
return dependsOn as reponse
vinit717 May 7, 2023
c8f88e9
Add test for task-dependency
vinit717 May 8, 2023
6ca49f2
change task res.json
vinit717 May 10, 2023
206cb79
remove unwanted code
vinit717 May 10, 2023
6c6cd23
Change task test integration
vinit717 May 10, 2023
a474cd0
change res.json
vinit717 May 12, 2023
c2287e9
refactor code
vinit717 May 13, 2023
23e594c
func: search roles and verified users
bhtibrewal May 13, 2023
0df2d1c
adds the route to get a specific document
heyrandhir May 14, 2023
07c0bb0
feat: search in_discord and verified
bhtibrewal May 14, 2023
19fe12a
chore: remove unused code
bhtibrewal May 14, 2023
6b013d7
chore: remove mapDiscordMembersDataAndSyncRole function
bhtibrewal May 14, 2023
893d672
handles internal server error gracefully
heyrandhir May 15, 2023
9580d54
add tests for 409 conflict
heyrandhir May 15, 2023
7310985
fixes the timezone offset
heyrandhir May 15, 2023
3829b53
remove the console logs
heyrandhir May 15, 2023
c40eed3
Merge branch 'feat/remove-skip-tests-for-progresses' into feat/progre…
heyrandhir May 15, 2023
16e15c7
added new line at the end of the file
heyrandhir May 15, 2023
96946c6
add test for retrieving progress document for the user on a particula…
heyrandhir May 15, 2023
7a43897
add test for retrieving progress document for the task on a particula…
heyrandhir May 15, 2023
9f74941
Add test for user,task for 404 No progress records found
heyrandhir May 15, 2023
07d57be
add 4 more tests to increase the test robustness
heyrandhir May 16, 2023
3e75de8
adds more strict check on time calculation
heyrandhir May 16, 2023
4c3be05
remove es lint warning message
heyrandhir May 16, 2023
cf520e1
write test for brew install redis
bhtibrewal May 17, 2023
9e95148
resolve comments by @DashDeipayan in the PR
heyrandhir May 17, 2023
ff0b91f
Merge branch 'feat/remove-skip-tests-for-progresses' into feat/progre…
heyrandhir May 17, 2023
c8cccd8
fixed the comments by @DashDeipayan in all 3 validator function
heyrandhir May 17, 2023
3676073
Merge pull request #1089 from Real-Dev-Squad/feat/progresses-api-v1.5
heyrandhir May 18, 2023
1cf19fc
Merge pull request #1070 from Real-Dev-Squad/task-dependency-v2
bhtibrewal May 18, 2023
e1ef0de
chore: change test description
bhtibrewal May 18, 2023
70a0d19
chore: address comments
bhtibrewal May 18, 2023
9aa1166
chore: use roles constant in validation
bhtibrewal May 18, 2023
a4952ed
Merge pull request #1060 from Real-Dev-Squad/feature/inDiscord
bhtibrewal May 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion constants/progresses.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -11,4 +13,17 @@ const RESPONSE_MESSAGES = {
PROGRESS_ALREADY_CREATED,
};

module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY };
const TYPE_MAP = {
user: "userId",
task: "taskId",
};

const VALID_PROGRESS_TYPES = ["task", "user"];

module.exports = {
RESPONSE_MESSAGES,
MILLISECONDS_IN_DAY,
INTERNAL_SERVER_ERROR_MESSAGE,
TYPE_MAP,
VALID_PROGRESS_TYPES,
};
1 change: 1 addition & 0 deletions constants/roles.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const ROLES = {
APPOWNER: "app_owner",
MEMBER: "member",
ARCHIVED: "archived",
INDISCORD: "in_discord",
};

module.exports = ROLES;
1 change: 1 addition & 0 deletions constants/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
80 changes: 71 additions & 9 deletions controllers/progresses.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
const { Conflict, NotFound } = require("http-errors");
const { createProgressDocument, getProgressDocument, getRangeProgressData } = require("../models/progresses");
const { RESPONSE_MESSAGES } = require("../constants/progresses");
const {
createProgressDocument,
getProgressDocument,
getRangeProgressData,
getProgressByDate,
} = require("../models/progresses");
const { RESPONSE_MESSAGES, INTERNAL_SERVER_ERROR_MESSAGE } = require("../constants/progresses");
const { PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED, PROGRESS_DOCUMENT_CREATED_SUCCEEDED } = RESPONSE_MESSAGES;

/**
Expand Down Expand Up @@ -58,8 +63,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,
});
}
};
Expand Down Expand Up @@ -112,8 +118,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,
});
}
};
Expand Down Expand Up @@ -165,10 +172,65 @@ 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,
});
}
};

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<void>} 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,
});
}
logger.error(error.message);
return res.status(500).json({
message: INTERNAL_SERVER_ERROR_MESSAGE,
});
}
};

module.exports = { createProgress, getProgress, getProgressRangeData, getProgressBydDateController };
19 changes: 14 additions & 5 deletions controllers/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { addOrUpdate, getRdsUserInfoByGitHubUsername } = 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
*
Expand All @@ -16,17 +17,25 @@ const { INTERNAL_SERVER_ERROR, SOMETHING_WENT_WRONG } = require("../constants/er
const addNewTask = async (req, res) => {
try {
const { id: createdBy } = req.userData;
const dependsOn = req.body.dependsOn;
const body = {
...req.body,
createdBy,
};

const task = await tasks.updateTask(body);

delete body.dependsOn;
const { taskId, taskDetails } = await tasks.updateTask(body);
const data = {
taskId,
dependsOn,
};
const taskDependency = dependsOn && (await dependencyModel.addDependency(data));
return res.json({
message: "Task created successfully!",
task: task.taskDetails,
id: task.taskId,
task: {
...taskDetails,
...(taskDependency && { dependsOn: taskDependency }),
id: taskId,
},
});
} catch (err) {
logger.error(`Error while creating new task: ${err}`);
Expand Down
8 changes: 6 additions & 2 deletions controllers/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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");
Expand All @@ -24,7 +24,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",
});
Expand Down
46 changes: 39 additions & 7 deletions middlewares/validators/progresses.js
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -44,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",
}),
Expand Down Expand Up @@ -92,8 +102,30 @@ 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(...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(),
});
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,
};
3 changes: 3 additions & 0 deletions middlewares/validators/user.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -172,6 +173,8 @@ async function validateUserQueryParams(req, res, next) {
joi.array().items(joi.string().valid("IDLE", "OOO", "ACTIVE"))
)
.optional(),
role: joi.string().valid(ROLES.MEMBER, ROLES.INDISCORD).optional(),
verified: joi.string().optional(),
})
.messages({
"object.min": "Please provide at least one filter criteria",
Expand Down
27 changes: 23 additions & 4 deletions models/progresses.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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.
Expand Down Expand Up @@ -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<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) {
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 };
25 changes: 24 additions & 1 deletion models/tasks.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
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 { fromFirestoreData, toFirestoreData, buildTasks } = require("../utils/tasks");
const { TASK_TYPE, TASK_STATUS, TASK_STATUS_OLD } = require("../constants/tasks");
Expand Down Expand Up @@ -32,13 +33,34 @@ 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 (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,
dependsId,
};
const docid = dependencyModel.doc();
batch.set(docid, taskDependOn);
}
await batch.commit();
return data.dependsOn;
} catch (err) {
logger.error("Error in creating dependency");
throw err;
}
};

/**
* Fetch all tasks
Expand Down Expand Up @@ -352,5 +374,6 @@ module.exports = {
fetchSelfTask,
fetchSkillLevelTask,
overdueTasks,
addDependency,
fetchTaskByIssueId,
};
Loading