Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
James Cori committed Dec 21, 2020
2 parents 75e0d76 + a1e5cc6 commit f94c842
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 15 deletions.
4 changes: 4 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ app.use((err, req, res, next) => {
}
}

if (!_.isUndefined(err.metadata)) {
errorResponse.metadata = err.metadata
}

res.status(status).json(errorResponse)
})

Expand Down
2 changes: 1 addition & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module.exports = {
AUTH0_PROXY_SERVER_URL: process.env.AUTH0_PROXY_SERVER_URL,

TERMS_API_URL: process.env.TERMS_API_URL || 'https://api.topcoder-dev.com/v5/terms',
MEMBER_API_URL: process.env.MEMBER_API_URL || 'https://api.topcoder-dev.com/v3/members',
MEMBER_API_URL: process.env.MEMBER_API_URL || 'https://api.topcoder-dev.com/v5/members',
USER_API_URL: process.env.USER_API_URL || 'https://api.topcoder-dev.com/v3/users',
CHALLENGE_API_URL: process.env.CHALLENGE_API_URL || 'http://localhost:4000/v5/challenges',
CHALLENGE_PHASES_API_URL: process.env.CHALLENGE_PHASES_API_URL || 'https://api.topcoder-dev.com/v5/challenge-phases',
Expand Down
21 changes: 21 additions & 0 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,9 @@ definitions:
type: string
description: The unauthorized error message.
example: Unable to authenticate the user.
metadata:
type: object
description: freeform metadata object
NotFound:
type: object
description: The not found error entity.
Expand All @@ -585,6 +588,9 @@ definitions:
type: string
description: The not found error message.
example: A resource with the name could not be found.
metadata:
type: object
description: freeform metadata object
ServerError:
type: object
description: The server error entity.
Expand All @@ -596,6 +602,9 @@ definitions:
Something went wrong while processing your request. We’re sorry for
the trouble. We’ve been notified of the error and will correct it as
soon as possible. Please try your request again in a moment.
metadata:
type: object
description: freeform metadata object
ServiceUnavailable:
type: object
description: The server is unavailable
Expand All @@ -604,6 +613,9 @@ definitions:
type: string
description: The server error message.
example: Something went wrong with the server.
metadata:
type: object
description: freeform metadata object
BadRequest:
type: object
description: The bad request error entity.
Expand All @@ -612,6 +624,9 @@ definitions:
type: string
description: The bad request error message.
example: Invalid input.
metadata:
type: object
description: freeform metadata object
Forbidden:
type: object
description: The permission error entity.
Expand All @@ -620,6 +635,9 @@ definitions:
type: string
description: The forbidden error message.
example: You are not allowed to access the request.
metadata:
type: object
description: freeform metadata object
Conflict:
type: object
description: The conflict error entity.
Expand All @@ -630,3 +648,6 @@ definitions:
type: string
description: The conflict error message.
example: Creating a resource with a name already exists.
metadata:
type: object
description: freeform metadata object
4 changes: 3 additions & 1 deletion src/common/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ function createError (name, statusCode) {
* The error constructor
* @param {String} message the error message
* @param {String} [cause] the error cause
* @param {Object} metadata the metadata
* @constructor
*/
function ErrorCtor (message, cause) {
function ErrorCtor (message, cause, metadata) {
Error.call(this)
Error.captureStackTrace(this)
this.message = message || name
this.cause = cause
this.metadata = metadata
this.httpStatus = statusCode
}

Expand Down
33 changes: 28 additions & 5 deletions src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,13 @@ async function getMemberIdByHandle (handle) {
async function getMemberIdByHandleFromV3Members (handle) {
let memberId
try {
logger.warn(`getMemberIdByHandle ${handle} from v3`)
logger.warn(`getMemberIdByHandle ${handle} from v5`)
const res = await getRequest(`${config.MEMBER_API_URL}/${handle}`)
if (_.get(res, 'body.result.content.userId')) {
memberId = String(res.body.result.content.userId)
if (_.get(res, 'body.userId')) {
memberId = String(res.body.userId)
}
// handle return from v3 API, handle and memberHandle are the same under case-insensitive condition
handle = _.get(res, 'body.result.content.handle')
handle = _.get(res, 'body.handle')
} catch (error) {
// re-throw all error except 404 Not-Founded, BadRequestError should be thrown if 404 occurs
if (error.status !== 404) {
Expand Down Expand Up @@ -256,6 +256,23 @@ async function scan (modelName, scanParams) {
})
}

/**
* Get all data collection (avoid default page limit of DynamoDB) by scan parameters
* @param {Object} modelName The dynamoose model name
* @param {Object} scanParams The scan parameters object
* @returns {Array}
*/
async function scanAll (modelName, scanParams) {
let results = await models[modelName].scan(scanParams).exec()
let lastKey = results.lastKey
while (!_.isUndefined(results.lastKey)) {
const newResult = await models[modelName].scan(scanParams).startAt(lastKey).exec()
results = [...results, ...newResult]
lastKey = newResult.lastKey
}
return results
}

/**
* Get data collection by query parameters
* @param {Object} modelName The dynamoose model name
Expand Down Expand Up @@ -430,15 +447,20 @@ function partialMatch (filter, value) {
*/
async function checkAgreedTerms (userId, terms) {
const unAgreedTerms = []
const missingTerms = []
for (const term of terms) {
const res = await getRequest(`${config.TERMS_API_URL}/${term.id}`, { userId })
if (!_.get(res, 'body.agreed', false)) {
unAgreedTerms.push(_.get(res, 'body.title', term))
missingTerms.push({
termId: term.id,
roleId: term.roleId
})
}
}

if (unAgreedTerms.length > 0) {
throw new errors.ForbiddenError(`The user has not yet agreed to the following terms: [${unAgreedTerms.join(', ')}]`)
throw new errors.ForbiddenError(`The user has not yet agreed to the following terms: [${unAgreedTerms.join(', ')}]`, null, { missingTerms })
}
}

Expand All @@ -455,6 +477,7 @@ module.exports = {
update,
query,
scan,
scanAll,
validateDuplicate,
getRequest,
postEvent,
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/ResourceRoleController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

const service = require('../services/ResourceRoleService')
const helper = require('../common/helper')

/**
* Get resource roles.
Expand All @@ -11,7 +12,8 @@ const service = require('../services/ResourceRoleService')
*/
async function getResourceRoles (req, res) {
const result = await service.getResourceRoles(req.query)
res.send(result)
helper.setResHeaders(req, res, result)
res.send(result.data)
}

/**
Expand Down
4 changes: 3 additions & 1 deletion src/controllers/ResourceRolePhaseDependencyController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

const service = require('../services/ResourceRolePhaseDependencyService')
const helper = require('../common/helper')

/**
* Get dependencies.
Expand All @@ -11,7 +12,8 @@ const service = require('../services/ResourceRolePhaseDependencyService')
*/
async function getDependencies (req, res) {
const result = await service.getDependencies(req.query)
res.send(result)
helper.setResHeaders(req, res, result)
res.send(result.data)
}

/**
Expand Down
11 changes: 8 additions & 3 deletions src/services/ResourceRolePhaseDependencyService.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ async function getDependencies (criteria) {
options.resourceRoleId = { eq: criteria.resourceRoleId }
}
if (!_.isNil(criteria.phaseState)) {
options.phaseState = { eq: criteria.phaseState }
options.phaseState = { eq: criteria.phaseState === 'true' }
}
const list = await helper.scanAll('ResourceRolePhaseDependency', options)
return {
data: list,
total: list.length,
page: 1,
perPage: Math.max(10, list.length)
}
const list = await helper.scan('ResourceRolePhaseDependency', options)
return list
}

getDependencies.schema = {
Expand Down
10 changes: 8 additions & 2 deletions src/services/ResourceRoleService.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const payloadFields = ['id', 'name', 'legacyId', 'fullReadAccess', 'fullWriteAcc
* @returns {Array} the search result
*/
async function getResourceRoles (criteria) {
let records = await helper.scan('ResourceRole')
let records = await helper.scanAll('ResourceRole')
if (criteria.name) records = _.filter(records, e => (criteria.name === e.name))
if (criteria.id) records = _.filter(records, e => (criteria.id === e.id))
if (criteria.legacyId) records = _.filter(records, e => (_.toNumber(criteria.legacyId) === _.toNumber(e.legacyId)))
Expand All @@ -26,7 +26,13 @@ async function getResourceRoles (criteria) {
if (!_.isUndefined(criteria.fullReadAccess)) records = _.filter(records, e => (e.fullReadAccess === (criteria.fullReadAccess === 'true')))
if (!_.isUndefined(criteria.fullWriteAccess)) records = _.filter(records, e => (e.fullWriteAccess === (criteria.fullWriteAccess === 'true')))

return _.map(records, e => _.pick(e, payloadFields))
const result = _.map(records, e => _.pick(e, payloadFields))
return {
data: result,
total: result.length,
page: 1,
perPage: Math.max(10, result.length)
}
}

getResourceRoles.schema = {
Expand Down
2 changes: 1 addition & 1 deletion src/services/ResourceService.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ async function deleteResource (currentUser, resource) {
undefined)

if (!ret) {
throw new errors.BadRequestError(`User ${handle || resource.memberHandle} doesn't have resource with roleId: ${resource.roleId} in challenge ${challengeId}`)
throw new errors.NotFoundError(`User ${handle || resource.memberHandle} doesn't have resource with roleId: ${resource.roleId} in challenge ${challengeId}`)
}

await ret.delete()
Expand Down

0 comments on commit f94c842

Please sign in to comment.