Skip to content

Revert "Issue Reviewer Role" #279

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

Merged
merged 1 commit into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 0 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,84 +115,6 @@ This script will load the data from `scripts/data` directory into ES
npm run start
```

### Local Deployment
0. Make sure to use Node v10+ by command `node -v`. We recommend using [NVM](https://github.com/nvm-sh/nvm) to quickly switch to the right version:

```bash
nvm use
```

1. 📦 Install npm dependencies

```bash
npm install
```

2. ⚙ Local config
In the `submissions-api` root directory create `.env` file with the next environment variables. Values for **Auth0 config** should be shared with you on the forum.<br>
```bash
# AWS related config
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
S3_BUCKET=
ARTIFACT_BUCKET=

# Auth0 config
AUTH0_URL=
AUTH0_PROXY_SERVER_URL=
TOKEN_CACHE_TIME=
AUTH0_AUDIENCE=
AUTH0_CLIENT_ID=
AUTH0_CLIENT_SECRET=

# Locally deployed services (via docker-compose)
ES_HOST=localhost:9200
```

- Values from this file would be automatically used by many `npm` commands.
- ⚠️ Never commit this file or its copy to the repository!

3. 🚢 Start docker-compose with services which are required to start Topcoder Submissions API locally

```bash
npm run services:up
```
- `npm run services:down` can be used to shutdown the docker services
- `npm run services:logs` can be used to view the logs from the docker services

4. ♻ Create tables.

```bash
npm run create-tables
```
5. ♻ Create ES index.

```bash
npm run create-index
```

6. ♻ Init DB, ES

```bash
npm run local:init
```

This command will do 2 things:
- Import the data to the database and index it to ElasticSearch
- Note, to migrate the existing data from DynamoDB to ES, run the following script
```
npm run db-to-es
```

7. 🚀 Start Topcoder Submissions API

```bash
npm run start
```
The Topcoder Submissions API will be served on `http://localhost:3000`


#### Linting JS files

```
Expand Down
13 changes: 0 additions & 13 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,6 @@ _.each(routes, (verbs, url) => {
})
}

if (def.blockByIp) {
actions.push((req, res, next) => {
req.authUser.blockIP = _.find(req.authUser, (value, key) => {
return (key.indexOf('blockIP') !== -1)
})
if (req.authUser.blockIP) {
throw new errors.HttpStatusError(403, 'Access denied')
} else {
next()
}
})
}

actions.push(method)
winston.info(`API : ${verb.toLocaleUpperCase()} ${config.API_VERSION}${url}`)
apiRouter[verb](`${config.API_VERSION}${url}`, helper.autoWrapExpress(actions))
Expand Down
14 changes: 2 additions & 12 deletions config/default.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Default configuration file
*/
require('dotenv').config()

module.exports = {
DISABLE_LOGGING: process.env.DISABLE_LOGGING || false, // If true, logging will be disabled
LOG_LEVEL: process.env.LOG_LEVEL || 'debug',
Expand Down Expand Up @@ -42,15 +42,5 @@ module.exports = {
AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL,
FETCH_CREATED_DATE_START: process.env.FETCH_CREATED_DATE_START || '2021-01-01',
FETCH_PAGE_SIZE: process.env.FETCH_PAGE_SIZE || 500,
MIGRATE_CHALLENGES: process.env.MIGRATE_CHALLENGES || [],

V5TOLEGACYSCORECARDMAPPING: {
'c56a4180-65aa-42ec-a945-5fd21dec0501': 30001363,
'c56a4180-65aa-42ec-a945-5fd21dec0502': 123456789,
'c56a4180-65aa-42ec-a945-5fd21dec0503': 30001031,
'c56a4180-65aa-42ec-a945-5fd21dec0504': 987654321,
'c56a4180-65aa-42ec-a945-5fd21dec0505': 987123456,
'9ecc88e5-a4ee-44a4-8ec1-70bd98022510': 123789456,
'd6d31f34-8ee5-4589-ae65-45652fcc01a6': 30000720
}
MIGRATE_CHALLENGES: process.env.MIGRATE_CHALLENGES || []
}
12 changes: 3 additions & 9 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1757,9 +1757,7 @@ components:
description: The scoreCardId filter of the reviews associated with the submission.
required: false
schema:
oneOf:
- type: integer
- type: string
type: integer
filterSubmissionReviewSubmissionId:
in: query
name: review.submissionId
Expand Down Expand Up @@ -1873,9 +1871,7 @@ components:
description: The score card id filter for reviews.
required: false
schema:
oneOf:
- type: integer
- type: string
type: integer
filterReviewSubmissionId:
in: query
name: submissionId
Expand Down Expand Up @@ -2151,9 +2147,7 @@ components:
example: a12bc280-65ab-42ec-a945-5fd21dec1567
description: The review reviewer id.
scoreCardId:
oneOf:
- type: integer
- type: string
type: integer
description: The review score card id.
example: 123456789
submissionId:
Expand Down
8 changes: 0 additions & 8 deletions local/docker-compose.yml

This file was deleted.

7 changes: 1 addition & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@
"test": "mocha test/unit/*.test.js --require test/unit/prepare.js --exit",
"e2e": "mocha test/e2e/*.test.js --require test/e2e/prepare.js --exit",
"cov": "nyc --reporter=html --reporter=text mocha test/unit/*.test.js --require test/unit/prepare.js --exit",
"cov-e2e": "nyc --reporter=html --reporter=text mocha test/e2e/*.test.js --require test/e2e/prepare.js --exit",
"services:up": "docker-compose -f ./local/docker-compose.yml up -d",
"services:down": "docker-compose -f ./local/docker-compose.yml down",
"services:logs": "docker-compose -f ./local/docker-compose.yml logs",
"local:init": "npm run init-db && npm run init-es"
"cov-e2e": "nyc --reporter=html --reporter=text mocha test/e2e/*.test.js --require test/e2e/prepare.js --exit"
},
"dependencies": {
"amazon-s3-uri": "0.0.3",
Expand All @@ -34,7 +30,6 @@
"common-errors": "^1.0.4",
"config": "^1.26.2",
"cors": "^2.8.4",
"dotenv": "^8.2.0",
"elasticsearch": "^15.1.1",
"express": "^4.15.4",
"express-fileupload": "^0.4.0",
Expand Down
97 changes: 8 additions & 89 deletions src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,6 @@ function * getLegacyChallengeId (challengeId) {
const response = yield request.get(`${config.CHALLENGEAPI_V5_URL}/${challengeId}`)
.set('Authorization', `Bearer ${token}`)
.set('Content-Type', 'application/json')
if (_.get(response.body, 'legacy.pureV5')) {
// pure V5 challenges don't have a legacy ID
return null
}
const legacyId = parseInt(response.body.legacyId, 10)
logger.debug(`Legacy challenge id is ${legacyId} for v5 challenge id ${challengeId}`)
return legacyId
Expand Down Expand Up @@ -379,15 +375,12 @@ function * getSubmissionPhaseId (challengeId) {
const checkPoint = _.filter(phases, { name: 'Checkpoint Submission', isOpen: true })
const submissionPh = _.filter(phases, { name: 'Submission', isOpen: true })
const finalFixPh = _.filter(phases, { name: 'Final Fix', isOpen: true })
const approvalPh = _.filter(phases, { name: 'Approval', isOpen: true })
if (checkPoint.length !== 0) {
phaseId = checkPoint[0].phaseId
} else if (submissionPh.length !== 0) {
phaseId = submissionPh[0].phaseId
} else if (finalFixPh.length !== 0) {
phaseId = finalFixPh[0].phaseId
} else if (approvalPh.length !== 0) {
phaseId = approvalPh[0].phaseId
}
}
return phaseId
Expand Down Expand Up @@ -452,18 +445,7 @@ function * checkCreateAccess (authUser, subEntity) {

// Get phases and winner detail from challengeDetails
const phases = challengeDetails.body.phases

// Check if the User is assigned as the reviewer for the contest
const reviewers = _.filter(currUserRoles, { role: 'Reviewer' })
if (reviewers.length !== 0) {
throw new errors.HttpStatusError(400, `You cannot create a submission for a challenge while you are a reviewer`)
}

// Check if the User is assigned as the iterative reviewer for the contest
const iterativeReviewers = _.filter(currUserRoles, { role: 'Iterative Reviewer' })
if (iterativeReviewers.length !== 0) {
throw new errors.HttpStatusError(400, `You cannot create a submission for a challenge while you are an iterative reviewer`)
}
const winner = challengeDetails.body.winners

// Check if the User is assigned as the reviewer for the contest
const reviewers = _.filter(currUserRoles, { role: 'Reviewer' })
Expand All @@ -486,22 +468,14 @@ function * checkCreateAccess (authUser, subEntity) {
const submissionPhaseId = yield getSubmissionPhaseId(subEntity.challengeId)

if (submissionPhaseId == null) {
throw new errors.HttpStatusError(403, 'You cannot create a submission in the current phase')
throw new errors.HttpStatusError(403, 'You are not allowed to submit when submission phase is not open')
}

const currPhase = _.filter(phases, { phaseId: submissionPhaseId })

if (currPhase[0].name === 'Final Fix' || currPhase[0].name === 'Approval') {
// Check if the user created a submission in the Submission phase - only such users
// will be allowed to submit during final phase
const userSubmission = yield fetchFromES({
challengeId,
memberId: authUser.userId
}, camelize('Submission'))

// User requesting submission haven't made any submission - prevent them for creating one
if (userSubmission.total === 0) {
throw new errors.HttpStatusError(403, 'You are not expected to create a submission in the current phase')
if (currPhase[0].name === 'Final Fix') {
if (!authUser.handle.equals(winner[0].handle)) {
throw new errors.HttpStatusError(403, 'Only winner is allowed to submit during Final Fix phase')
}
}
} else {
Expand Down Expand Up @@ -605,7 +579,7 @@ function * checkGetAccess (authUser, submission) {
const appealsResponseStatus = getPhaseStatus('Appeals Response', challengeDetails.body)

// Appeals Response is not closed yet
if (appealsResponseStatus !== 'Closed' && appealsResponseStatus !== 'Invalid') {
if (appealsResponseStatus !== 'Closed') {
throw new errors.HttpStatusError(403, 'You cannot access other submissions before the end of Appeals Response phase')
} else {
const userSubmission = yield fetchFromES({
Expand Down Expand Up @@ -641,21 +615,10 @@ function * checkGetAccess (authUser, submission) {
* @returns {Promise}
*/
function * checkReviewGetAccess (authUser, submission) {
let resources
let challengeDetails
const token = yield getM2Mtoken()
const challengeId = yield getV5ChallengeId(submission.challengeId)

try {
resources = yield request.get(`${config.RESOURCEAPI_V5_BASE_URL}/resources?challengeId=${challengeId}`)
.set('Authorization', `Bearer ${token}`)
.set('Content-Type', 'application/json')
} catch (ex) {
logger.error(`Error while accessing ${config.RESOURCEAPI_V5_BASE_URL}/resources?challengeId=${challengeId}`)
logger.error(ex)
throw new errors.HttpStatusError(503, `Could not determine the user's role in the challenge with id ${challengeId}`)
}

try {
challengeDetails = yield request.get(`${config.CHALLENGEAPI_V5_URL}/${challengeId}`)
.set('Authorization', `Bearer ${token}`)
Expand All @@ -666,32 +629,9 @@ function * checkReviewGetAccess (authUser, submission) {
return false
}

// Get map of role id to role name
const resourceRolesMap = yield getRoleIdToRoleNameMap()

// Check if role id to role name mapping is available. If not user's role cannot be determined.
if (resourceRolesMap == null || _.size(resourceRolesMap) === 0) {
throw new errors.HttpStatusError(503, `Could not determine the user's role in the challenge with id ${challengeId}`)
}

if (resources && challengeDetails) {
// Fetch all roles of the User pertaining to the current challenge
const currUserRoles = _.filter(resources.body, { memberHandle: authUser.handle })

// Populate the role names for the current user role ids
_.forEach(currUserRoles, currentUserRole => {
currentUserRole.role = resourceRolesMap[currentUserRole.roleId]
})

if (challengeDetails) {
const subTrack = challengeDetails.body.legacy.subTrack

// Check if the User is a Copilot, Manager or Observer for that contest
const validRoles = ['Copilot', 'Manager', 'Observer']
const passedRoles = currUserRoles.filter(a => validRoles.includes(a.role))
if (passedRoles.length !== 0) {
return true
}

// For Marathon Match, everyone can access review result
if (subTrack === 'DEVELOP_MARATHON_MATCH') {
logger.info('No access check for Marathon match')
Expand All @@ -706,10 +646,6 @@ function * checkReviewGetAccess (authUser, submission) {

return true
}
} else {
// We don't have enough details to validate the access
logger.debug('No enough details to validate the Permissions')
throw new errors.HttpStatusError(503, `Not all information could be fetched about challenge with id ${submission.challengeId}`)
}
}

Expand Down Expand Up @@ -754,7 +690,6 @@ function * postToBusApi (payload) {
function cleanseReviews (reviews, authUser) {
// Not a machine user
if (!authUser.scopes) {
logger.info('Not a machine user. Filtering reviews...')
const admin = _.filter(authUser.roles, role => role.toLowerCase() === 'Administrator'.toLowerCase())
const copilot = _.filter(authUser.roles, role => role.toLowerCase() === 'Copilot'.toLowerCase())

Expand Down Expand Up @@ -880,21 +815,6 @@ function * getLatestChallenges (page) {
}
}

/**
* Get legacy scorecard id if the scorecard id is uuid form
* @param {String} scoreCardId Scorecard ID
* @returns {String} Legacy scorecard ID of the given challengeId
*/
function getLegacyScoreCardId (scoreCardId) {
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(scoreCardId)) {
logger.debug(`${scoreCardId} detected as uuid. Converting to legacy scorecard id`)

return config.get('V5TOLEGACYSCORECARDMAPPING')[scoreCardId]
}

return scoreCardId
}

module.exports = {
wrapExpress,
autoWrapExpress,
Expand All @@ -913,6 +833,5 @@ module.exports = {
getRoleIdToRoleNameMap,
getV5ChallengeId,
adjustSubmissionChallengeId,
getLatestChallenges,
getLegacyScoreCardId
getLatestChallenges
}
Loading