@@ -17,6 +17,7 @@ const prisma = require('../common/prisma').getClient()
1717const payloadFields = [ 'id' , 'challengeId' , 'memberId' , 'memberHandle' , 'roleId' , 'phaseChangeNotifications' , 'created' , 'createdBy' , 'updated' , 'updatedBy' ]
1818
1919let copilotResourceRoleIdsCache
20+ let restrictedRoleIdsCache
2021
2122async function getCopilotResourceRoleIds ( ) {
2223 if ( copilotResourceRoleIdsCache ) {
@@ -34,6 +35,41 @@ async function getCopilotResourceRoleIds () {
3435 return copilotResourceRoleIdsCache
3536}
3637
38+ /**
39+ * Get resource role IDs that are restricted from being combined with submitter role.
40+ * These include: Manager, Copilot, Reviewer, Iterative Reviewer, Screener,
41+ * Checkpoint Screener, Checkpoint Reviewer, and Approver.
42+ * @returns {Promise<Array<String>> } Array of restricted role IDs
43+ */
44+ async function getRestrictedRoleIds ( ) {
45+ if ( restrictedRoleIdsCache ) {
46+ return restrictedRoleIdsCache
47+ }
48+ const restrictedRoleNames = [
49+ 'manager' ,
50+ 'copilot' ,
51+ 'reviewer' ,
52+ 'iterative reviewer' ,
53+ 'screener' ,
54+ 'checkpoint screener' ,
55+ 'checkpoint reviewer' ,
56+ 'approver'
57+ ]
58+ const roles = await prisma . resourceRole . findMany ( {
59+ where : {
60+ nameLower : {
61+ in : restrictedRoleNames
62+ }
63+ } ,
64+ select : {
65+ id : true ,
66+ nameLower : true
67+ }
68+ } )
69+ restrictedRoleIdsCache = roles . map ( role => role . id )
70+ return restrictedRoleIdsCache
71+ }
72+
3773/**
3874 * Check whether the user can access resources
3975 * @param {Array } resources resources of current user for specified challenge id
@@ -307,12 +343,22 @@ async function init (currentUser, challengeId, resource, isCreated) {
307343 `User ${ handle } is not allowed to register.`
308344 )
309345 }
310- if ( ! _ . get ( challenge , 'task.isTask' , false ) && ( _ . toLower ( challenge . createdBy ) === _ . toLower ( memberId ) ||
311- _ . some ( userResources , r => r . roleId === config . REVIEWER_RESOURCE_ROLE_ID || r . roleId === config . ITERATIVE_REVIEWER_RESOURCE_ROLE_ID ) ) ) {
346+ // Prevent challenge creator from registering as submitter (for non-tasks)
347+ if ( ! _ . get ( challenge , 'task.isTask' , false ) && _ . toLower ( challenge . createdBy ) === _ . toLower ( memberId ) ) {
312348 throw new errors . BadRequestError (
313349 `User ${ handle } is not allowed to register.`
314350 )
315351 }
352+ // Check if user already has a restricted role (Manager, Copilot, Reviewer, etc.)
353+ const restrictedRoleIds = await getRestrictedRoleIds ( )
354+ const existingRestrictedRole = _ . find ( userResources , r => restrictedRoleIds . includes ( r . roleId ) )
355+ if ( existingRestrictedRole ) {
356+ // Get the role name for better error message
357+ const existingRole = await getResourceRole ( existingRestrictedRole . roleId , false )
358+ throw new errors . BadRequestError (
359+ `User ${ handle } is already assigned a ${ existingRole . name } role and cannot be registered as a submitter.`
360+ )
361+ }
316362 }
317363
318364 // Prevent from creating more than 1 submitter resources on tasks
@@ -344,6 +390,19 @@ async function init (currentUser, challengeId, resource, isCreated) {
344390 // ensure resource role existed
345391 const resourceRole = await getResourceRole ( resource . roleId , isCreated )
346392
393+ // Check if user is trying to assign a restricted role and already has submitter role
394+ if ( isCreated ) {
395+ const restrictedRoleIds = await getRestrictedRoleIds ( )
396+ if ( restrictedRoleIds . includes ( resource . roleId ) ) {
397+ const existingSubmitterRole = _ . find ( userResources , r => r . roleId === config . SUBMITTER_RESOURCE_ROLE_ID )
398+ if ( existingSubmitterRole ) {
399+ throw new errors . BadRequestError (
400+ `User ${ handle } is already registered as a submitter and cannot be assigned a ${ resourceRole . name } role.`
401+ )
402+ }
403+ }
404+ }
405+
347406 // Verify the member has agreed to the challenge terms
348407 if ( isCreated ) {
349408 await helper . checkAgreedTerms ( memberId , _ . filter ( _ . get ( challenge , 'terms' , [ ] ) , t => t . roleId === resourceRole . id ) )
0 commit comments