From a840bd9846030654138ff9e75e43726ff9338b31 Mon Sep 17 00:00:00 2001 From: Guilhem SEMPERE Date: Tue, 3 May 2022 15:46:17 +0200 Subject: [PATCH] Supporting germplasmDbIds param in /search/studies & /search/callsets ... addresses issues https://github.com/SouthGreenPlatform/Gigwa2/issues/46 and https://github.com/SouthGreenPlatform/Gigwa2/issues/47 --- .../brapi/v2/api/CallsetsApiController.java | 88 ++++++++++++++----- .../brapi/v2/api/GermplasmApiController.java | 57 ++++++------ .../brapi/v2/api/StudiesApiController.java | 38 +++++--- 3 files changed, 116 insertions(+), 67 deletions(-) diff --git a/src/main/java/org/brapi/v2/api/CallsetsApiController.java b/src/main/java/org/brapi/v2/api/CallsetsApiController.java index 7fd5a2e..74710c3 100644 --- a/src/main/java/org/brapi/v2/api/CallsetsApiController.java +++ b/src/main/java/org/brapi/v2/api/CallsetsApiController.java @@ -1,6 +1,8 @@ package org.brapi.v2.api; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -77,15 +79,19 @@ public ResponseEntity searchCallsetsPost( @ApiParam(value cslr.setMetadata(metadata); boolean fTriedToAccessForbiddenData = false; - HashMap sampleQueryByModule = new HashMap<>(); + HashMap> sampleCritByModule = new HashMap<>(); - if ((body.getCallSetDbIds() == null || body.getCallSetDbIds().isEmpty()) && (body.getVariantSetDbIds() == null || body.getVariantSetDbIds().isEmpty())) { - status.setMessage("Some callSetDbIds or variantSetDbIds must be specified as parameter!"); + boolean fFilterOnCallSets = body.getCallSetDbIds() != null && !body.getCallSetDbIds().isEmpty(); + boolean fFilterOnGermplasm = body.getGermplasmDbIds() != null && !body.getGermplasmDbIds().isEmpty(); + boolean fFilterOnVariantSets = body.getVariantSetDbIds() != null && !body.getVariantSetDbIds().isEmpty(); + + if (!fFilterOnCallSets && !fFilterOnVariantSets && !fFilterOnGermplasm) { + status.setMessage("Some callSetDbIds, germplasmDbIds or variantSetDbIds must be specified as parameter!"); metadata.addStatusItem(status); httpCode = HttpStatus.BAD_REQUEST; } else { - if (body.getVariantSetDbIds() == null || body.getVariantSetDbIds().isEmpty()) { // no variantSets specified, but we have a list of callSets + if (fFilterOnCallSets) { HashMap /*samples, null means all*/> samplesByModule = new HashMap<>(); for (String csId : body.getCallSetDbIds()) { String[] info = GigwaSearchVariantsRequest.getInfoFromId(csId, 3); @@ -96,15 +102,16 @@ public ResponseEntity searchCallsetsPost( @ApiParam(value } moduleSamples.add(Integer.parseInt(info[2])); } - for (String module : samplesByModule.keySet()) { // make sure we filter out any samples that are from projects the user is not allowed to see - MongoTemplate mongoTemplate = MongoTemplateManager.get(module); - HashSet moduleSamples = samplesByModule.get(module); - Query query = new Query(Criteria.where("_id").in(moduleSamples)); + + for (String db : samplesByModule.keySet()) { // make sure we filter out any samples that are from projects the user is not allowed to see + MongoTemplate mongoTemplate = MongoTemplateManager.get(db); + HashSet moduleSamples = samplesByModule.get(db); + Criteria crit = Criteria.where("_id").in(moduleSamples); HashMap projectAccessPermissions = new HashMap<>(); - for (GenotypingSample sample : mongoTemplate.find(query, GenotypingSample.class)) { + for (GenotypingSample sample : mongoTemplate.find(new Query(crit), GenotypingSample.class)) { Boolean fPjAllowed = projectAccessPermissions.get(sample.getProjectId()); if (fPjAllowed == null) { - fPjAllowed = tokenManager.canUserReadProject(token, module, sample.getProjectId()); + fPjAllowed = tokenManager.canUserReadProject(token, db, sample.getProjectId()); projectAccessPermissions.put(sample.getProjectId(), fPjAllowed); } if (!fPjAllowed) { @@ -113,25 +120,58 @@ public ResponseEntity searchCallsetsPost( @ApiParam(value } } - if (moduleSamples.size() > 0) - sampleQueryByModule.put(module, query); + if (moduleSamples.size() > 0) { + ArrayList moduleCrit = sampleCritByModule.get(db); + if (moduleCrit == null) { + moduleCrit = new ArrayList<>(); + sampleCritByModule.put(db, moduleCrit); + } + moduleCrit.add(crit); + } } - } - else + } + + if (fFilterOnGermplasm) { + HashMap>> dbProjectIndividuals = GermplasmApiController.readGermplasmIDs(body.getGermplasmDbIds()); + for (String db : dbProjectIndividuals.keySet()) { + HashMap> projectIndividuals = dbProjectIndividuals.get(db); + for (int nProjId : projectIndividuals.keySet()) { // make sure at least one germplasm exists in each project before returning it + if (tokenManager.canUserReadProject(token, db, nProjId)) { + ArrayList moduleCrit = sampleCritByModule.get(db); + if (moduleCrit == null) { + moduleCrit = new ArrayList<>(); + sampleCritByModule.put(db, moduleCrit); + } + moduleCrit.add(new Criteria().andOperator(Criteria.where(GenotypingSample.FIELDNAME_PROJECT_ID).is(nProjId), Criteria.where(GenotypingSample.FIELDNAME_INDIVIDUAL).in(projectIndividuals.get(nProjId)))); + } + } + } + } + + if (fFilterOnVariantSets) for (String variantSetDbId : body.getVariantSetDbIds()) { String[] info = GigwaSearchVariantsRequest.getInfoFromId(variantSetDbId, 3); - int projId = Integer.parseInt(info[1]); - if (tokenManager.canUserReadProject(token, info[0], projId)) - sampleQueryByModule.put(info[0], new Query(new Criteria().andOperator(Criteria.where(GenotypingSample.FIELDNAME_PROJECT_ID).is(projId), Criteria.where(GenotypingSample.FIELDNAME_RUN).is(info[2])))); - else - fTriedToAccessForbiddenData = true; + if (!sampleCritByModule.containsKey(info[0])) { // only look at variantSet IDs if we don't already have samples selected + int projId = Integer.parseInt(info[1]); + if (tokenManager.canUserReadProject(token, info[0], projId)) { + ArrayList moduleCrit = sampleCritByModule.get(info[0]); + if (moduleCrit == null) { + moduleCrit = new ArrayList<>(); + sampleCritByModule.put(info[0], moduleCrit); + } + moduleCrit.add(new Criteria().andOperator(Criteria.where(GenotypingSample.FIELDNAME_PROJECT_ID).is(projId), Criteria.where(GenotypingSample.FIELDNAME_RUN).is(info[2]))); + } + else + fTriedToAccessForbiddenData = true; + } } int nTotalCallSetsEncountered = 0; - for (String module : sampleQueryByModule.keySet()) { - MongoTemplate mongoTemplate = MongoTemplateManager.get(module); + for (String db : sampleCritByModule.keySet()) { + MongoTemplate mongoTemplate = MongoTemplateManager.get(db); Map indIdToSampleIdMap = new HashMap<>(); - List samples = mongoTemplate.find(sampleQueryByModule.get(module), GenotypingSample.class); + ArrayList critList = sampleCritByModule.get(db); + List samples = mongoTemplate.find(new Query(new Criteria().orOperator(critList.toArray(new Criteria[critList.size()]))), GenotypingSample.class); for (GenotypingSample sample : samples) indIdToSampleIdMap.put(sample.getIndividual(), sample.getId()); @@ -148,10 +188,10 @@ public ResponseEntity searchCallsetsPost( @ApiParam(value GenotypingSample sample = samples.get(i); nTotalCallSetsEncountered++; CallSet callset = new CallSet(); - callset.setCallSetDbId(module + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getIndividual() + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getId()); + callset.setCallSetDbId(db + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getIndividual() + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getId()); callset.setCallSetName(callset.getCallSetDbId()); callset.setSampleDbId(callset.getCallSetDbId()); - callset.setVariantSetIds(Arrays.asList(module + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getProjectId() + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getRun())); + callset.setVariantSetIds(Arrays.asList(db + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getProjectId() + GigwaGa4ghServiceImpl.ID_SEPARATOR + sample.getRun())); final Individual ind = indMap.get(sample.getIndividual()); if (!ind.getAdditionalInfo().isEmpty()) callset.setAdditionalInfo(ind.getAdditionalInfo().keySet().stream().filter(k -> ind.getAdditionalInfo().get(k) != null).collect(Collectors.toMap(k -> k, k -> (List) Arrays.asList(ind.getAdditionalInfo().get(k).toString())))); diff --git a/src/main/java/org/brapi/v2/api/GermplasmApiController.java b/src/main/java/org/brapi/v2/api/GermplasmApiController.java index 55ef029..710205e 100644 --- a/src/main/java/org/brapi/v2/api/GermplasmApiController.java +++ b/src/main/java/org/brapi/v2/api/GermplasmApiController.java @@ -1,15 +1,9 @@ package org.brapi.v2.api; -import java.io.UnsupportedEncodingException; -import java.net.SocketException; -import java.net.URLDecoder; -import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -17,59 +11,36 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; -import org.apache.commons.lang.StringUtils; -import org.brapi.v2.model.Call; -import org.brapi.v2.model.CallListResponse; +import org.brapi.v2.model.ExternalReferences; +import org.brapi.v2.model.ExternalReferencesInner; import org.brapi.v2.model.Germplasm; import org.brapi.v2.model.GermplasmListResponse; import org.brapi.v2.model.GermplasmListResponseResult; -import org.brapi.v2.model.GermplasmMCPD; +import org.brapi.v2.model.GermplasmNewRequest.BiologicalStatusOfAccessionCodeEnum; import org.brapi.v2.model.GermplasmSearchRequest; import org.brapi.v2.model.IndexPagination; -import org.brapi.v2.model.ListValue; import org.brapi.v2.model.Metadata; -import org.brapi.v2.model.MetadataTokenPagination; import org.brapi.v2.model.Status; -import org.brapi.v2.model.TokenPagination; -import org.brapi.v2.model.GermplasmNewRequest.BiologicalStatusOfAccessionCodeEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; -import org.threeten.bp.LocalDate; -import org.threeten.bp.format.DateTimeParseException; import com.fasterxml.jackson.databind.ObjectMapper; import fr.cirad.io.brapi.BrapiService; -import fr.cirad.mgdb.model.mongo.maintypes.GenotypingProject; -import fr.cirad.mgdb.model.mongo.maintypes.GenotypingSample; -import fr.cirad.mgdb.model.mongo.maintypes.VariantData; -import fr.cirad.mgdb.model.mongo.maintypes.VariantRunData; -import fr.cirad.mgdb.model.mongo.maintypes.VariantRunData.VariantRunDataId; -import fr.cirad.mgdb.model.mongo.subtypes.AbstractVariantData; -import fr.cirad.mgdb.model.mongo.subtypes.SampleGenotype; import fr.cirad.mgdb.model.mongodao.MgdbDao; import fr.cirad.mgdb.service.GigwaGa4ghServiceImpl; import fr.cirad.mgdb.service.IGigwaService; import fr.cirad.model.GigwaSearchVariantsRequest; -import fr.cirad.tools.mongo.MongoTemplateManager; import fr.cirad.tools.security.base.AbstractTokenManager; import fr.cirad.web.controller.rest.BrapiRestController; import io.swagger.annotations.ApiParam; -import jhi.brapi.api.germplasm.BrapiGermplasm; -import org.brapi.v2.model.ExternalReferences; -import org.brapi.v2.model.ExternalReferencesInner; -import org.brapi.v2.model.GermplasmNewRequestStorageTypes; -import org.brapi.v2.model.GermplasmNewRequestStorageTypes.CodeEnum; @javax.annotation.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2021-03-22T14:25:44.495Z[GMT]") @CrossOrigin @@ -96,6 +67,28 @@ public GermplasmApiController(ObjectMapper objectMapper, HttpServletRequest requ this.objectMapper = objectMapper; this.request = request; } + + public static HashMap>> readGermplasmIDs(Collection germplasmDbIds) { + HashMap>> dbProjectIndividuals = new HashMap<>(); + for (String gpId : germplasmDbIds) { + String[] info = GigwaSearchVariantsRequest.getInfoFromId(gpId, 3); + int projId = Integer.parseInt(info[1]); + + HashMap> projectIndividuals = dbProjectIndividuals.get(info[0]); + if (projectIndividuals == null) { + projectIndividuals = new HashMap<>(); + dbProjectIndividuals.put(info[0], projectIndividuals); + } + + Collection individuals = projectIndividuals.get(projId); + if (individuals == null) { + individuals = new ArrayList<>(); + projectIndividuals.put(projId, individuals); + } + individuals.add(info[2]); + } + return dbProjectIndividuals; + } public ResponseEntity searchGermplasmPost(HttpServletResponse response, @ApiParam(value = "Germplasm Search request") @Valid @RequestBody GermplasmSearchRequest body, @ApiParam(value = "HTTP HEADER - Token used for Authorization Bearer {token_string} ") @RequestHeader(value = "Authorization", required = false) String authorization) throws Exception { String token = ServerinfoApiController.readToken(authorization); diff --git a/src/main/java/org/brapi/v2/api/StudiesApiController.java b/src/main/java/org/brapi/v2/api/StudiesApiController.java index db20a1d..ab72c94 100644 --- a/src/main/java/org/brapi/v2/api/StudiesApiController.java +++ b/src/main/java/org/brapi/v2/api/StudiesApiController.java @@ -1,6 +1,7 @@ package org.brapi.v2.api; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -29,6 +30,7 @@ import org.springframework.web.bind.annotation.RequestHeader; import fr.cirad.mgdb.model.mongo.maintypes.GenotypingProject; +import fr.cirad.mgdb.model.mongo.maintypes.GenotypingSample; import fr.cirad.mgdb.service.IGigwaService; import fr.cirad.model.GigwaSearchVariantsRequest; import fr.cirad.tools.Helper; @@ -52,6 +54,8 @@ public ResponseEntity searchStudiesPost(@ApiParam(value = "St try { StudyListResponse slr = new StudyListResponse(); StudyListResponseResult result = new StudyListResponseResult(); + Metadata metadata = new Metadata(); + slr.setMetadata(metadata); boolean fGotTrialIDs = body != null && body.getTrialDbIds() != null && !body.getTrialDbIds().isEmpty(); boolean fGotProgramIDs = body != null && body.getProgramDbIds() != null && !body.getProgramDbIds().isEmpty(); @@ -66,6 +70,21 @@ public ResponseEntity searchStudiesPost(@ApiParam(value = "St } moduleProjects.add(Integer.parseInt(info[1])); } + else if (body.getGermplasmDbIds() != null && !body.getGermplasmDbIds().isEmpty()) { + HashMap>> dbProjectIndividuals = GermplasmApiController.readGermplasmIDs(body.getGermplasmDbIds()); + for (String db : dbProjectIndividuals.keySet()) { + HashMap> projectIndividuals = dbProjectIndividuals.get(db); + for (int nProjId : projectIndividuals.keySet()) // make sure at least one germplasm exists in each project before returning it + if (MongoTemplateManager.get(db).count(new Query(new Criteria().andOperator(Criteria.where(GenotypingSample.FIELDNAME_PROJECT_ID).is(nProjId), Criteria.where(GenotypingSample.FIELDNAME_INDIVIDUAL).in(projectIndividuals.get(nProjId)))), GenotypingSample.class) > 0) { + HashSet moduleProjects = projectsByModule.get(db); + if (moduleProjects == null) { + moduleProjects = new HashSet<>(); + projectsByModule.put(db, moduleProjects); + } + moduleProjects.add(nProjId); + } + } + } for (String module : MongoTemplateManager.getAvailableModules()) if (body.getCommonCropNames() == null || body.getCommonCropNames().isEmpty() || body.getCommonCropNames().contains(Helper.nullToEmptyString(MongoTemplateManager.getTaxonName(module)))) { @@ -73,26 +92,23 @@ public ResponseEntity searchStudiesPost(@ApiParam(value = "St continue; for (GenotypingProject pj : MongoTemplateManager.get(module).find(projectsByModule.isEmpty() ? new Query() : new Query(Criteria.where("id_").in(projectsByModule.get(module))), GenotypingProject.class)) { - - if (tokenManager.canUserReadProject(token, module, pj.getId())) - result.addDataItem(new Study() {{ - setTrialDbId(module); - setStudyDbId(module + IGigwaService.ID_SEPARATOR + pj.getId()); - setStudyType("genotype"); - setStudyName(pj.getName()); /* variantSets in GA4GH correspond to projects, i.e. studies in BrAPI v2 */ - setStudyDescription(pj.getDescription()); - }} ); + if (tokenManager.canUserReadProject(token, module, pj.getId())) + result.addDataItem(new Study() {{ + setTrialDbId(module); + setStudyDbId(module + IGigwaService.ID_SEPARATOR + pj.getId()); + setStudyType("genotype"); + setStudyName(pj.getName()); /* variantSets in GA4GH correspond to projects, i.e. studies in BrAPI v2 */ + setStudyDescription(pj.getDescription()); + }} ); } } - Metadata metadata = new Metadata(); IndexPagination pagination = new IndexPagination(); pagination.setPageSize(result.getData().size()); pagination.setCurrentPage(0); pagination.setTotalPages(1); pagination.setTotalCount(result.getData().size()); metadata.setPagination(pagination); - slr.setMetadata(metadata); slr.setResult(result); return new ResponseEntity(slr, HttpStatus.OK);