@@ -16,7 +16,20 @@ const prisma = require('../common/prisma').getClient()
1616
1717const 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+
1931let copilotResourceRoleIdsCache
32+ let restrictedRoleIdsCache
2033
2134async 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 */
4179async 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 ) )
0 commit comments