-
Notifications
You must be signed in to change notification settings - Fork 56
[PROD RELEASE] - Q2 #823
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
base: master
Are you sure you want to change the base?
[PROD RELEASE] - Q2 #823
Conversation
kkartunov
commented
Jun 17, 2025
- QA bug fixes
- Copilot Portal
fix(PM-1077): permission issue to delete copilot invite
PM-589 add migration for fixing copilot request model
@@ -55,6 +65,14 @@ module.exports = function defineProjectMemberInvite(sequelize, DataTypes) { | |||
raw: true, | |||
}); | |||
|
|||
ProjectMemberInvite.getPendingInvitesForApplication = applicationId => ProjectMemberInvite.findAll({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding input validation for applicationId
to ensure it is of the expected type and format before querying the database.
ProjectMemberInvite.getPendingInvitesForApplication = applicationId => ProjectMemberInvite.findAll({ | ||
where: { | ||
applicationId, | ||
status: INVITE_STATUS.PENDING, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that INVITE_STATUS.PENDING
is defined and imported correctly. If it's a constant, verify its source and usage.
|
||
LIST_COPILOT_OPPORTUNITY: { | ||
meta: { | ||
title: 'Apply copilot opportunity', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The title
for LIST_COPILOT_OPPORTUNITY
seems to be incorrect as it duplicates the title from APPLY_COPILOT_OPPORTUNITY
. Consider changing it to something more appropriate like 'List copilot opportunities'.
meta: { | ||
title: 'Apply copilot opportunity', | ||
group: 'Apply Copilot', | ||
description: 'Who can apply for copilot opportunity.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description
for LIST_COPILOT_OPPORTUNITY
is identical to the one for APPLY_COPILOT_OPPORTUNITY
. It might be more accurate to describe what listing copilot opportunities entails.
@@ -599,6 +638,7 @@ export const PERMISSION = { // eslint-disable-line import/prefer-default-export | |||
topcoderRoles: [ | |||
...TOPCODER_ROLES_ADMINS, | |||
USER_ROLE.COPILOT_MANAGER, | |||
USER_ROLE.PROJECT_MANAGER, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider verifying if the addition of USER_ROLE.PROJECT_MANAGER
to topcoderRoles
is necessary for the intended functionality, as it might affect permissions and access control.
* @return {Promise} Returns a promise | ||
*/ | ||
module.exports = freq => new Promise((resolve, reject) => { | ||
const opportunityId = _.parseInt(freq.params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding validation to ensure freq.params.id
is a valid number before using _.parseInt
. This could prevent potential issues if the parameter is not a number.
*/ | ||
module.exports = freq => new Promise((resolve, reject) => { | ||
const opportunityId = _.parseInt(freq.params.id); | ||
const currentUserId = freq.authUser.userId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that freq.authUser
and freq.authUser.userId
are defined before accessing userId
. This will prevent runtime errors if authUser
is undefined.
module.exports = freq => new Promise((resolve, reject) => { | ||
const opportunityId = _.parseInt(freq.params.id); | ||
const currentUserId = freq.authUser.userId; | ||
return models.CopilotOpportunity.findOne({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error handling for the findOne
operation. If the database query fails, it should be handled gracefully.
req.context.currentOpportunity = opportunity; | ||
const isProjectManager = util.hasProjectManagerRole(req); | ||
|
||
return models.CopilotApplication.findOne({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the previous comment, add error handling for this findOne
operation to manage potential database query failures.
// user is not an admin nor is a registered project member | ||
return reject(new Error(errorMessage)); | ||
} | ||
return resolve(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a catch block at the end of the promise chain to handle any unexpected errors that might occur during the execution of the promise.
@@ -199,4 +200,7 @@ module.exports = () => { | |||
Authorizer.setPolicy('customerPayment.view', generalPermission(PERMISSION.VIEW_CUSTOMER_PAYMENT)); | |||
Authorizer.setPolicy('customerPayment.edit', generalPermission(PERMISSION.UPDATE_CUSTOMER_PAYMENT)); | |||
Authorizer.setPolicy('customerPayment.confirm', customerPaymentConfirm); | |||
|
|||
// Copilot opportunity |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment // Copilot opportunity
could be more descriptive to clarify the purpose of the policy being set for copilotApplications.view
. Consider providing a more detailed explanation in the code logic or documentation.
import { PERMISSION } from '../../permissions/constants'; | ||
import { COPILOT_APPLICATION_STATUS, COPILOT_OPPORTUNITY_STATUS, COPILOT_REQUEST_STATUS, EVENT, INVITE_STATUS, PROJECT_MEMBER_ROLE, RESOURCES } from '../../constants'; | ||
|
||
const assignCopilotOpportunityValidations = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validation schema for applicationId
should include a required()
constraint to ensure that this field is always provided in the request body.
validate(assignCopilotOpportunityValidations), | ||
async (req, res, next) => { | ||
const { applicationId } = req.body; | ||
const copilotOpportunityId = _.parseInt(req.params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a check to ensure applicationId
is not null or undefined before proceeding, to prevent potential runtime errors.
return next(err); | ||
} | ||
|
||
return models.sequelize.transaction(async (t) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a try-catch block around the transaction to handle any unexpected errors that might occur during the transaction process.
}, { | ||
transaction: t, | ||
}) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing semicolon at the end of the statement. Ensure consistent use of semicolons throughout the code.
async (req, res, next) => { | ||
const { notes } = req.body; | ||
const copilotOpportunityId = _.parseInt(req.params.id); | ||
if (!util.hasPermissionByReq(PERMISSION.APPLY_COPILOT_OPPORTUNITY, req)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider checking if req.params.id
is defined before parsing it with _.parseInt
. This will help avoid potential errors if id
is not provided.
createdBy: req.authUser.userId, | ||
updatedBy: req.authUser.userId, | ||
opportunityId: copilotOpportunityId, | ||
notes: notes ? req.sanitize(notes) : null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that req.sanitize
is properly defined and implemented to avoid any security vulnerabilities related to input sanitization.
}); | ||
|
||
if (existingApplication) { | ||
res.status(200).json(existingApplication); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning the existing application with a 200 status code might not be appropriate if the intention is to indicate that the application already exists. Consider using a different status code or providing additional context in the response.
|
||
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; | ||
const copilotPortalUrl = config.get('copilotPortalUrl'); | ||
listOfSubjects.forEach((subject) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider handling potential errors in the listOfSubjects.forEach
loop, especially if createEvent
fails for any subject. This will help ensure that the application process is robust and can handle failures gracefully.
(req, res, next) => { | ||
const canAccessAllApplications = util.hasRoles(req, ADMIN_ROLES) || util.hasProjectManagerRole(req); | ||
const userId = req.authUser.userId; | ||
const opportunityId = _.parseInt(req.params.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding validation to ensure req.params.id
is a valid integer before using _.parseInt
to prevent unexpected behavior if the parameter is not a number.
} | ||
const sortableProps = ['createdAt asc', 'createdAt desc']; | ||
if (_.indexOf(sortableProps, sort) < 0) { | ||
return util.handleError('Invalid sort criteria', null, req, next); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The util.handleError
function is called with null
as the second argument. Ensure this is intentional and that the function can handle null
appropriately.
as: 'copilotOpportunity', | ||
}, | ||
], | ||
order: [[sortParams[0], sortParams[1]]], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The order
array uses sortParams
directly from user input. Consider validating sortParams
further to prevent potential SQL injection or unexpected behavior.
@@ -35,7 +35,7 @@ module.exports = [ | |||
updatedBy: req.authUser.userId, | |||
}); | |||
|
|||
return approveRequest(data) | |||
return approveRequest(req, data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approveRequest
function signature has been changed to include req
as a parameter. Ensure that the approveRequest
function definition and its internal logic are updated accordingly to handle the req
parameter.
@@ -11,7 +14,7 @@ const resolveTransaction = (transaction, callback) => { | |||
return models.sequelize.transaction(callback); | |||
}; | |||
|
|||
module.exports = (data, existingTransaction) => { | |||
module.exports = (req, data, existingTransaction) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function signature has been changed to include a new parameter req
. Ensure that this parameter is used within the function or is necessary for future use. If not, consider removing it to maintain clean code.
@@ -52,6 +55,29 @@ module.exports = (data, existingTransaction) => { | |||
return models.CopilotOpportunity | |||
.create(data, { transaction }); | |||
})) | |||
.then(async (opportunity) => { | |||
const roles = await util.getRolesByRoleName(USER_ROLE.TC_COPILOT, req.log, req.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error handling for the getRolesByRoleName
function call to ensure that any issues retrieving roles are properly managed.
@@ -52,6 +55,29 @@ module.exports = (data, existingTransaction) => { | |||
return models.CopilotOpportunity | |||
.create(data, { transaction }); | |||
})) | |||
.then(async (opportunity) => { | |||
const roles = await util.getRolesByRoleName(USER_ROLE.TC_COPILOT, req.log, req.id); | |||
const { subjects = [] } = await util.getRoleInfo(roles[0], req.log, req.id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check if roles
array is empty before accessing roles[0]
to avoid potential runtime errors.
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; | ||
const copilotPortalUrl = config.get('copilotPortalUrl'); | ||
req.log.info("Sending emails to all copilots about new opportunity"); | ||
subjects.forEach(subject => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding a check to ensure subjects
is not empty before iterating over it to prevent unnecessary operations.
const copilotPortalUrl = config.get('copilotPortalUrl'); | ||
req.log.info("Sending emails to all copilots about new opportunity"); | ||
subjects.forEach(subject => { | ||
createEvent(emailEventType, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The createEvent
function call should include error handling to manage any potential failures in sending emails.
@@ -98,7 +98,7 @@ module.exports = [ | |||
updatedBy: req.authUser.userId, | |||
type: copilotRequest.data.projectType, | |||
}); | |||
return approveRequest(approveData, transaction).then(() => copilotRequest); | |||
return approveRequest(req, approveData, transaction).then(() => copilotRequest); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approveRequest
function now takes req
as an additional parameter. Ensure that the function definition and implementation of approveRequest
are updated accordingly to handle this new parameter. Also, verify that req
is necessary for the function's logic and that it is used appropriately within the function.
@@ -1,7 +1,6 @@ | |||
import _ from 'lodash'; | |||
|
|||
import models from '../../models'; | |||
import { ADMIN_ROLES } from '../../constants'; | |||
import util from '../../util'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statement for ADMIN_ROLES
has been removed. Ensure that this removal is intentional and that ADMIN_ROLES
is not used elsewhere in the code, as this could lead to runtime errors if it is still needed.
isAdmin ? {} : { createdBy: userId }, | ||
projectId ? { projectId } : {}, | ||
); | ||
const whereCondition = projectId ? { projectId } : {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of the createdBy
condition means that now all users, not just admins, can see all requests if a projectId
is not specified. If this change is intentional, ensure that it aligns with the desired access control policies. Otherwise, consider re-implementing the logic to restrict visibility based on user roles.
`/${apiVersion}/projects/copilots/opportunities`, | ||
`/${apiVersion}/projects/copilot/opportunities/:id(\\d+)`, | ||
new RegExp(`^/${apiVersion}/projects/copilots/opportunities$`), | ||
new RegExp(`^/${apiVersion}/projects/copilot/opportunity/\\d+$`), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regex pattern for the copilot opportunity endpoint has been changed from opportunities/:id(\\d+)
to opportunity/\\d+
. Ensure that this change is intentional and that the endpoint is correctly updated in other parts of the application to reflect this singular form and pattern.
@@ -35,7 +35,7 @@ const jwtAuth = require('tc-core-library-js').middleware.jwtAuthenticator; | |||
router.all( | |||
RegExp(`\\/${apiVersion}\\/(copilots|projects|timelines|orgConfig|customer-payments)(?!\\/health).*`), | |||
(req, res, next) => { | |||
if (publicRoutes.some(route => req.path.match(new RegExp(`^${route}$`)))) { | |||
if (publicRoutes.some(routeRegex => routeRegex.test(req.path))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider renaming routeRegex
to routePattern
for clarity, as it represents a regex pattern rather than a specific route.
req.log.debug(req.authUser); | ||
const emailEventType = CONNECT_NOTIFICATION_EVENT.PROJECT_MEMBER_EMAIL_INVITE_CREATED; | ||
const emailEventType = CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The change from CONNECT_NOTIFICATION_EVENT.PROJECT_MEMBER_EMAIL_INVITE_CREATED
to CONNECT_NOTIFICATION_EVENT.EXTERNAL_ACTION_EMAIL
should be verified to ensure it aligns with the intended functionality. This change may affect the type of email notification sent, so please confirm that this is the desired behavior.
@@ -237,13 +238,9 @@ const sendInviteEmail = (req, projectId, invite) => { | |||
], | |||
}], | |||
}, | |||
sendgrid_template_id: TEMPLATE_IDS.PROJECT_MEMBER_INVITED, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sendgrid_template_id
is being added here. Ensure that TEMPLATE_IDS.PROJECT_MEMBER_INVITED
is defined and correctly set up in your configuration to avoid runtime errors.
@@ -237,13 +238,9 @@ const sendInviteEmail = (req, projectId, invite) => { | |||
], | |||
}], | |||
}, | |||
sendgrid_template_id: TEMPLATE_IDS.PROJECT_MEMBER_INVITED, | |||
recipients: [invite.email], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The recipients
field is correctly set to invite.email
. Ensure that invite.email
is validated and sanitized to prevent any potential security issues.
@@ -237,13 +238,9 @@ const sendInviteEmail = (req, projectId, invite) => { | |||
], | |||
}], | |||
}, | |||
sendgrid_template_id: TEMPLATE_IDS.PROJECT_MEMBER_INVITED, | |||
recipients: [invite.email], | |||
version: 'v3', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The from
field has been removed. Verify that the email sending service has a default sender configured, or ensure that the removal of this field does not affect the email delivery.
name: config.get('EMAIL_INVITE_FROM_NAME'), | ||
email: config.get('EMAIL_INVITE_FROM_EMAIL'), | ||
}, | ||
categories: [`${process.env.NODE_ENV}:${emailEventType}`.toLowerCase()], | ||
}, req.log); | ||
}).catch((error) => { | ||
req.log.error(error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding more detailed error handling or logging to capture specific error scenarios that might occur during the email sending process.
@@ -295,13 +292,12 @@ module.exports = [ | |||
// whom we are inviting, because Member Service has a loose search logic and may return | |||
// users with handles whom we didn't search for | |||
.then((foundUsers) => { | |||
if(invite.handles) { | |||
if (invite.handles) { | |||
const lowerCaseHandles = invite.handles.map(handle => handle.toLowerCase()); | |||
return foundUsers.filter(foundUser => _.includes(lowerCaseHandles, foundUser.handleLower)); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using consistent formatting for the if
statement. The opening brace should be on the same line as the if
condition, as per common JavaScript style guides.
return [] | ||
} | ||
|
||
return []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure consistent use of semicolons throughout the code. The addition of a semicolon here is good, but verify that all statements in the file follow this convention for consistency.
Object.assign({}, v.toJSON(), { | ||
source: 'work_manager', | ||
}), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an extra comma at the end of the Object.assign
call. Ensure that the formatting is consistent with the rest of the codebase.
@@ -74,14 +74,31 @@ module.exports = [ | |||
.update({ | |||
status: INVITE_STATUS.CANCELED, | |||
}) | |||
.then((updatedInvite) => { | |||
.then(async (updatedInvite) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of async
in the .then()
function suggests that there might be an await
operation inside this function. Please ensure that any asynchronous operations are properly handled within this block. If there are no await
operations, consider removing async
to avoid unnecessary complexity.
// emit the event | ||
util.sendResourceToKafkaBus( | ||
req, | ||
EVENT.ROUTING_KEY.PROJECT_MEMBER_INVITE_REMOVED, | ||
RESOURCES.PROJECT_MEMBER_INVITE, | ||
updatedInvite.toJSON()); | ||
|
||
// update the application if the invite | ||
// originated from copilot opportunity | ||
if (invite.applicationId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error handling for the case where invite.applicationId
is not found or getPendingInvitesForApplication
fails. This will help prevent potential runtime errors.
const allPendingInvitesForApplication = await models.ProjectMemberInvite.getPendingInvitesForApplication(invite.applicationId); | ||
// If only the current invite is the open one's | ||
// then the application status has to be moved to pending status | ||
if (allPendingInvitesForApplication.length === 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The condition allPendingInvitesForApplication.length === 0
might be incorrect if getPendingInvitesForApplication
returns an array with the current invite included. Ensure that the logic correctly identifies when there are no other pending invites.
@@ -1,12 +1,14 @@ | |||
import validate from 'express-validation'; | |||
import _ from 'lodash'; | |||
import Joi from 'joi'; | |||
import { Op } from 'sequelize'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statement for Op
from 'sequelize' is added but not used in the current code. Consider removing it if it's not needed.
import { PERMISSION } from '../../permissions/constants'; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an unnecessary blank line added here. Consider removing it to keep the code clean and consistent.
@@ -19,6 +21,8 @@ const updateMemberValidations = { | |||
status: Joi.any() | |||
.valid(_.values(INVITE_STATUS)) | |||
.required(), | |||
source: Joi.string() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider validating the source
field to ensure it only accepts specific values, similar to how status
is validated. This can help prevent invalid data from being accepted.
@@ -29,6 +33,7 @@ module.exports = [ | |||
permissions('projectMemberInvite.edit'), | |||
(req, res, next) => { | |||
const newStatus = req.body.status; | |||
const source = req.body.source; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider validating the source
field to ensure it contains expected values before using it further in the code. This can help prevent potential issues from unexpected input.
@@ -81,7 +86,7 @@ module.exports = [ | |||
.update({ | |||
status: newStatus, | |||
}) | |||
.then((updatedInvite) => { | |||
.then(async (updatedInvite) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use of async
in the .then
function suggests that there might be an await
operation inside the function. Please ensure that any asynchronous operations within this function are properly handled with await
. If there are no asynchronous operations, consider removing async
for clarity.
@@ -94,7 +99,7 @@ module.exports = [ | |||
if (updatedInvite.status === INVITE_STATUS.ACCEPTED || | |||
updatedInvite.status === INVITE_STATUS.REQUEST_APPROVED) { | |||
return models.ProjectMember.getActiveProjectMembers(projectId) | |||
.then((members) => { | |||
.then(async (members) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using async
in a .then()
method can be confusing and is generally not recommended. Consider using await
within an async
function instead of chaining .then()
. This can improve readability and maintainability of the code.
.addUserToProject(req, member) | ||
.then(() => res.json(util.postProcessInvites('$.email', updatedInvite, req))) | ||
.catch(err => next(err)); | ||
const t = await models.sequelize.transaction(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error handling for the transaction initialization. If models.sequelize.transaction()
fails, it could lead to unhandled exceptions.
transaction: t, | ||
}); | ||
|
||
await application.update({ status: nextApplicationStatus }, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that application
is not null before calling update
on it. If findOne
does not find a record, application
will be null, leading to a runtime error.
transaction: t | ||
}); | ||
|
||
const opportunity = await models.CopilotOpportunity.findOne({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that opportunity
is not null before calling update
on it. If findOne
does not find a record, opportunity
will be null, leading to a runtime error.
transaction: t, | ||
}); | ||
|
||
const request = await models.CopilotRequest.findOne({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that request
is not null before calling update
on it. If findOne
does not find a record, request
will be null, leading to a runtime error.
// update the application if the invite | ||
// originated from copilot opportunity | ||
if (updatedInvite.applicationId) { | ||
const allPendingInvitesForApplication = await models.ProjectMemberInvite.getPendingInvitesForApplication(invite.applicationId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error handling for getPendingInvitesForApplication
. If it fails, it could lead to unhandled exceptions.
@@ -225,6 +225,23 @@ const projectServiceUtils = { | |||
return _.intersection(roles, ADMIN_ROLES.map(r => r.toLowerCase())).length > 0; | |||
}, | |||
|
|||
/** | |||
* Helper funtion to verify if user has project manager role |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in the comment: 'funtion' should be corrected to 'function'.
const isMachineToken = _.get(req, 'authUser.isMachine', false); | ||
const tokenScopes = _.get(req, 'authUser.scopes', []); | ||
if (isMachineToken) { | ||
if (_.indexOf(tokenScopes, M2M_SCOPES.CONNECT_PROJECT_ADMIN) >= 0) return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider simplifying the condition by directly returning the result of the comparison: return _.indexOf(tokenScopes, M2M_SCOPES.CONNECT_PROJECT_ADMIN) >= 0;
.
return _.get(res, 'data.result.content', []); | ||
}); | ||
} catch (err) { | ||
logger.debug(err, "error on getting role info"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using logger.error
instead of logger.debug
for logging errors to ensure they are appropriately flagged in the logs.
.map(r => r.id); | ||
}); | ||
} catch (err) { | ||
return Promise.reject(err); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding error logging similar to the getRoleInfo
method to capture and debug errors effectively.