From 75983c3ba8777d065fc23548fbf1701ef2ca795d Mon Sep 17 00:00:00 2001 From: Vasilica Olariu Date: Mon, 18 May 2026 10:45:04 +0300 Subject: [PATCH] PM-5065 - allow projectIds[] param for fetching challenges --- docs/swagger.yaml | 9 +++++++++ src/services/ChallengeService.js | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index c3706ee..c2d9dcb 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -189,6 +189,15 @@ paths: required: false type: integer minimum: 1 + - name: projectIds + in: query + description: Filter by multiple v5 project ids (array). Use repeated query params, e.g. projectIds[]=1&projectIds[]=2. + required: false + type: array + items: + type: integer + minimum: 1 + collectionFormat: brackets - name: forumId in: query description: Filter by forum id, exact match. diff --git a/src/services/ChallengeService.js b/src/services/ChallengeService.js index f3b14db..9156c15 100644 --- a/src/services/ChallengeService.js +++ b/src/services/ChallengeService.js @@ -1403,6 +1403,13 @@ async function searchChallenges(currentUser, criteria) { } }); + // handle projectIds (array of project IDs, applied as IN filter) + if (Array.isArray(criteria.projectIds) && criteria.projectIds.length > 0) { + prismaFilter.where.AND.push({ + projectId: { in: criteria.projectIds }, + }); + } + // handle status if (!_.isNil(criteria.status)) { prismaFilter.where.AND.push({ @@ -1709,6 +1716,18 @@ async function searchChallenges(currentUser, criteria) { currentUser, ); } + // When filtering by multiple project IDs, treat as having project manager access + // (the caller is expected to pass only project IDs the user has access to) + if ( + !hasProjectManagerAccessForSearch && + currentUser && + !_hasAdminRole && + !_isMachineToken && + Array.isArray(criteria.projectIds) && + criteria.projectIds.length > 0 + ) { + hasProjectManagerAccessForSearch = true; + } let groupsToFilter = []; let accessibleGroups = []; @@ -2131,6 +2150,7 @@ searchChallenges.schema = { tags: Joi.array().items(Joi.string()), includeAllTags: Joi.boolean().default(true), projectId: Joi.number().integer().positive(), + projectIds: Joi.array().items(Joi.number().integer().positive()), forumId: Joi.number().integer(), legacyId: Joi.number().integer().positive(), status: Joi.string()