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

Sync dev to main #2054

Merged
merged 10 commits into from
Aug 6, 2024
15 changes: 15 additions & 0 deletions constants/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const LOG_ACTION = {
export const REQUEST_TYPE = {
OOO: "OOO",
EXTENSION: "EXTENSION",
TASK: "TASK",
ALL: "ALL",
};

Expand All @@ -38,3 +39,17 @@ export const ERROR_WHILE_UPDATING_REQUEST = "Error while updating request";

export const REQUEST_DOES_NOT_EXIST = "Request does not exist";
export const REQUEST_ALREADY_PENDING = "Request already exists please wait for approval or rejection";

export const TASK_REQUEST_MESSAGES = {
NOT_AUTHORIZED_TO_CREATE_REQUEST: "Not authorized to create the request",
USER_NOT_FOUND: "User not found",
TASK_NOT_EXIST: "Task does not exist",
INVALID_EXTERNAL_ISSUE_URL: "External issue url is not valid",
ISSUE_NOT_EXIST: "Issue does not exist",
TASK_REQUEST_EXISTS: "Task request already exists",
TASK_EXISTS_FOR_GIVEN_ISSUE: "Task exists for the given issue.",
TASK_ALREADY_REQUESTED: "Task was already requested",
TASK_REQUEST_CREATED_SUCCESS: "Task request created successfully",
ERROR_CREATING_TASK_REQUEST: "Error while creating task request",
TASK_REQUEST_UPDATED_SUCCESS: "Task request updated successfully",
};
2 changes: 1 addition & 1 deletion constants/taskRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const TASK_REQUEST_ERROR_MESSAGE = {
INVALID_PREV: "Invalid 'prev' value",
INVALID_NEXT: "Invalid 'next' value",
};
const TASK_REQUEST_TYPE = {
export const TASK_REQUEST_TYPE = {
ASSIGNMENT: "ASSIGNMENT",
CREATION: "CREATION",
};
Expand Down
2 changes: 1 addition & 1 deletion constants/urls.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const GITHUB_URL = "https://github.com";
export const GITHUB_URL = "https://github.com";

module.exports = {
GITHUB_URL,
Expand Down
1 change: 1 addition & 0 deletions controllers/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
const groupRoleData = {
rolename,
createdBy: req.userData.id,
description: req.body.description || "",
date: admin.firestore.Timestamp.fromDate(new Date()),
};

Expand Down Expand Up @@ -290,7 +291,7 @@
const nickNameUpdatedUsers = [];
let counter = 0;
for (let i = 0; i < usersToBeEffected.length; i++) {
const { discordId, username, first_name: firstName } = usersToBeEffected[i];

Check warning on line 294 in controllers/discordactions.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Variable Assigned to Object Injection Sink
try {
if (counter % 10 === 0 && counter !== 0) {
await new Promise((resolve) => setTimeout(resolve, 5500));
Expand All @@ -306,7 +307,7 @@
if (message) {
counter++;
totalNicknamesUpdated.count++;
nickNameUpdatedUsers.push(usersToBeEffected[i].id);

Check warning on line 310 in controllers/discordactions.js

View workflow job for this annotation

GitHub Actions / build (20.11.x)

Generic Object Injection Sink
}
}
} catch (error) {
Expand Down
6 changes: 5 additions & 1 deletion controllers/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { CustomResponse } from "../typeDefinitions/global";
import { ExtensionRequestRequest, ExtensionRequestResponse } from "../types/extensionRequests";
import { createTaskExtensionRequest, updateTaskExtensionRequest } from "./extensionRequestsv2";
import { UpdateRequest } from "../types/requests";
import { TaskRequestRequest } from "../types/taskRequests";
import { createTaskRequestController } from "./taskRequestsv2";

export const createRequestController = async (
req: OooRequestCreateRequest | ExtensionRequestRequest,
req: OooRequestCreateRequest | ExtensionRequestRequest | TaskRequestRequest,
res: CustomResponse
) => {
const type = req.body.type;
Expand All @@ -22,6 +24,8 @@ export const createRequestController = async (
return await createOooRequestController(req as OooRequestCreateRequest, res as OooRequestResponse);
case REQUEST_TYPE.EXTENSION:
return await createTaskExtensionRequest(req as ExtensionRequestRequest, res as ExtensionRequestResponse);
case REQUEST_TYPE.TASK:
return await createTaskRequestController(req as TaskRequestRequest, res as CustomResponse);
default:
return res.boom.badRequest("Invalid request type");
}
Expand Down
174 changes: 174 additions & 0 deletions controllers/taskRequestsv2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import { REQUEST_STATE, TASK_REQUEST_MESSAGES } from "../constants/requests";
import { TASK_REQUEST_TYPE } from "../constants/taskRequests";
import { addLog } from "../models/logs";
import { createRequest, getRequestByKeyValues } from "../models/requests";
import { fetchTask } from "../models/tasks";
import { fetchUser } from "../models/users";
import { fetchIssuesById } from "../services/githubService";
import { CustomResponse } from "../typeDefinitions/global";
import { userData } from "../types/global";
import { TaskRequestRequest } from "../types/taskRequests";

export const createTaskRequestController = async (req: TaskRequestRequest, res: CustomResponse) => {
const taskRequestData = req.body;
const requestedBy = req?.userData?.id;

if (!requestedBy) {
return res.boom.unauthorized();
}

if (req.userData.id !== taskRequestData.userId && !req.userData.roles?.super_user) {
return res.boom.forbidden(TASK_REQUEST_MESSAGES.NOT_AUTHORIZED_TO_CREATE_REQUEST);
}

const userPromise: any = await fetchUser({ userId: taskRequestData.userId });
const userData: userData = userPromise.user;
if (!userData.id || !userData.username) {
return res.boom.notFound(TASK_REQUEST_MESSAGES.USER_NOT_FOUND);
}
try {
switch (taskRequestData.requestType) {
case TASK_REQUEST_TYPE.ASSIGNMENT: {
if (!req.userData.roles?.super_user) {
return res.boom.unauthorized(TASK_REQUEST_MESSAGES.NOT_AUTHORIZED_TO_CREATE_REQUEST);
}
const { taskData } = await fetchTask(taskRequestData.taskId);
if (!taskData) {
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_NOT_EXIST);
}
taskRequestData.taskTitle = taskData?.title;
break;
}
case TASK_REQUEST_TYPE.CREATION: {
let issueData: any;
try {
const url = new URL(taskRequestData.externalIssueUrl);
const issueUrlPaths = url.pathname.split("/");
const repositoryName = issueUrlPaths[3];
const issueNumber = issueUrlPaths[5];
issueData = await fetchIssuesById(repositoryName, issueNumber);
} catch (error) {
return res.boom.badRequest(TASK_REQUEST_MESSAGES.INVALID_EXTERNAL_ISSUE_URL);
}
if (!issueData) {
return res.boom.badRequest(TASK_REQUEST_MESSAGES.ISSUE_NOT_EXIST);
}
taskRequestData.taskTitle = issueData?.title;
break;
}
}
const existingRequest = await getRequestByKeyValues({
externalIssueUrl: taskRequestData.externalIssueUrl,
requestType: taskRequestData.requestType,
});

if (
existingRequest &&
existingRequest.state === REQUEST_STATE.PENDING &&
existingRequest.requestors.includes(requestedBy)
) {
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_REQUEST_EXISTS);
} else if (
existingRequest &&
existingRequest.state === REQUEST_STATE.PENDING &&
!existingRequest.requestors.includes(requestedBy)
) {
existingRequest.requestors.push(requestedBy);
existingRequest.users.push({
userId: userData.id,
username: userData.username,
proposedStartDate: taskRequestData.proposedStartDate,
proposedDeadline: taskRequestData.proposedDeadline,
description: taskRequestData.description,
markdownEnabled: taskRequestData.markdownEnabled,
firstName: userData.first_name,
lastName: userData.last_name,
state: REQUEST_STATE.PENDING,
requestedAt: Date.now(),
});
const updatedRequest = await createRequest(existingRequest);
const taskRequestLog = {
type: "taskRequests",
meta: {
taskRequestId: updatedRequest.id,
action: "update",
createdBy: req.userData.id,
createdAt: Date.now(),
lastModifiedBy: req.userData.id,
lastModifiedAt: Date.now(),
},
body: updatedRequest,
};
await addLog(taskRequestLog.type, taskRequestLog.meta, taskRequestLog.body);
const data = {
message: TASK_REQUEST_MESSAGES.TASK_REQUEST_UPDATED_SUCCESS,
data: {
id: updatedRequest.id,
...updatedRequest,
},
};
return res.status(200).json(data);
}

taskRequestData.requestedBy = requestedBy;
const createtaskRequestData = {
externalIssueUrl: taskRequestData.externalIssueUrl,
externalIssueHtmlUrl: taskRequestData.externalIssueHtmlUrl,
requestType: taskRequestData.requestType,
type: taskRequestData.type,
state: REQUEST_STATE.PENDING,
requestedBy: requestedBy,
taskTitle: taskRequestData.taskTitle,
users: [
{
userId: userData.id,
username: userData.username,
proposedStartDate: taskRequestData.proposedStartDate,
proposedDeadline: taskRequestData.proposedDeadline,
description: taskRequestData.description,
markdownEnabled: taskRequestData.markdownEnabled,
firstName: userData.first_name,
lastName: userData.last_name,
state: REQUEST_STATE.PENDING,
requestedAt: Date.now(),
},
],

requestors: [requestedBy],
};
const newTaskRequest = await createRequest(createtaskRequestData);

if (newTaskRequest.isCreationRequestApproved) {
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_EXISTS_FOR_GIVEN_ISSUE);
}
if (newTaskRequest.alreadyRequesting) {
return res.boom.badRequest(TASK_REQUEST_MESSAGES.TASK_ALREADY_REQUESTED);
}

const taskRequestLog = {
type: "taskRequests",
meta: {
taskRequestId: newTaskRequest.id,
action: "create",
createdBy: req.userData.id,
createdAt: Date.now(),
lastModifiedBy: req.userData.id,
lastModifiedAt: Date.now(),
},
body: newTaskRequest,
};
await addLog(taskRequestLog.type, taskRequestLog.meta, taskRequestLog.body);

const data = {
message: TASK_REQUEST_MESSAGES.TASK_REQUEST_CREATED_SUCCESS,
data: {
id: newTaskRequest.id,
...newTaskRequest,
},
};
return res.status(201).json(data);
} catch (err) {
logger.error(`${TASK_REQUEST_MESSAGES.ERROR_CREATING_TASK_REQUEST} : ${err}`);
return res.boom.serverUnavailable(TASK_REQUEST_MESSAGES.ERROR_CREATING_TASK_REQUEST);
}
};
23 changes: 4 additions & 19 deletions controllers/tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,8 @@ const fetchPaginatedTasks = async (query) => {

const fetchTasks = async (req, res) => {
try {
const { dev, status, page, size, prev, next, q: queryString, assignee, title, userFeatureFlag } = req.query;
const transformedQuery = transformQuery(dev, status, size, page, assignee, title);

if (dev) {
const paginatedTasks = await fetchPaginatedTasks({ ...transformedQuery, prev, next, userFeatureFlag });
return res.json({
message: "Tasks returned successfully!",
...paginatedTasks,
});
}
const { status, page, size, prev, next, q: queryString, assignee, title, userFeatureFlag } = req.query;
const transformedQuery = transformQuery(status, size, page, assignee, title);

if (queryString !== undefined) {
const searchParams = parseSearchQuery(queryString);
Expand All @@ -167,17 +159,10 @@ const fetchTasks = async (req, res) => {
});
}

const allTasks = await tasks.fetchTasks();
const tasksWithRdsAssigneeInfo = await fetchTasksWithRdsAssigneeInfo(allTasks);
if (tasksWithRdsAssigneeInfo.length === 0) {
return res.status(404).json({
message: "No tasks found",
tasks: [],
});
}
const paginatedTasks = await fetchPaginatedTasks({ ...transformedQuery, prev, next, userFeatureFlag });
return res.json({
message: "Tasks returned successfully!",
tasks: tasksWithRdsAssigneeInfo,
...paginatedTasks,
});
} catch (err) {
logger.error(`Error while fetching tasks ${err}`);
Expand Down
49 changes: 35 additions & 14 deletions controllers/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const { getPaginationLink, getUsernamesFromPRs, getRoleToUpdate } = require("../
const { setInDiscordFalseScript, setUserDiscordNickname } = require("../services/discordService");
const { generateDiscordProfileImageUrl } = require("../utils/discord-actions");
const { addRoleToUser, getDiscordMembers } = require("../services/discordService");
const { fetchAllUsers, addGithubUserId } = require("../models/users");
const { fetchAllUsers } = require("../models/users");
const { getOverdueTasks } = require("../models/tasks");
const { getQualifiers } = require("../utils/helper");
const { parseSearchQuery } = require("../utils/users");
Expand Down Expand Up @@ -918,19 +918,40 @@ async function usersPatchHandler(req, res) {
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
}
}
const migrations = async (req, res) => {
const { page = 0, size } = req.query;

try {
const result = await addGithubUserId(parseInt(page), parseInt(size));
return res.status(200).json({
message: "Result of migration",
data: result,
});
} catch (error) {
logger.error(`Internal Server Error: ${error}`);
return res.boom.badImplementation(INTERNAL_SERVER_ERROR);
}
const getIdentityStats = async (req, res) => {
const verifiedUsers = await userQuery.fetchUserForKeyValue("profileStatus", "VERIFIED");
const blockedUsers = await userQuery.fetchUserForKeyValue("profileStatus", "BLOCKED");
let developers = [];
const membersInDiscord = await getDiscordMembers();
if (membersInDiscord) {
const developersInDiscord = membersInDiscord.filter(
(discordMember) => discordMember && discordMember.roles && discordMember.roles.includes(discordDeveloperRoleId)
);
developers = developersInDiscord;
}

const findUserByDiscordId = (usersArray, discordId) => usersArray.find((user) => user.discordId === discordId);

const verifiedDeveloperCount = developers.filter((developer) =>
findUserByDiscordId(verifiedUsers, developer.user.id)
).length;
const blockedDeveloperCount = developers.filter((developer) =>
findUserByDiscordId(blockedUsers, developer.user.id)
).length;
const developersLeftToVerifyCount = developers.filter(
(developer) =>
!findUserByDiscordId(verifiedUsers, developer.user.id) && !findUserByDiscordId(blockedUsers, developer.user.id)
).length;

return res.status(200).json({
verifiedUsersCount: verifiedUsers.length,
blockedUsersCount: blockedUsers.length,
verifiedDeveloperCount,
blockedDeveloperCount,
developersLeftToVerifyCount,
developersCount: developers.length,
});
};

module.exports = {
Expand Down Expand Up @@ -962,6 +983,6 @@ module.exports = {
updateDiscordUserNickname,
archiveUserIfNotInDiscord,
usersPatchHandler,
migrations,
isDeveloper,
getIdentityStats,
};
1 change: 1 addition & 0 deletions middlewares/validators/discordactions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { validateMillisecondsTimestamp } = require("./utils");
const validateGroupRoleBody = async (req, res, next) => {
const schema = Joi.object({
rolename: Joi.string().trim().required(),
description: Joi.string().trim(),
});

try {
Expand Down
9 changes: 7 additions & 2 deletions middlewares/validators/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { REQUEST_STATE, REQUEST_TYPE } from "../../constants/requests";
import { OooRequestCreateRequest, OooRequestResponse } from "../../types/oooRequest";
import { createOooStatusRequestValidator } from "./oooRequests";
import { createExtensionRequestValidator } from "./extensionRequestsv2";
import {createTaskRequestValidator} from "./taskRequests";
import { ExtensionRequestRequest, ExtensionRequestResponse } from "../../types/extensionRequests";
import { CustomResponse } from "../../typeDefinitions/global";
import { UpdateRequest } from "../../types/requests";
import { TaskRequestRequest, TaskRequestResponse } from "../../types/taskRequests";

export const createRequestsMiddleware = async (
req: OooRequestCreateRequest|ExtensionRequestRequest,
req: OooRequestCreateRequest|ExtensionRequestRequest | TaskRequestRequest,
res: CustomResponse,
next: NextFunction
) => {
Expand All @@ -27,6 +29,9 @@ export const createRequestsMiddleware = async (
case REQUEST_TYPE.EXTENSION:
await createExtensionRequestValidator(req as ExtensionRequestRequest, res as ExtensionRequestResponse, next);
break;
case REQUEST_TYPE.TASK:
await createTaskRequestValidator(req as TaskRequestRequest, res as TaskRequestResponse, next);
break;
default:
res.boom.badRequest(`Invalid request type: ${type}`);
}
Expand Down Expand Up @@ -82,7 +87,7 @@ export const getRequestsMiddleware = async (req: OooRequestCreateRequest, res: O
id: joi.string().optional(),
type: joi
.string()
.valid(REQUEST_TYPE.OOO, REQUEST_TYPE.EXTENSION, REQUEST_TYPE.ALL)
.valid(REQUEST_TYPE.OOO, REQUEST_TYPE.EXTENSION, REQUEST_TYPE.TASK, REQUEST_TYPE.ALL)
.optional(),
requestedBy: joi.string().insensitive().optional(),
state: joi
Expand Down
Loading
Loading