Skip to content

Commit 66f9a96

Browse files
zhijiezhijie
authored andcommitted
add support for memberId for resource API
1 parent 6ed0e24 commit 66f9a96

File tree

8 files changed

+143
-35
lines changed

8 files changed

+143
-35
lines changed

.DS_Store

0 Bytes
Binary file not shown.

docs/swagger.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,7 @@ definitions:
557557
required:
558558
- challengeId
559559
- memberHandle
560+
- memberId
560561
- roleId
561562
properties:
562563
challengeId:
@@ -566,6 +567,9 @@ definitions:
566567
memberHandle:
567568
type: string
568569
description: The member handle
570+
memberId:
571+
type: string
572+
description: The member id
569573
roleId:
570574
type: string
571575
format: UUID

mock/mock-challenge-api.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ const mockChallengeApi = http.createServer((req, res) => {
5555
id: 'ae6d0a58-ce7d-4521-8501-b8132b1c0393',
5656
roleId: config.SUBMITTER_RESOURCE_ROLE_ID
5757
}],
58-
groups: (challengeId === 'fe6d0a58-ce7d-4521-8501-b8132b1c0394') ?
59-
['11111111-2222-3333-9999-555555555555', '11111111-2222-3333-9999-555555555557'] :
60-
(challengeId === 'fe6d0a58-ce7d-4521-8501-b8132b1c0391' ? ['11111111-2222-3333-9999-555555555555'] : []),
58+
groups: (challengeId === 'fe6d0a58-ce7d-4521-8501-b8132b1c0394')
59+
? ['11111111-2222-3333-9999-555555555555', '11111111-2222-3333-9999-555555555557']
60+
: (challengeId === 'fe6d0a58-ce7d-4521-8501-b8132b1c0391' ? ['11111111-2222-3333-9999-555555555555'] : []),
6161
phases: [{
6262
phaseId: 'aa5a3f78-79e0-4bf7-93ff-b11e8f5b398b',
6363
isOpen: true
@@ -110,9 +110,9 @@ const mockChallengeApi = http.createServer((req, res) => {
110110
if (handle === '123abcx') {
111111
return send(res, 404, {})
112112
} else if (Object.keys(userIds).includes(handle.toLowerCase())) {
113-
return send(res, 200, { userId: userIds[handle.toLowerCase()], email: '' })
113+
return send(res, 200, { userId: userIds[handle.toLowerCase()], email: '', handle })
114114
}
115-
return send(res, 200, { userId: 123456, email: 'test@topcoder.com' })
115+
return send(res, 200, { userId: 123456, email: 'test@topcoder.com', handle })
116116
} else if (req.method === 'GET' && req.url.match(/^\/v5\/groups\/memberGroups.+$/)) {
117117
const groups = [
118118
'11111111-2222-3333-9999-555555555555',

src/common/helper.js

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,16 @@ function getUserHandleOrSub (authUser) {
9898
return authUser.handle || authUser.sub
9999
}
100100

101+
/**
102+
* Get user id from token
103+
*
104+
* @param {Object} authUser request auth user
105+
* @returns user id
106+
*/
107+
function getUserIdFromToken (authUser) {
108+
return authUser.userId
109+
}
110+
101111
/**
102112
* Check if exists.
103113
*
@@ -170,20 +180,52 @@ async function getMemberDetailsByHandle (handle) {
170180
},
171181
select: {
172182
userId: true,
183+
handle: true,
173184
email: true
174185
}
175186
})
176187
if (!profile || !profile.userId) {
177-
throw new Error('Member profile not found')
188+
throw new Error(`Member profile not found for handle: ${handle}`)
178189
}
179-
return { memberId: profile.userId, email: profile.email }
190+
return { memberId: profile.userId, email: profile.email, handle }
180191
} catch (e) {
181192
// fall back to v3 api...
182193
logger.warn(`Get Member by Handle from DB Failed, trying v3 Members API. Error: ${JSON.stringify(e)}`)
183194
return getMemberDetailsByHandleFromV3Members(handle)
184195
}
185196
}
186197

198+
/**
199+
* Get Data by model id
200+
* @param {String} memberId The member id
201+
* @returns {Promise<void>}
202+
*/
203+
async function getMemberDetailsById (memberId) {
204+
if (!memberId) {
205+
return null
206+
}
207+
try {
208+
const profile = await prisma.memberProfile.findUnique({
209+
where: {
210+
userId: memberId
211+
},
212+
select: {
213+
userId: true,
214+
handle: true,
215+
email: true
216+
}
217+
})
218+
if (!profile || !profile.userId) {
219+
throw new Error(`Member profile not found for memberId: ${memberId}`)
220+
}
221+
return { memberId: profile.userId, email: profile.email }
222+
} catch (e) {
223+
// fall back to v3 api...
224+
logger.warn(`Get Member by Handle from DB Failed, trying v3 Members API. Error: ${JSON.stringify(e)}`)
225+
return getMemberDetailsByIdFromMemberApi(memberId)
226+
}
227+
}
228+
187229
async function getMemberDetailsByHandleFromV3Members (handle) {
188230
let memberId
189231
let email
@@ -209,7 +251,42 @@ async function getMemberDetailsByHandleFromV3Members (handle) {
209251
throw new errors.BadRequestError(`User with handle: ${handle} doesn't exist`)
210252
}
211253

212-
return { memberId, email }
254+
return { memberId, email, handle }
255+
}
256+
257+
/**
258+
* Get member detail by id from member api
259+
* @param {String} userId user id
260+
* @returns member detail
261+
*/
262+
async function getMemberDetailsByIdFromMemberApi (userId) {
263+
let memberId
264+
let email
265+
let handle
266+
try {
267+
logger.warn(`getMemberByHandle ${handle} from v5`)
268+
const res = await getRequest(`${config.MEMBER_API_URL}?userId=${userId}`)
269+
if (_.get(res, 'body[0].userId')) {
270+
memberId = String(res.body[0].userId)
271+
}
272+
if (_.get(res, 'body[0].email')) {
273+
email = String(res.body[0].email)
274+
}
275+
if (_.get(res, 'body[0].handle')) {
276+
handle = _.get(res, 'body[0].handle')
277+
}
278+
} catch (error) {
279+
// re-throw all error except 404 Not-Founded, BadRequestError should be thrown if 404 occurs
280+
if (error.status !== 404) {
281+
throw error
282+
}
283+
}
284+
285+
if (_.isUndefined(memberId)) {
286+
throw new errors.BadRequestError(`User with id: ${userId} doesn't exist`)
287+
}
288+
289+
return { memberId, email, handle }
213290
}
214291

215292
/**
@@ -222,7 +299,7 @@ async function update (authUser, modelName, dbItem, data) {
222299
Object.keys(data).forEach((key) => {
223300
dbItem[key] = data[key]
224301
})
225-
dbItem.updatedBy = getUserHandleOrSub(authUser)
302+
dbItem.updatedBy = getUserIdFromToken(authUser)
226303
dbItem.updatedAt = moment().utc().format()
227304
const prismaModel = _.camelCase(modelName)
228305
const ret = await prisma[prismaModel].update({
@@ -454,9 +531,11 @@ module.exports = {
454531
autoWrapExpress,
455532
getMemberInfoByIdList,
456533
getMemberDetailsByHandle,
534+
getMemberDetailsById,
457535
checkIfExists,
458536
hasAdminRole,
459537
getUserHandleOrSub,
538+
getUserIdFromToken,
460539
getById,
461540
update,
462541
validateDuplicate,

src/services/ResourceRolePhaseDependencyService.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ async function createDependency (authUser, data) {
8484
let entity = await prisma.resourceRolePhaseDependency.create({
8585
data: _.assign({
8686
id: uuid(),
87-
createdBy: helper.getUserHandleOrSub(authUser),
87+
createdBy: helper.getUserIdFromToken(authUser),
8888
createdAt: moment().utc().format()
8989
}, data)
9090
})

src/services/ResourceRoleService.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ async function createResourceRole (authUser, resourceRole) {
7979
data: _.assign({ id: uuid(),
8080
nameLower,
8181
createdAt: moment().utc().format(),
82-
createdBy: helper.getUserHandleOrSub(authUser) }, resourceRole)
82+
createdBy: helper.getUserIdFromToken(authUser) }, resourceRole)
8383
})
8484
const ret = _.pick(entity, payloadFields)
8585
await helper.postEvent(config.RESOURCE_ROLE_CREATE_TOPIC, ret)

src/services/ResourceService.js

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,15 @@ async function init (currentUser, challengeId, resource, isCreated) {
242242

243243
const registrationPhase = challenge.phases.find((phase) => phase.name === 'Registration')
244244
const currentSubmitters = _.filter(allResources, (r) => r.roleId === config.SUBMITTER_RESOURCE_ROLE_ID)
245-
const handle = resource.memberHandle
245+
let handle = resource.memberHandle
246+
const resourceMemberId = resource.memberId
247+
248+
let memberInfoFromDb = await helper.getMemberDetailsById(resourceMemberId)
249+
if (!memberInfoFromDb) {
250+
memberInfoFromDb = await helper.getMemberDetailsByHandle(handle)
251+
}
252+
const { memberId, email } = memberInfoFromDb
253+
handle = memberInfoFromDb.handle
246254
const userResources = allResources.filter((r) => _.toLower(r.memberHandle) === _.toLower(handle))
247255
// Retrieve the constraint - Allowed Registrants
248256
if (isCreated && resource.roleId === config.SUBMITTER_RESOURCE_ROLE_ID) {
@@ -257,13 +265,13 @@ async function init (currentUser, challengeId, resource, isCreated) {
257265
)
258266
) {
259267
throw new errors.ConflictError(
260-
`User ${resource.memberHandle} is not allowed to register.`
268+
`User ${handle} is not allowed to register.`
261269
)
262270
}
263271
if (!_.get(challenge, 'task.isTask', false) && (_.toLower(challenge.createdBy) === _.toLower(handle) ||
264272
_.some(userResources, r => r.roleId === config.REVIEWER_RESOURCE_ROLE_ID || r.roleId === config.ITERATIVE_REVIEWER_RESOURCE_ROLE_ID))) {
265273
throw new errors.BadRequestError(
266-
`User ${resource.memberHandle} is not allowed to register.`
274+
`User ${handle} is not allowed to register.`
267275
)
268276
}
269277
}
@@ -278,14 +286,12 @@ async function init (currentUser, challengeId, resource, isCreated) {
278286
const currentUserResources = allResources.filter((r) => _.toString(r.memberId) === _.toString(currentUser.userId))
279287
const isResourceExist = !_.isUndefined(_.find(userResources, r => r.roleId === resource.roleId))
280288
if (isCreated && isResourceExist) {
281-
throw new errors.ConflictError(`User ${resource.memberHandle} already has resource with roleId: ${resource.roleId} in challenge: ${challengeId}`)
289+
throw new errors.ConflictError(`User ${handle} already has resource with roleId: ${resource.roleId} in challenge: ${challengeId}`)
282290
}
283291

284292
if (!isCreated && !isResourceExist) {
285293
throw new errors.NotFoundError(`User ${handle} doesn't have resource with roleId: ${resource.roleId} in challenge ${challengeId}`)
286294
}
287-
288-
const { memberId, email } = await helper.getMemberDetailsByHandle(handle)
289295
// check if the resource is reviewer role and has already made a submission in the challenge
290296
if (isCreated && (resource.roleId === config.REVIEWER_RESOURCE_ROLE_ID || resource.roleId === config.ITERATIVE_REVIEWER_RESOURCE_ROLE_ID)) {
291297
const submissionsRes = await helper.getRequest(`${config.SUBMISSIONS_API_URL}`, { challengeId: challengeId, perPage: 100, memberId: memberId })
@@ -376,8 +382,9 @@ async function createResource (currentUser, resource) {
376382
const prismaData = _.assign({
377383
id: uuid(),
378384
memberId: _.toString(memberId),
379-
createdBy: helper.getUserHandleOrSub(currentUser),
380-
createdAt: moment().utc().format()
385+
createdBy: _.toString(memberId),
386+
createdAt: moment().utc().format(),
387+
memberHandle: handle
381388
}, resource)
382389
const createdResource = await prisma.resource.create({
383390
data: prismaData
@@ -436,11 +443,20 @@ async function createResource (currentUser, resource) {
436443

437444
createResource.schema = {
438445
currentUser: Joi.any(),
439-
resource: Joi.object().keys({
440-
challengeId: Joi.id(),
441-
memberHandle: Joi.string().required(),
442-
roleId: Joi.id()
443-
}).required()
446+
resource: Joi.alternatives().try(
447+
Joi.object().keys({
448+
challengeId: Joi.id(),
449+
memberId: Joi.string(),
450+
memberHandle: Joi.string().required(),
451+
roleId: Joi.id()
452+
}),
453+
Joi.object().keys({
454+
challengeId: Joi.id(),
455+
memberId: Joi.string().required(),
456+
memberHandle: Joi.string(),
457+
roleId: Joi.id()
458+
})
459+
)
444460
}
445461

446462
/**
@@ -483,11 +499,20 @@ async function deleteResource (currentUser, resource) {
483499

484500
deleteResource.schema = {
485501
currentUser: Joi.any(),
486-
resource: Joi.object().keys({
487-
challengeId: Joi.id(),
488-
memberHandle: Joi.string().required(),
489-
roleId: Joi.id()
490-
}).required()
502+
resource: Joi.alternatives().try(
503+
Joi.object().keys({
504+
challengeId: Joi.id(),
505+
memberId: Joi.string(),
506+
memberHandle: Joi.string().required(),
507+
roleId: Joi.id()
508+
}),
509+
Joi.object().keys({
510+
challengeId: Joi.id(),
511+
memberId: Joi.string().required(),
512+
memberHandle: Joi.string(),
513+
roleId: Joi.id()
514+
})
515+
)
491516
}
492517

493518
/**

test/unit/deleteResource.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ module.exports = describe('Delete resource', () => {
5353
await service.deleteResource(user.m2m, entity)
5454
throw new Error('should not throw error here')
5555
} catch (err) {
56-
should.equal(err.name, 'NotFoundError')
57-
assertError(err, `User 123abcx doesn't have resource with roleId: ${observerRoleId} in challenge ${challengeId}`)
56+
should.equal(err.name, 'BadRequestError')
57+
assertError(err, `User with handle: 123abcx doesn't exist`)
5858
}
5959
})
6060

@@ -145,7 +145,7 @@ module.exports = describe('Delete resource', () => {
145145
should.equal(ret.memberHandle.toLowerCase(), 'ghostar')
146146
should.equal(ret.roleId, submitterRoleId)
147147
should.exist(ret.created)
148-
should.equal(ret.createdBy, user.m2m.sub)
148+
should.equal(ret.createdBy, '151743')
149149
})
150150

151151
it('delete resource by user', async () => {
@@ -163,7 +163,7 @@ module.exports = describe('Delete resource', () => {
163163
should.equal(ret.memberHandle.toLowerCase(), 'denis')
164164
should.equal(ret.roleId, submitterRoleId)
165165
should.exist(ret.created)
166-
should.equal(ret.createdBy.toLowerCase(), 'denis')
166+
should.equal(ret.createdBy.toLowerCase(), '251280')
167167
})
168168

169169
it('delete resource by admin', async () => {
@@ -181,7 +181,7 @@ module.exports = describe('Delete resource', () => {
181181
should.equal(ret.memberHandle.toLowerCase(), 'hohosky')
182182
should.equal(ret.roleId, copilotRoleId)
183183
should.exist(ret.created)
184-
should.equal(ret.createdBy.toLowerCase(), 'tonyj')
184+
should.equal(ret.createdBy.toLowerCase(), '16096823')
185185
})
186186

187187
it(`delete self obtainable resource by user itself`, async () => {
@@ -199,6 +199,6 @@ module.exports = describe('Delete resource', () => {
199199
should.equal(ret.memberHandle.toLowerCase(), 'lars2520')
200200
should.equal(ret.roleId, submitterRoleId)
201201
should.exist(ret.created)
202-
should.equal(ret.createdBy.toLowerCase(), 'lars2520')
202+
should.equal(ret.createdBy.toLowerCase(), '287131')
203203
})
204204
})

0 commit comments

Comments
 (0)