Skip to content

Commit 65f4545

Browse files
committed
Merge branch 'develop' of https://github.com/Real-Dev-Squad/website-backend into develop
2 parents 558dd2d + 24a1110 commit 65f4545

File tree

21 files changed

+1893
-1515
lines changed

21 files changed

+1893
-1515
lines changed

controllers/issues.js

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
const issuesService = require("../services/issuesService");
2+
const tasks = require("../models/tasks");
3+
const { SOMETHING_WENT_WRONG } = require("../constants/errorMessages");
4+
5+
/**
6+
* Get the issues of the repo
7+
* @param {Object} req - Express request object
8+
* @param {Object} res - Express response object
9+
*/
10+
11+
const getIssues = async (req, res) => {
12+
try {
13+
const issues = await issuesService.getOrgIssues();
14+
let issuesData = issues.data.length > 0 ? issues.data : [];
15+
issuesData = issuesData.filter((issue) => !Object.keys(issue).includes("pull_request"));
16+
issuesData = issuesData.map(async (issue) => {
17+
const taskData = await tasks.fetchTaskByIssueId(issue.id);
18+
if (taskData) {
19+
issue.taskExists = true;
20+
}
21+
22+
return issue;
23+
});
24+
const updatedIsuees = await Promise.all(issuesData);
25+
return res.json({
26+
message: "Issues returned successfully!",
27+
issues: updatedIsuees,
28+
});
29+
} catch (err) {
30+
logger.error(`Error while retriving issues ${err}`);
31+
return res.boom.badImplementation(SOMETHING_WENT_WRONG);
32+
}
33+
};
34+
35+
/**
36+
* Receive updated issue information from webhook
37+
* @param {Object} req - Express request object
38+
* @param {Object} res - Express response object
39+
*/
40+
const issueUpdates = async (req, res) => {
41+
try {
42+
const response = req.body;
43+
if ("issue" in response) {
44+
const { issue } = response;
45+
const taskData = await tasks.fetchTaskByIssueId(issue.id);
46+
if (taskData) {
47+
// filtering properties with undefined or null values
48+
const updatedTaskData = Object.fromEntries(Object.entries(taskData).filter(([_, value]) => value ?? false));
49+
50+
updatedTaskData.title = issue.title;
51+
updatedTaskData.github = {
52+
issue: {
53+
...updatedTaskData.github.issue,
54+
status: issue.state,
55+
},
56+
};
57+
58+
// If the issue has any updates with the assignee
59+
if (issue.assignee) {
60+
// If there are no previous assignees or the task was not assigned before
61+
if (!updatedTaskData.github.issue.assignee || !updatedTaskData.assignee) {
62+
updatedTaskData.github.issue.assignee = issue.assignee.login;
63+
}
64+
}
65+
// If the issue assignee was removed and task was not assigned
66+
else if (updatedTaskData.github.issue.assignee && !updatedTaskData.assignee) {
67+
delete updatedTaskData.github.issue.assignee;
68+
}
69+
70+
if (issue.state === "closed") {
71+
updatedTaskData.github.issue.closedAt = issue.closed_at;
72+
}
73+
74+
await tasks.updateTask(updatedTaskData, taskData.id);
75+
return res.json({
76+
message: "Task updated successfully",
77+
});
78+
} else {
79+
return res.json({
80+
message: "No task was found for the updated issue",
81+
});
82+
}
83+
}
84+
return res.json({
85+
message: "No issue was updated",
86+
});
87+
} catch (err) {
88+
logger.error(`Error while retriving issues ${err}`);
89+
return res.boom.badImplementation(SOMETHING_WENT_WRONG);
90+
}
91+
};
92+
93+
module.exports = {
94+
getIssues,
95+
issueUpdates,
96+
};

controllers/tasks.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const tasks = require("../models/tasks");
22
const { TASK_STATUS, TASK_STATUS_OLD } = require("../constants/tasks");
33
const { addLog } = require("../models/logs");
44
const { USER_STATUS } = require("../constants/users");
5-
const { addOrUpdate } = require("../models/users");
5+
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");
@@ -20,6 +20,7 @@ const addNewTask = async (req, res) => {
2020
...req.body,
2121
createdBy,
2222
};
23+
2324
const task = await tasks.updateTask(body);
2425

2526
return res.json({
@@ -41,9 +42,32 @@ const addNewTask = async (req, res) => {
4142
const fetchTasks = async (req, res) => {
4243
try {
4344
const allTasks = await tasks.fetchTasks();
45+
const fetchTasksWithRdsAssigneeInfo = allTasks.map(async (task) => {
46+
/*
47+
If the issue has a "github.issue" inner object and a property "assignee",
48+
then fetch the RDS user information with GitHub username in "assignee"
49+
*/
50+
if (Object.keys(task).includes("github")) {
51+
if (Object.keys(task.github.issue).includes("assignee")) {
52+
return {
53+
...task,
54+
github: {
55+
...task.github,
56+
issue: {
57+
...task.github.issue,
58+
assigneeRdsInfo: await getRdsUserInfoByGitHubUsername(task.github.issue.assignee),
59+
},
60+
},
61+
};
62+
}
63+
}
64+
return task;
65+
});
66+
67+
const tasksWithRdsAssigneeInfo = await Promise.all(fetchTasksWithRdsAssigneeInfo);
4468
return res.json({
4569
message: "Tasks returned successfully!",
46-
tasks: allTasks.length > 0 ? allTasks : [],
70+
tasks: tasksWithRdsAssigneeInfo.length > 0 ? tasksWithRdsAssigneeInfo : [],
4771
});
4872
} catch (err) {
4973
logger.error(`Error while fetching tasks ${err}`);

middlewares/validators/tasks.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ const createTask = async (req, res, next) => {
4242
})
4343
.optional(),
4444
isNoteworthy: joi.bool().optional(),
45+
github: joi
46+
.object()
47+
.keys({
48+
issue: joi.object().keys({
49+
status: joi.string().optional(),
50+
assignee: joi.string().optional(),
51+
id: joi.number().optional(),
52+
closedAt: joi.string().optional(),
53+
}),
54+
})
55+
.optional(),
4556
});
4657

4758
try {

models/tasks.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,32 @@ const fetchTask = async (taskId) => {
105105
}
106106
};
107107

108+
/**
109+
* Fetch a task against the IssueId
110+
* @param issueId { number }: issueId which will be used to fetch the task
111+
* @return {Promise<taskData|Object>}
112+
*/
113+
const fetchTaskByIssueId = async (issueId) => {
114+
try {
115+
const task = await tasksModel.where("github.issue.id", "==", issueId).get();
116+
const [taskDoc] = task.docs;
117+
let updatedTaskData;
118+
if (taskDoc) {
119+
updatedTaskData = { id: taskDoc.id, ...taskDoc.data() };
120+
}
121+
const taskData = await fromFirestoreData(updatedTaskData);
122+
123+
if (taskData?.status) {
124+
taskData.status = TASK_STATUS[taskData.status.toUpperCase()];
125+
}
126+
127+
return taskData;
128+
} catch (err) {
129+
logger.error("Error retrieving task data from issue Id", err);
130+
throw err;
131+
}
132+
};
133+
108134
/**
109135
* Fetch assigned self task
110136
* @param taskId { string }: taskId which will be used to fetch the task
@@ -326,4 +352,5 @@ module.exports = {
326352
fetchSelfTask,
327353
fetchSkillLevelTask,
328354
overdueTasks,
355+
fetchTaskByIssueId,
329356
};

models/users.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const addOrUpdate = async (userData, userId = null) => {
5959
userData.roles = { archived: false };
6060
userData.incompleteUserDetails = true;
6161
const userInfo = await userModel.add(userData);
62-
return { isNewUser: true, userId: userInfo.id };
62+
return { isNewUser: true, userId: userInfo.id, incompleteUserDetails: true };
6363
} catch (err) {
6464
logger.error("Error in adding or updating user", err);
6565
throw err;
@@ -224,7 +224,7 @@ const fetchUsers = async (usernames = []) => {
224224
* @param { Object }: Object with username and userId, any of the two can be used
225225
* @return {Promise<{userExists: boolean, user: <userModel>}|{userExists: boolean, user: <userModel>}>}
226226
*/
227-
const fetchUser = async ({ userId = null, username = null }) => {
227+
const fetchUser = async ({ userId = null, username = null, githubUsername = null }) => {
228228
try {
229229
let userData, id;
230230
if (username) {
@@ -238,6 +238,12 @@ const fetchUser = async ({ userId = null, username = null }) => {
238238
const user = await userModel.doc(userId).get();
239239
id = userId;
240240
userData = user.data();
241+
} else if (githubUsername) {
242+
const user = await userModel.where("github_id", "==", githubUsername).limit(1).get();
243+
user.forEach((doc) => {
244+
id = doc.id;
245+
userData = doc.data();
246+
});
241247
}
242248
return {
243249
userExists: !!userData,
@@ -335,6 +341,16 @@ const fetchUserSkills = async (id) => {
335341
}
336342
};
337343

344+
const getRdsUserInfoByGitHubUsername = async (githubUsername) => {
345+
const { user } = await fetchUser({ githubUsername });
346+
347+
return {
348+
firstName: user.first_name ?? "",
349+
lastName: user.last_name ?? "",
350+
username: user.username ?? "",
351+
};
352+
};
353+
338354
/**
339355
* Fetches user data based on the filter query
340356
*
@@ -405,6 +421,7 @@ module.exports = {
405421
getJoinData,
406422
getSuggestedUsers,
407423
fetchUserSkills,
424+
getRdsUserInfoByGitHubUsername,
408425
fetchUsers,
409426
getUsersBasedOnFilter,
410427
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"eslint-plugin-promise": "^6.0.0",
5151
"eslint-plugin-security": "^1.4.0",
5252
"eslint-plugin-standard": "^4.1.0",
53-
"firebase-tools": "^11.0.0",
53+
"firebase-tools": "^11.28.0",
5454
"mocha": "^10.0.0",
5555
"nock": "^13.0.11",
5656
"nodemon": "^2.0.7",

routes/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ app.use("/levels", require("./levels.js"));
2424
app.use("/items", require("./items.js"));
2525
app.use("/cache", require("./cloudflareCache.js"));
2626
app.use("/external-accounts", require("./external-accounts.js"));
27+
app.use("/issues", require("./issues.js"));
2728

2829
module.exports = app;

routes/issues.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const express = require("express");
2+
const issues = require("../controllers/issues");
3+
const router = express.Router();
4+
5+
router.get("/", issues.getIssues);
6+
router.post("/updates", issues.issueUpdates);
7+
8+
module.exports = router;

scripts/tests/testIntegration.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@
33
# set 'test' environment
44
export NODE_ENV='test'
55

6+
# get project_id value from firestore config
7+
json=$(node -e "console.log(require('config').get('firestore'))")
8+
project_id=$(echo $json | grep -o '"project_id":[^,}]*' | cut -d':' -f2 | tr -d '"' | tr -d '[:space:]')
9+
610
echo 'Start firestore emulator and run integration tests:'
7-
firebase emulators:exec 'nyc mocha test/integration/**'
11+
firebase emulators:exec 'nyc mocha test/integration/**' --project=$project_id

scripts/tests/testUnit.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@
33
# set 'test' environment
44
export NODE_ENV='test'
55

6+
# get project_id value from firestore config
7+
json=$(node -e "console.log(require('config').get('firestore'))")
8+
project_id=$(echo $json | grep -o '"project_id":[^,}]*' | cut -d':' -f2 | tr -d '"' | tr -d '[:space:]')
9+
610
echo 'Start firestore emulator and run unit tests:'
7-
firebase emulators:exec 'nyc --x=controllers --x=test --x=docs --x=mockdata mocha test/unit/**'
11+
firebase emulators:exec 'nyc --x=controllers --x=test --x=docs --x=mockdata mocha test/unit/**' --project=$project_id

0 commit comments

Comments
 (0)