Skip to content

Commit c1722bc

Browse files
Merge pull request #1087 from Real-Dev-Squad/develop
dev to main sync
2 parents 5357721 + 55d3537 commit c1722bc

File tree

21 files changed

+1409
-7
lines changed

21 files changed

+1409
-7
lines changed

constants/progresses.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const PROGRESS_DOCUMENT_CREATED_SUCCEEDED = "Progress document created successfully.";
2+
const PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED = "Progress document retrieved successfully.";
3+
const PROGRESS_DOCUMENT_NOT_FOUND = "No progress records found.";
4+
const PROGRESS_ALREADY_CREATED = "Progress for the day has already been created.";
5+
const MILLISECONDS_IN_DAY = 24 * 60 * 60 * 1000;
6+
7+
const RESPONSE_MESSAGES = {
8+
PROGRESS_DOCUMENT_CREATED_SUCCEEDED,
9+
PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED,
10+
PROGRESS_DOCUMENT_NOT_FOUND,
11+
PROGRESS_ALREADY_CREATED,
12+
};
13+
14+
module.exports = { RESPONSE_MESSAGES, MILLISECONDS_IN_DAY };

constants/userStatus.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const userState = {
22
ACTIVE: "ACTIVE",
33
IDLE: "IDLE",
44
OOO: "OOO",
5+
ONBOARDING: "ONBOARDING",
56
};
67

78
module.exports = { userState };

controllers/progresses.js

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
const { Conflict, NotFound } = require("http-errors");
2+
const { createProgressDocument, getProgressDocument, getRangeProgressData } = require("../models/progresses");
3+
const { RESPONSE_MESSAGES } = require("../constants/progresses");
4+
const { PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED, PROGRESS_DOCUMENT_CREATED_SUCCEEDED } = RESPONSE_MESSAGES;
5+
6+
/**
7+
* @typedef {Object} ProgressRequestBody
8+
* @property {string} type - The type of progress document.
9+
* @property {string} completed - The completed progress.
10+
* @property {string} planned - The planned progress.
11+
* @property {string} blockers - The blockers.
12+
* @property {string} [taskId] - The task ID (optional).
13+
*/
14+
15+
/**
16+
* @typedef {Object} ProgressDocument
17+
* @property {string} type - The type of progress document.
18+
* @property {string} completed - The completed progress.
19+
* @property {string} planned - The planned progress.
20+
* @property {string} blockers - The blockers.
21+
* @property {string} userId - The User ID
22+
* @property {string} [taskId] - The task ID (optional).
23+
* @property {number} createdAt - The timestamp when the progress document was created.
24+
* @property {number} date - The timestamp for the day the progress document was created.
25+
*/
26+
27+
/**
28+
* @typedef {Object} ProgressResponse
29+
* @property {ProgressDocument} data - The progress document data.
30+
* @property {string} message - The success message.
31+
*/
32+
33+
/**
34+
* Creates a new progress document.
35+
* @param {Object} req - The HTTP request object.
36+
* @param {ProgressRequestBody} req.body - The progress document data.
37+
* @param {Object} res - The HTTP response object.
38+
* @returns {Promise<void>} A Promise that resolves when the response is sent.
39+
*/
40+
41+
const createProgress = async (req, res) => {
42+
const {
43+
body: { type },
44+
} = req;
45+
try {
46+
const data = await createProgressDocument({ ...req.body, userId: req.userData.id });
47+
return res.status(201).json({
48+
data,
49+
message: `${type.charAt(0).toUpperCase() + type.slice(1)} ${PROGRESS_DOCUMENT_CREATED_SUCCEEDED}`,
50+
});
51+
} catch (error) {
52+
if (error instanceof Conflict) {
53+
return res.status(409).json({
54+
message: error.message,
55+
});
56+
} else if (error instanceof NotFound) {
57+
return res.status(404).json({
58+
message: error.message,
59+
});
60+
}
61+
return res.status(400).json({
62+
message: error.message,
63+
});
64+
}
65+
};
66+
67+
/**
68+
* @typedef {Object} ProgressQueryParams
69+
* @property {string} [type] - The type of progress document.
70+
* @property {string} [taskId] - The task ID (optional).
71+
* @property {string} [userId] - The user ID (optional).
72+
*/
73+
74+
/**
75+
* @typedef {Object} ProgressDocument
76+
* @property {string} type - The type of progress document.
77+
* @property {string} completed - The completed progress.
78+
* @property {string} planned - The planned progress.
79+
* @property {string} blockers - The blockers.
80+
* @property {string} userId - The User ID
81+
* @property {string} [taskId] - The task ID (optional).
82+
* @property {number} createdAt - The timestamp when the progress document was created.
83+
* @property {number} date - The timestamp for the day the progress document was created.
84+
*/
85+
86+
/**
87+
* @typedef {Object} GetProgressResponse
88+
* @property {string} message - The success message.
89+
* @property {number} count - The no of progress documents retrieved
90+
* @property {[ProgressDocument]} data - An array of progress documents
91+
*/
92+
93+
/**
94+
* Retrieves the progress documents based on provided query parameters.
95+
* @param {Object} req - The HTTP request object.
96+
* @param {ProgressQueryParams} req.query - The query parameters
97+
* @param {Object} res - The HTTP response object.
98+
* @returns {Promise<void>} A Promise that resolves when the response is sent.
99+
*/
100+
101+
const getProgress = async (req, res) => {
102+
try {
103+
const data = await getProgressDocument(req.query);
104+
return res.json({
105+
message: PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED,
106+
count: data.length,
107+
data,
108+
});
109+
} catch (error) {
110+
if (error instanceof NotFound) {
111+
return res.status(404).json({
112+
message: error.message,
113+
});
114+
}
115+
return res.status(400).json({
116+
message: error.message,
117+
});
118+
}
119+
};
120+
121+
/**
122+
* @typedef {Object} ProgressQueryParams
123+
* @property {string} [taskId] - The task ID (optional).
124+
* @property {string} [userId] - The user ID (optional).
125+
* @property {string} startDate - The start date of the date range to retrieve progress records for.
126+
* @property {string} endDate - The end date of the date range to retrieve progress records for.
127+
*/
128+
129+
/**
130+
* @typedef {Object} progressRecord
131+
* @property {boolean} date - the boolean indicating whether the progress was recorded or not for that date
132+
/**
133+
134+
/**
135+
* @typedef {Object} ProgressRangeData
136+
* @property {string} startDate - the start date for the progress records
137+
* @property {string} endDate - the end date for the progress records
138+
* @property {Object.<string, progressRecord>} progressRecords - An object where the keys are dates and the values are progress records.
139+
/**
140+
141+
/**
142+
* @typedef {Object} GetProgressRangeDataResponse
143+
* @property {string} message - The success message.
144+
* @property {ProgressRangeData} data - The progress range data.
145+
*/
146+
147+
/**
148+
* Retrieves the progress documents based on provided query parameters.
149+
* @param {Object} req - The HTTP request object.
150+
* @param {ProgressQueryParams} req.query - The query parameters
151+
* @param {Object} res - The HTTP response object.
152+
* @returns {Promise<void>} A Promise that resolves when the response is sent.
153+
*/
154+
155+
const getProgressRangeData = async (req, res) => {
156+
try {
157+
const data = await getRangeProgressData(req.query);
158+
return res.json({
159+
message: PROGRESS_DOCUMENT_RETRIEVAL_SUCCEEDED,
160+
data,
161+
});
162+
} catch (error) {
163+
if (error instanceof NotFound) {
164+
return res.status(404).json({
165+
message: error.message,
166+
});
167+
}
168+
return res.status(400).json({
169+
message: error.message,
170+
});
171+
}
172+
};
173+
174+
module.exports = { createProgress, getProgress, getProgressRangeData };

controllers/users.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ const addUserIntro = async (req, res) => {
390390
await userQuery.addJoinData(data);
391391

392392
return res.status(201).json({
393-
message: "User data added successfully",
393+
message: "User join data and newstatus data added and updated successfully",
394394
});
395395
} catch (err) {
396396
logger.error("Could not save user data");
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
const joi = require("joi");
2+
3+
const validateCreateProgressRecords = async (req, res, next) => {
4+
const baseSchema = joi
5+
.object()
6+
.strict()
7+
.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+
}),
12+
completed: joi.string().trim().required().messages({
13+
"any.required": "Required field 'completed' is missing.",
14+
"string.trim": "completed must not have leading or trailing whitespace",
15+
}),
16+
planned: joi.string().trim().required().messages({
17+
"any.required": "Required field 'planned' is missing.",
18+
"string.trim": "planned must not have leading or trailing whitespace",
19+
}),
20+
blockers: joi.string().trim().allow("").required().messages({
21+
"any.required": "Required field 'blockers' is missing.",
22+
"string.trim": "blockers must not have leading or trailing whitespace",
23+
}),
24+
})
25+
.messages({ "object.unknown": "Invalid field provided." });
26+
27+
const taskSchema = joi.object().keys({
28+
taskId: joi.string().trim().required().messages({
29+
"any.required": "Required field 'taskId' is missing.",
30+
"string.trim": "taskId must not have leading or trailing whitespace",
31+
}),
32+
});
33+
const schema = req.body.type === "task" ? baseSchema.concat(taskSchema) : baseSchema;
34+
35+
try {
36+
await schema.validateAsync(req.body, { abortEarly: false });
37+
next();
38+
} catch (error) {
39+
logger.error(`Error validating payload: ${error}`);
40+
res.boom.badRequest(error.details[0].message);
41+
}
42+
};
43+
44+
const validateGetProgressRecordsQuery = async (req, res, next) => {
45+
const schema = joi
46+
.object({
47+
type: joi.string().valid("user", "task").optional().messages({
48+
"any.only": "Type field is restricted to either 'user' or 'task'.",
49+
}),
50+
userId: joi.string().optional().allow("").messages({
51+
"string.base": "userId must be a string",
52+
}),
53+
taskId: joi.string().optional().allow("").messages({
54+
"string.base": "taskId must be a string",
55+
}),
56+
})
57+
.xor("type", "userId", "taskId")
58+
.messages({
59+
"object.unknown": "Invalid field provided.",
60+
"object.xor": "Only one of type, userId, or taskId should be present",
61+
});
62+
try {
63+
await schema.validateAsync(req.query, { abortEarly: false });
64+
next();
65+
} catch (error) {
66+
logger.error(`Error validating payload: ${error}`);
67+
res.boom.badRequest(error.details[0].message);
68+
}
69+
};
70+
71+
const validateGetRangeProgressRecordsParams = async (req, res, next) => {
72+
const schema = joi
73+
.object({
74+
userId: joi.string().optional(),
75+
taskId: joi.string().optional(),
76+
startDate: joi.date().iso().required(),
77+
endDate: joi.date().iso().min(joi.ref("startDate")).required(),
78+
})
79+
.xor("userId", "taskId")
80+
.messages({
81+
"object.unknown": "Invalid field provided.",
82+
"object.missing": "Either userId or taskId is required.",
83+
"object.xor": "Only one of userId or taskId should be present",
84+
"any.required": "Start date and End date is mandatory.",
85+
"date.min": "EndDate must be on or after startDate",
86+
});
87+
try {
88+
await schema.validateAsync(req.query, { abortEarly: false });
89+
next();
90+
} catch (error) {
91+
logger.error(`Error validating payload: ${error}`);
92+
res.boom.badRequest(error.details[0].message);
93+
}
94+
};
95+
module.exports = {
96+
validateCreateProgressRecords,
97+
validateGetProgressRecordsQuery,
98+
validateGetRangeProgressRecordsParams,
99+
};

middlewares/validators/tasks.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const createTask = async (req, res, next) => {
4242
})
4343
.optional(),
4444
isNoteworthy: joi.bool().optional(),
45+
isCollapsed: joi.bool().optional(),
4546
github: joi
4647
.object()
4748
.keys({
@@ -101,6 +102,7 @@ const updateTask = async (req, res, next) => {
101102
})
102103
.optional(),
103104
isNoteworthy: joi.bool().optional(),
105+
isCollapsed: joi.bool().optional(),
104106
});
105107
try {
106108
await schema.validateAsync(req.body);

middlewares/validators/userStatus.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ const validateUserStatusData = async (todaysTime, req, res, next) => {
77
currentStatus: Joi.object().keys({
88
state: Joi.string()
99
.trim()
10-
.valid(userState.IDLE, userState.ACTIVE, userState.OOO)
11-
.error(new Error(`Invalid State. State must be either IDLE, ACTIVE or OOO`)),
10+
.valid(userState.IDLE, userState.ACTIVE, userState.OOO, userState.ONBOARDING)
11+
.error(new Error(`Invalid State. State must be either IDLE, ACTIVE, OOO, or ONBOARDING`)),
1212
updatedAt: Joi.number().required(),
1313
from: Joi.number()
1414
.min(todaysTime)

0 commit comments

Comments
 (0)