Skip to content

Pm 4393 ai#1748

Open
kkartunov wants to merge 2 commits intodevelopfrom
PM-4393-AI
Open

Pm 4393 ai#1748
kkartunov wants to merge 2 commits intodevelopfrom
PM-4393-AI

Conversation

@kkartunov
Copy link
Contributor

@kkartunov kkartunov commented Mar 19, 2026

Impelments the fix with Factory.AI


Open with Devin

@kkartunov kkartunov requested a review from Copilot March 19, 2026 08:39
const isProjectDetailLoaded = reduxProjectInfo && `${reduxProjectInfo.id}` === `${projectId}`
const isAdmin = checkAdmin(auth.token)
const isCopilot = checkCopilot(auth.token)
const isProjectMember = isProjectDetailLoaded && checkIsProjectMember(auth.token, reduxProjectInfo)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 performance]
The checkIsProjectMember function is called only if isProjectDetailLoaded is true. If checkIsProjectMember has side effects or is computationally expensive, consider whether this conditional logic is necessary or if it could be simplified.

const canAccessProject = isAdmin || isCopilot || isProjectMember || hasProjectAccess

// Show access denied message if user cannot access this project
const accessDeniedMessage = isProjectRoute && isProjectDetailLoaded && !canAccessProject

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[💡 readability]
The accessDeniedMessage logic is embedded directly in the return statement. Consider extracting this logic into a separate function for better readability and maintainability.

.catch((error) => {
if (isActive) {
history.replace('/projects')
const status = _.get(error, 'payload.response.status', _.get(error, 'response.status'))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ maintainability]
Using _.get to access nested properties in the error object is a good practice to avoid runtime errors. However, consider logging the error or handling other potential error statuses to improve error handling and debugging.

}

// Handle 403 access denied - redirect to challenges page which will show the error
if (accessDenied || !hasProjectAccess) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[⚠️ correctness]
The check for accessDenied and hasProjectAccess is correctly redirecting to the challenges page. However, ensure that the hasProjectAccess prop is always correctly set in the Redux state to avoid unexpected redirects.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the project entry flow and challenges page to better handle “no access” scenarios (notably HTTP 403), aiming to route users to the challenges page and display an appropriate access-denied message.

Changes:

  • Add 403-aware handling in ProjectEntry to redirect forbidden project visits to the project challenges route.
  • Add access checks in Challenges to compute whether the user can access the current project and override warnMessage with an access-denied message.
  • Plumb projects.hasProjectAccess into both containers via mapStateToProps.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/containers/ProjectEntry/index.js Adds access-denied state and redirects 403 responses to the project challenges route.
src/containers/Challenges/index.js Adds project access evaluation (admin/copilot/member/flag) and conditionally displays an access-denied warning message.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines 128 to 133
activeProjectId,
projectId,
status,
projectDetail: reduxProjectInfo,
hasProjectAccess,
loadChallengesByPage,
Comment on lines +171 to +172
// Show access denied message if user cannot access this project
const accessDeniedMessage = isProjectRoute && isProjectDetailLoaded && !canAccessProject
Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +129 to 135
projectId,
status,
projectDetail: reduxProjectInfo,
hasProjectAccess,
loadChallengesByPage,
page,
perPage,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Duplicate projectId destructuring in const binding causes SyntaxError

projectId is destructured twice from this.props in the same const destructuring assignment (lines 129 and 140). In standard JavaScript, this is a SyntaxError — const bindings do not allow duplicate identifiers. The PR added projectId at line 129 but forgot to remove the original at line 140. Depending on the Babel transpilation pipeline, this either crashes at build time or silently produces confusing code.

(Refers to lines 129-140)

Prompt for agents
In src/containers/Challenges/index.js, the render() method's const destructuring declares `projectId` twice — at line 129 and at line 140. Remove the duplicate at line 140 (`projectId,`). The intent was to move `projectId` earlier in the destructuring (line 129) to group it with related variables, but the original on line 140 was not removed.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +169 to +174
const canAccessProject = isAdmin || isCopilot || isProjectMember || hasProjectAccess

// Show access denied message if user cannot access this project
const accessDeniedMessage = isProjectRoute && isProjectDetailLoaded && !canAccessProject
? "You don't have access to this project. Please contact support@topcoder.com."
: warnMessage

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Access denied message condition is logically unreachable — mutually exclusive guards

The access denied message at line 172 requires both isProjectDetailLoaded and !canAccessProject to be true, but these conditions are mutually exclusive:

  • On 403 (API failure): The reducer at src/reducers/projects.js:141 sets hasProjectAccess: false but does NOT update projectDetail, so isProjectDetailLoaded (which checks reduxProjectInfo.id === projectId) is false. The condition fails on isProjectDetailLoaded.
  • On 200 (API success): The reducer at src/reducers/projects.js:147 sets hasProjectAccess: true, which makes canAccessProject (isAdmin || isCopilot || isProjectMember || hasProjectAccess) always true. The condition fails on !canAccessProject.

As a result, the access denied message string is dead code and will never be displayed to users who lack project access. The entire access-control feature added by this PR is non-functional.

Root cause: hasProjectAccess is both a condition guard and a fallback

Including hasProjectAccess in canAccessProject on line 169 makes it impossible for canAccessProject to be false when the project detail has loaded successfully, because LOAD_PROJECT_DETAILS_SUCCESS always sets hasProjectAccess: true. A possible fix is to remove isProjectDetailLoaded from the condition on line 172 and instead rely solely on !hasProjectAccess for the 403 case, OR remove hasProjectAccess from canAccessProject on line 169 and use it only in the outer condition.

Prompt for agents
In src/containers/Challenges/index.js, lines 163-174 implement an access-denied check that is logically unreachable. The condition on line 172 requires `isProjectDetailLoaded && !canAccessProject`, but these are mutually exclusive because `canAccessProject` includes `hasProjectAccess` (line 169), which is always `true` when the project detail has loaded (set by the reducer on LOAD_PROJECT_DETAILS_SUCCESS at src/reducers/projects.js:147).

To fix this, choose one of:

1. For the 403 case (project didn't load): Replace the condition on line 172 with `isProjectRoute && !hasProjectAccess` (remove the `isProjectDetailLoaded` requirement). This handles the case where the API returned 403 and no project detail is available.

2. For the membership check case (project loaded but user lacks role): Remove `hasProjectAccess` from `canAccessProject` on line 169 so the condition becomes `const canAccessProject = isAdmin || isCopilot || isProjectMember`. Then the `isProjectDetailLoaded && !canAccessProject` check on line 172 will correctly trigger when the project is loaded but the user lacks the required role.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants