Skip to content

Commit f1440b6

Browse files
authored
Merge pull request #7 from topcoder-platform/develop
Migration final deploy
2 parents f787af8 + ea06535 commit f1440b6

File tree

2 files changed

+106
-2
lines changed

2 files changed

+106
-2
lines changed

src/services/ResourceService.js

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,20 @@ const prisma = require('../common/prisma').getClient()
1616

1717
const payloadFields = ['id', 'challengeId', 'memberId', 'memberHandle', 'roleId', 'phaseChangeNotifications', 'created', 'createdBy', 'updated', 'updatedBy']
1818

19+
// Restricted roles that cannot be combined with submitter role
20+
const RESTRICTED_ROLE_NAMES = [
21+
'manager',
22+
'copilot',
23+
'reviewer',
24+
'iterative reviewer',
25+
'screener',
26+
'checkpoint screener',
27+
'checkpoint reviewer',
28+
'approver'
29+
]
30+
1931
let copilotResourceRoleIdsCache
32+
let restrictedRoleIdsCache
2033

2134
async function getCopilotResourceRoleIds () {
2235
if (copilotResourceRoleIdsCache) {
@@ -34,11 +47,42 @@ async function getCopilotResourceRoleIds () {
3447
return copilotResourceRoleIdsCache
3548
}
3649

50+
/**
51+
* Get resource role IDs that are restricted from being combined with submitter role.
52+
* These include: Manager, Copilot, Reviewer, Iterative Reviewer, Screener,
53+
* Checkpoint Screener, Checkpoint Reviewer, and Approver.
54+
* @returns {Promise<Array<String>>} Array of restricted role IDs
55+
*/
56+
async function getRestrictedRoleIds () {
57+
if (restrictedRoleIdsCache) {
58+
return restrictedRoleIdsCache
59+
}
60+
const roles = await prisma.resourceRole.findMany({
61+
where: {
62+
nameLower: {
63+
in: RESTRICTED_ROLE_NAMES
64+
}
65+
},
66+
select: {
67+
id: true,
68+
nameLower: true
69+
}
70+
})
71+
restrictedRoleIdsCache = roles.map(role => role.id)
72+
return restrictedRoleIdsCache
73+
}
74+
3775
/**
3876
* Check whether the user can access resources
3977
* @param {Array} resources resources of current user for specified challenge id
4078
*/
4179
async function checkAccess (currentUserResources) {
80+
const copilotRoleIds = await getCopilotResourceRoleIds()
81+
const hasCopilotRole = _.some(currentUserResources, r => copilotRoleIds.includes(r.roleId))
82+
if (hasCopilotRole) {
83+
return
84+
}
85+
4286
const list = await prisma.resourceRole.findMany({})
4387
const fullAccessRoles = []
4488
_.each(list, e => {
@@ -291,6 +335,12 @@ async function init (currentUser, challengeId, resource, isCreated) {
291335
const { memberId, email } = memberInfoFromDb
292336
handle = memberInfoFromDb.handle
293337
const userResources = allResources.filter((r) => _.toLower(r.memberHandle) === _.toLower(handle))
338+
339+
let restrictedRoleIds
340+
if (isCreated) {
341+
restrictedRoleIds = await getRestrictedRoleIds()
342+
}
343+
294344
// Retrieve the constraint - Allowed Registrants
295345
if (isCreated && resource.roleId === config.SUBMITTER_RESOURCE_ROLE_ID) {
296346
const allowedRegistrants = _.get(challenge, 'constraints.allowedRegistrants')
@@ -307,12 +357,20 @@ async function init (currentUser, challengeId, resource, isCreated) {
307357
`User ${handle} is not allowed to register.`
308358
)
309359
}
310-
if (!_.get(challenge, 'task.isTask', false) && (_.toLower(challenge.createdBy) === _.toLower(handle) ||
311-
_.some(userResources, r => r.roleId === config.REVIEWER_RESOURCE_ROLE_ID || r.roleId === config.ITERATIVE_REVIEWER_RESOURCE_ROLE_ID))) {
360+
// Prevent challenge creator from registering as submitter (for non-tasks)
361+
if (!_.get(challenge, 'task.isTask', false) && _.toLower(challenge.createdBy) === _.toLower(memberId)) {
312362
throw new errors.BadRequestError(
313363
`User ${handle} is not allowed to register.`
314364
)
315365
}
366+
// Check if user already has a restricted role (Manager, Copilot, Reviewer, etc.)
367+
const existingRestrictedRole = _.find(userResources, r => restrictedRoleIds.includes(r.roleId))
368+
if (existingRestrictedRole) {
369+
const roleNamesList = RESTRICTED_ROLE_NAMES.slice(0, -1).join(', ') + ', or ' + RESTRICTED_ROLE_NAMES.slice(-1)
370+
throw new errors.BadRequestError(
371+
`User ${handle} is already assigned a restricted role (${roleNamesList}) and cannot be registered as a submitter.`
372+
)
373+
}
316374
}
317375

318376
// Prevent from creating more than 1 submitter resources on tasks
@@ -344,6 +402,18 @@ async function init (currentUser, challengeId, resource, isCreated) {
344402
// ensure resource role existed
345403
const resourceRole = await getResourceRole(resource.roleId, isCreated)
346404

405+
// Check if user is trying to assign a restricted role and already has submitter role
406+
if (isCreated) {
407+
if (restrictedRoleIds.includes(resource.roleId)) {
408+
const existingSubmitterRole = _.find(userResources, r => r.roleId === config.SUBMITTER_RESOURCE_ROLE_ID)
409+
if (existingSubmitterRole) {
410+
throw new errors.BadRequestError(
411+
`User ${handle} is already registered as a submitter and cannot be assigned a ${resourceRole.name} role.`
412+
)
413+
}
414+
}
415+
}
416+
347417
// Verify the member has agreed to the challenge terms
348418
if (isCreated) {
349419
await helper.checkAgreedTerms(memberId, _.filter(_.get(challenge, 'terms', []), t => t.roleId === resourceRole.id))

test/unit/createResource.test.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const { v4: uuid } = require('uuid')
99
const service = require('../../src/services/ResourceService')
1010
const ResourceRolePhaseDependencyService = require('../../src/services/ResourceRolePhaseDependencyService')
1111
const prisma = require('../../src/common/prisma').getClient()
12+
const helper = require('../../src/common/helper')
1213
const ResourceRoleService = require('../../src/services/ResourceRoleService')
1314
const { requestBody, user } = require('../common/testData')
1415
const { assertValidationError, assertError, assertResource, getRoleIds, clearDependencies } = require('../common/testHelper')
@@ -264,6 +265,39 @@ module.exports = describe('Create resource', () => {
264265
await assertResource(ret.id, ret)
265266
})
266267

268+
it('copilot can manage resources without full access flags', async () => {
269+
const originalRole = await helper.getById('ResourceRole', copilotRoleId)
270+
await ResourceRoleService.updateResourceRole(user.admin, copilotRoleId, {
271+
name: originalRole.name,
272+
fullReadAccess: false,
273+
fullWriteAccess: false,
274+
isActive: originalRole.isActive,
275+
selfObtainable: originalRole.selfObtainable
276+
})
277+
278+
const entity = resources.createBody('diazz', reviewerRoleId, challengeId2)
279+
let createdResource
280+
try {
281+
createdResource = await service.createResource(user.phead, entity)
282+
should.equal(createdResource.roleId, entity.roleId)
283+
should.equal(createdResource.memberHandle.toLowerCase(), entity.memberHandle.toLowerCase())
284+
await assertResource(createdResource.id, createdResource)
285+
} finally {
286+
if (createdResource && createdResource.id) {
287+
await prisma.resource.deleteMany({
288+
where: { id: createdResource.id }
289+
})
290+
}
291+
await ResourceRoleService.updateResourceRole(user.admin, copilotRoleId, {
292+
name: originalRole.name,
293+
fullReadAccess: originalRole.fullReadAccess,
294+
fullWriteAccess: originalRole.fullWriteAccess,
295+
isActive: originalRole.isActive,
296+
selfObtainable: originalRole.selfObtainable
297+
})
298+
}
299+
})
300+
267301
it('create resource for user ghostar 1', async () => {
268302
const entity = resources.createBody('ghostar', reviewerRoleId, challengeId2)
269303
const ret = await service.createResource(user.m2m, entity)

0 commit comments

Comments
 (0)