From 014967cc3b15fd93c0c981207dd592a0125c5144 Mon Sep 17 00:00:00 2001 From: pfurio Date: Thu, 16 Nov 2023 15:54:14 +0100 Subject: [PATCH 1/7] core: add annotationSet support for ClinicalAnalysis, #TASK-5198 --- .../clinical/ClinicalTsvAnnotationLoader.java | 53 +++++ .../internal/InternalCliOptionsParser.java | 1 + .../executors/ClinicalCommandExecutor.java | 19 ++ .../options/ClinicalCommandOptions.java | 29 +++ .../db/api/ClinicalAnalysisDBAdaptor.java | 20 +- .../db/mongodb/AnnotationMongoDBAdaptor.java | 35 ++-- .../mongodb/AuthorizationMongoDBAdaptor.java | 2 +- .../ClinicalAnalysisMongoDBAdaptor.java | 134 ++++++++++--- .../db/mongodb/IndividualMongoDBAdaptor.java | 4 +- .../mongodb/InterpretationMongoDBAdaptor.java | 10 +- .../converters/ClinicalAnalysisConverter.java | 2 +- ...linicalAnalysisCatalogMongoDBIterator.java | 25 ++- .../managers/ClinicalAnalysisManager.java | 186 ++++++++++++------ .../catalog/managers/StudyManager.java | 9 +- .../catalog/managers/AbstractManagerTest.java | 2 +- .../managers/ClinicalAnalysisManagerTest.java | 126 ++++++++++++ .../models/clinical/ClinicalAnalysis.java | 15 +- .../ClinicalAnalysisCreateParams.java | 19 +- .../clinical/ClinicalAnalysisPermissions.java | 5 +- .../ClinicalAnalysisUpdateParams.java | 19 +- .../core/models/study/StudyPermissions.java | 8 +- .../core/models/study/VariableSet.java | 3 +- .../monitor/daemons/ExecutionDaemon.java | 2 + .../rest/analysis/ClinicalWebService.java | 68 ++++++- 24 files changed, 644 insertions(+), 152 deletions(-) create mode 100644 opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalTsvAnnotationLoader.java diff --git a/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalTsvAnnotationLoader.java b/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalTsvAnnotationLoader.java new file mode 100644 index 00000000000..1d2be95e82e --- /dev/null +++ b/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalTsvAnnotationLoader.java @@ -0,0 +1,53 @@ +/* + * Copyright 2015-2020 OpenCB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.opencb.opencga.analysis.clinical; + +import org.opencb.commons.datastore.core.ObjectMap; +import org.opencb.commons.datastore.core.Query; +import org.opencb.commons.datastore.core.QueryOptions; +import org.opencb.opencga.analysis.annotations.TsvAnnotationLoader; +import org.opencb.opencga.catalog.exceptions.CatalogException; +import org.opencb.opencga.catalog.managers.AnnotationSetManager; +import org.opencb.opencga.catalog.utils.Constants; +import org.opencb.opencga.catalog.utils.ParamUtils; +import org.opencb.opencga.core.models.clinical.ClinicalAnalysisUpdateParams; +import org.opencb.opencga.core.models.common.AnnotationSet; +import org.opencb.opencga.core.models.common.Enums; +import org.opencb.opencga.core.tools.annotations.Tool; + +import java.util.Collections; + +@Tool(id = ClinicalTsvAnnotationLoader.ID, resource = Enums.Resource.CLINICAL_ANALYSIS, type = Tool.Type.OPERATION, + description = "Load annotations from TSV file.") +public class ClinicalTsvAnnotationLoader extends TsvAnnotationLoader { + public final static String ID = "clinical-tsv-load"; + + @Override + public int count(Query query) throws CatalogException { + return catalogManager.getClinicalAnalysisManager().count(study, query, token).getNumResults(); + } + + @Override + public void addAnnotationSet(String entryId, AnnotationSet annotationSet, QueryOptions options) throws CatalogException { + ClinicalAnalysisUpdateParams updateParams = new ClinicalAnalysisUpdateParams() + .setAnnotationSets(Collections.singletonList(annotationSet)); + QueryOptions queryOptions = options != null ? new QueryOptions(options) : new QueryOptions(); + queryOptions.put(Constants.ACTIONS, new ObjectMap(AnnotationSetManager.ANNOTATION_SETS, ParamUtils.BasicUpdateAction.ADD)); + + catalogManager.getClinicalAnalysisManager().update(study, entryId, updateParams, queryOptions, token); + } +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/InternalCliOptionsParser.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/InternalCliOptionsParser.java index 132ad854c82..0079461d25a 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/InternalCliOptionsParser.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/InternalCliOptionsParser.java @@ -226,6 +226,7 @@ public InternalCliOptionsParser() { clinicalSubCommands.addCommand(RGA_INDEX_RUN_COMMAND, clinicalCommandOptions.rgaSecondaryIndexCommandOptions); clinicalSubCommands.addCommand(RGA_AUX_INDEX_RUN_COMMAND, clinicalCommandOptions.rgaAuxiliarSecondaryIndexCommandOptions); clinicalSubCommands.addCommand(EXOMISER_INTERPRETATION_RUN_COMMAND, clinicalCommandOptions.exomiserInterpretationCommandOptions); + clinicalSubCommands.addCommand("tsv-load", clinicalCommandOptions.tsvLoad); fileCommandOptions = new FileCommandOptions(commonCommandOptions, jCommander); jCommander.addCommand("files", fileCommandOptions); diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/executors/ClinicalCommandExecutor.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/executors/ClinicalCommandExecutor.java index e0785c79fee..14256ac1652 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/executors/ClinicalCommandExecutor.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/executors/ClinicalCommandExecutor.java @@ -24,6 +24,7 @@ import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; +import org.opencb.opencga.analysis.clinical.ClinicalTsvAnnotationLoader; import org.opencb.opencga.analysis.clinical.exomiser.ExomiserInterpretationAnalysis; import org.opencb.opencga.analysis.clinical.rga.AuxiliarRgaAnalysis; import org.opencb.opencga.analysis.clinical.rga.RgaAnalysis; @@ -96,6 +97,9 @@ public void execute() throws Exception { case EXOMISER_INTERPRETATION_RUN_COMMAND: exomiserInterpretation(); break; + case "tsv-load": + tsvLoad(); + break; default: logger.error("Subcommand not valid"); break; @@ -314,4 +318,19 @@ private void exomiserInterpretation() throws Exception { // exomiserInterpretationAnalysis.setPrimary(cliOptions.primary); exomiserInterpretationAnalysis.start(); } + + private void tsvLoad() throws ToolException { + ClinicalCommandOptions.TsvLoad options = clinicalCommandOptions.tsvLoad; + + Path outDir = Paths.get(options.outDir); + + ClinicalTsvAnnotationLoader annotationLoader = new ClinicalTsvAnnotationLoader(); + annotationLoader.setAnnotationSetId(options.annotationSetId); + annotationLoader.setVariableSetId(options.variableSetId); + annotationLoader.setPath(options.filePath); + annotationLoader.setStudy(options.study); + + annotationLoader.setUp(opencgaHome.toString(), new ObjectMap(), outDir, options.commonOptions.token); + annotationLoader.start(); + } } diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/options/ClinicalCommandOptions.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/options/ClinicalCommandOptions.java index 2663f3c7c5e..9c7f8806fc7 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/options/ClinicalCommandOptions.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/internal/options/ClinicalCommandOptions.java @@ -5,6 +5,7 @@ import com.beust.jcommander.Parameters; import com.beust.jcommander.ParametersDelegate; import org.opencb.biodata.models.clinical.ClinicalProperty; +import org.opencb.opencga.analysis.clinical.ClinicalTsvAnnotationLoader; import org.opencb.opencga.analysis.clinical.exomiser.ExomiserInterpretationAnalysis; import org.opencb.opencga.analysis.clinical.rga.AuxiliarRgaAnalysis; import org.opencb.opencga.analysis.clinical.rga.RgaAnalysis; @@ -14,6 +15,7 @@ import org.opencb.opencga.analysis.clinical.zetta.ZettaInterpretationAnalysis; import org.opencb.opencga.app.cli.GeneralCliOptions; import org.opencb.opencga.app.cli.internal.InternalCliOptionsParser; +import org.opencb.opencga.core.api.ParamConstants; import org.opencb.opencga.core.models.clinical.RgaAnalysisParams; import org.opencb.opencga.storage.app.cli.client.options.StorageVariantCommandOptions.BasicVariantQueryOptions; @@ -33,6 +35,7 @@ public class ClinicalCommandOptions { public final RgaSecondaryIndexCommandOptions rgaSecondaryIndexCommandOptions; public final RgaAuxiliarSecondaryIndexCommandOptions rgaAuxiliarSecondaryIndexCommandOptions; public final ExomiserInterpretationCommandOptions exomiserInterpretationCommandOptions; + public final TsvLoad tsvLoad; public JCommander jCommander; public GeneralCliOptions.CommonCommandOptions commonCommandOptions; @@ -53,6 +56,7 @@ public ClinicalCommandOptions(GeneralCliOptions.CommonCommandOptions commonComma this.rgaSecondaryIndexCommandOptions = new RgaSecondaryIndexCommandOptions(); this.rgaAuxiliarSecondaryIndexCommandOptions = new RgaAuxiliarSecondaryIndexCommandOptions(); this.exomiserInterpretationCommandOptions = new ExomiserInterpretationCommandOptions(); + this.tsvLoad = new TsvLoad(); } @Parameters(commandNames = {TieringCommandOptions.TIERING_INTERPRETATION_RUN_COMMAND}, commandDescription = @@ -335,4 +339,29 @@ public class ExomiserInterpretationCommandOptions extends GeneralCliOptions.Stud @Parameter(names = {"-o", "--outdir"}, description = "Directory where output files will be saved", arity = 1) public String outdir; } + + @Parameters(commandNames = {"tsv-load"}, commandDescription = "Load annotations from a TSV file") + public class TsvLoad extends GeneralCliOptions.StudyOption { + + public static final String TSV_LOAD_COMMAND = ClinicalTsvAnnotationLoader.ID; + + @ParametersDelegate + public GeneralCliOptions.CommonCommandOptions commonOptions = commonCommandOptions; + + @ParametersDelegate + public InternalCliOptionsParser.JobOptions jobOptions = internalJobOptions; + + @Parameter(names = {"--file"}, description = "Path to the TSV file.", required = true, arity = 1) + public String filePath; + + @Parameter(names = {"--variable-set-id"}, description = ParamConstants.VARIABLE_SET_DESCRIPTION, required = true, arity = 1) + public String variableSetId; + + @Parameter(names = {"--annotation-set-id"}, description = "AnnotationSet id that will be given to the new annotations.", + required = true, arity = 1) + public String annotationSetId; + + @Parameter(names = {"-o", "--outdir"}, description = "Directory where output files will be saved", required = true, arity = 1) + public String outDir; + } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java index f40e073d760..ac30c48e9d2 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java @@ -26,8 +26,10 @@ import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; +import org.opencb.opencga.catalog.utils.Constants; import org.opencb.opencga.core.api.ParamConstants; import org.opencb.opencga.core.models.clinical.ClinicalAnalysis; +import org.opencb.opencga.core.models.study.VariableSet; import org.opencb.opencga.core.response.OpenCGAResult; import java.util.List; @@ -38,7 +40,7 @@ /** * Created by pfurio on 05/06/17. */ -public interface ClinicalAnalysisDBAdaptor extends CoreDBAdaptor { +public interface ClinicalAnalysisDBAdaptor extends AnnotationSetDBAdaptor { enum QueryParams implements QueryParam { ID("id", TEXT, ""), @@ -109,7 +111,11 @@ enum QueryParams implements QueryParam { DELETED(ParamConstants.DELETED_PARAM, BOOLEAN, ""), STUDY_UID("studyUid", INTEGER_ARRAY, ""), - STUDY("study", INTEGER_ARRAY, ""); // Alias to studyId in the database. Only for the webservices. + STUDY("study", INTEGER_ARRAY, ""), // Alias to studyId in the database. Only for the webservices. + + ANNOTATION_SETS("annotationSets", TEXT_ARRAY, ""), + ANNOTATION_SET_NAME("annotationSetName", TEXT_ARRAY, ""), + ANNOTATION(Constants.ANNOTATION, TEXT_ARRAY, ""); private static Map map; @@ -170,14 +176,16 @@ default void checkId(long clinicalAnalysisId) throws CatalogDBException, Catalog OpenCGAResult nativeInsert(Map clinicalAnalysis, String userId) throws CatalogDBException; - OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, List clinicalAuditList, QueryOptions options) + OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, List variableSetList, + List clinicalAuditList, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; - OpenCGAResult update(long id, ObjectMap parameters, List clinicalAuditList, QueryOptions queryOptions) + OpenCGAResult update(long id, ObjectMap parameters, List variableSetList, + List clinicalAuditList, QueryOptions queryOptions) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; - OpenCGAResult update(Query query, ObjectMap parameters, List clinicalAuditList, - QueryOptions queryOptions) + OpenCGAResult update(Query query, ObjectMap parameters, List variableSetList, + List clinicalAuditList, QueryOptions queryOptions) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException; OpenCGAResult get(long clinicalAnalysisUid, QueryOptions options) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java index 15c7555e75e..e8cfa1d0ad1 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AnnotationMongoDBAdaptor.java @@ -262,7 +262,7 @@ public boolean containsAnnotationQuery(Query query) { return query.containsKey(Constants.ANNOTATION); } - OpenCGAResult updateAnnotationSets(ClientSession clientSession, long entryId, ObjectMap parameters, + OpenCGAResult updateAnnotationSets(ClientSession clientSession, long entryUid, ObjectMap parameters, List variableSetList, QueryOptions options, boolean isVersioned) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { Map actionMap = options.getMap(Constants.ACTIONS, new HashMap<>()); @@ -281,7 +281,7 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess // Create or remove a new annotation set if (action == ParamUtils.BasicUpdateAction.ADD || action == ParamUtils.BasicUpdateAction.SET) { // 1. Check the annotation set ids are not in use - validateNewAnnotations(clientSession, entryId, annotationSetList, variableSetList, isVersioned); + validateNewAnnotations(clientSession, entryUid, annotationSetList, variableSetList, isVersioned); // 2. Obtain the list of documents that need to be inserted List annotationDocumentList = getNewAnnotationList(annotationSetList, variableSetList); @@ -290,26 +290,26 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess if (action == ParamUtils.BasicUpdateAction.SET) { if (CollectionUtils.isEmpty(internalAnnotationDocumentList)) { // 2.1 Remove all user existing annotations - removeAllAnnotationSets(clientSession, entryId, isVersioned); + removeAllAnnotationSets(clientSession, entryUid, isVersioned); } else { // 2.1 Remove all internal existing annotations - removeAllAnnotationSets(clientSession, entryId, isVersioned, true); + removeAllAnnotationSets(clientSession, entryUid, isVersioned, true); } } if (CollectionUtils.isEmpty(internalAnnotationDocumentList)) { // 3. Insert the list of documents - addNewAnnotations(clientSession, entryId, annotationDocumentList, isVersioned); + addNewAnnotations(clientSession, entryUid, annotationDocumentList, isVersioned); // 4. Set variable set map uid - id - addPrivateVariableMap(clientSession, entryId, getPrivateVariableMapToSet(annotationSetList, variableSetList), + addPrivateVariableMap(clientSession, entryUid, getPrivateVariableMapToSet(annotationSetList, variableSetList), isVersioned); } else { // 3. Insert the list of documents - addNewAnnotations(clientSession, entryId, internalAnnotationDocumentList, isVersioned, true); + addNewAnnotations(clientSession, entryUid, internalAnnotationDocumentList, isVersioned, true); // 4. Set variable set map uid - id - addPrivateVariableMap(clientSession, entryId, getPrivateVariableMapToSet(annotationSetList, variableSetList), + addPrivateVariableMap(clientSession, entryUid, getPrivateVariableMapToSet(annotationSetList, variableSetList), isVersioned, true); } @@ -317,7 +317,7 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess // Action = REMOVE // 0. Obtain the annotationSet to be removed to know the variableSet being annotated - OpenCGAResult queryResult = nativeGet(new Query(PRIVATE_UID, entryId), new QueryOptions(QueryOptions.INCLUDE, + OpenCGAResult queryResult = nativeGet(new Query(PRIVATE_UID, entryUid), new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(ANNOTATION_SETS))); if (queryResult.getNumResults() != 1) { @@ -373,7 +373,7 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess } // 1. Remove annotationSet - removeAnnotationSetByAnnotationSetId(clientSession, entryId, annotationSet.getId(), isVersioned); + removeAnnotationSetByAnnotationSetId(clientSession, entryUid, annotationSet.getId(), isVersioned); String variableSetId = annotationSetIdVariableSetUidMap.get(annotationSet.getId()); // Remove the annotation set from the variableSetAnnotationsets @@ -384,7 +384,7 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess // 2. Unset variable set map uid - id Map variableSetMapToRemove = new HashMap<>(); variableSetMapToRemove.put(variableSetId, null); - removePrivateVariableMap(clientSession, entryId, variableSetMapToRemove, isVersioned); + removePrivateVariableMap(clientSession, entryUid, variableSetMapToRemove, isVersioned); } } else if (StringUtils.isNotEmpty(annotationSet.getVariableSetId())) { VariableSet variableSet = variableSetMap.get(annotationSet.getVariableSetId()); @@ -402,19 +402,18 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess if (!variableSet.isInternal()) { // Remove all annotationSets - removeAnnotationSetByVariableSetId(clientSession, entryId, variableSet.getUid(), isVersioned); - removePrivateVariableMap(clientSession, entryId, variableSetMapToRemove, isVersioned); + removeAnnotationSetByVariableSetId(clientSession, entryUid, variableSet.getUid(), isVersioned); + removePrivateVariableMap(clientSession, entryUid, variableSetMapToRemove, isVersioned); } else { // Remove all annotationSets - removeAnnotationSetByVariableSetId(clientSession, entryId, variableSet.getUid(), isVersioned, true); - removePrivateVariableMap(clientSession, entryId, variableSetMapToRemove, isVersioned, true); + removeAnnotationSetByVariableSetId(clientSession, entryUid, variableSet.getUid(), isVersioned, true); + removePrivateVariableMap(clientSession, entryUid, variableSetMapToRemove, isVersioned, true); } } } else { throw new CatalogDBException("Could not delete AnnotationSet. AnnotationSet 'id' or 'variableSetId' not defined."); } } - } } else if (actionMap.containsKey(ANNOTATIONS)) { // Update annotation @@ -424,10 +423,10 @@ OpenCGAResult updateAnnotationSets(ClientSession clientSess List annotationDocumentList = getNewAnnotationList(Collections.singletonList(annotationSet), variableSetList); // 2. Remove all the existing annotations of the annotation set - removeAnnotationSetByAnnotationSetId(clientSession, entryId, annotationSet.getId(), isVersioned); + removeAnnotationSetByAnnotationSetId(clientSession, entryUid, annotationSet.getId(), isVersioned); // 3. Add new list of annotations - addNewAnnotations(clientSession, entryId, annotationDocumentList, isVersioned); + addNewAnnotations(clientSession, entryUid, annotationDocumentList, isVersioned); } return endWrite(startTime, 1, 1, new ArrayList<>()); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java index fff9a1ed3b3..26d65edff3f 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/AuthorizationMongoDBAdaptor.java @@ -128,7 +128,7 @@ private void initCollectionConnections() { this.dbCollectionMap.put(Enums.Resource.JOB, Collections.singletonList(dbAdaptorFactory.getCatalogJobDBAdaptor().getJobCollection())); this.dbCollectionMap.put(Enums.Resource.CLINICAL_ANALYSIS, - Collections.singletonList(dbAdaptorFactory.getClinicalAnalysisDBAdaptor().getClinicalCollection())); + Collections.singletonList(dbAdaptorFactory.getClinicalAnalysisDBAdaptor().getCollection())); // Versioned models will always have first the main collection and second the archive collection this.dbCollectionMap.put(Enums.Resource.INDIVIDUAL, Arrays.asList(dbAdaptorFactory.getCatalogIndividualDBAdaptor().getCollection(), diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java index 9ef226dabde..67f9a035aa0 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java @@ -48,6 +48,7 @@ import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.models.clinical.*; +import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.Enums; import org.opencb.opencga.core.models.common.FlagAnnotation; import org.opencb.opencga.core.models.common.InternalStatus; @@ -56,22 +57,27 @@ import org.opencb.opencga.core.models.individual.Individual; import org.opencb.opencga.core.models.panel.Panel; import org.opencb.opencga.core.models.sample.Sample; +import org.opencb.opencga.core.models.study.StudyPermissions; +import org.opencb.opencga.core.models.study.VariableSet; import org.opencb.opencga.core.response.OpenCGAResult; import org.slf4j.LoggerFactory; +import javax.annotation.Nullable; import java.io.IOException; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.function.UnaryOperator; import static org.opencb.opencga.catalog.db.api.ClinicalAnalysisDBAdaptor.QueryParams.*; +import static org.opencb.opencga.catalog.db.mongodb.AuthorizationMongoDBUtils.filterAnnotationSets; import static org.opencb.opencga.catalog.db.mongodb.AuthorizationMongoDBUtils.getQueryForAuthorisedEntries; import static org.opencb.opencga.catalog.db.mongodb.MongoDBUtils.*; /** * Created by pfurio on 05/06/17. */ -public class ClinicalAnalysisMongoDBAdaptor extends MongoDBAdaptor implements ClinicalAnalysisDBAdaptor { +public class ClinicalAnalysisMongoDBAdaptor extends AnnotationMongoDBAdaptor implements ClinicalAnalysisDBAdaptor { private static final String PRIVATE_DUE_DATE = "_dueDate"; private final MongoDBCollection clinicalCollection; @@ -87,6 +93,11 @@ public ClinicalAnalysisMongoDBAdaptor(MongoDBCollection clinicalCollection, Mong this.clinicalConverter = new ClinicalAnalysisConverter(); } + @Override + protected MongoDBCollection getCollection() { + return clinicalCollection; + } + static void fixCommentsForRemoval(ObjectMap parameters) { if (parameters.get(COMMENTS.key()) == null) { return; @@ -144,8 +155,27 @@ static void fixFilesForRemoval(ObjectMap parameters) { parameters.put(FILES.key(), fileParamList); } - public MongoDBCollection getClinicalCollection() { - return clinicalCollection; + @Override + public OpenCGAResult getAnnotationSet(long id, @Nullable String annotationSetName) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + QueryOptions queryOptions = new QueryOptions(); + List includeList = new ArrayList<>(); + + if (StringUtils.isNotEmpty(annotationSetName)) { + includeList.add(Constants.ANNOTATION_SET_NAME + "." + annotationSetName); + } else { + includeList.add(QueryParams.ANNOTATION_SETS.key()); + } + queryOptions.put(QueryOptions.INCLUDE, includeList); + + OpenCGAResult clinicalDataResult = get(id, queryOptions); + if (CollectionUtils.isEmpty(clinicalDataResult.first().getAnnotationSets())) { + return new OpenCGAResult<>(clinicalDataResult.getTime(), clinicalDataResult.getEvents(), 0, Collections.emptyList(), 0); + } else { + List annotationSets = clinicalDataResult.first().getAnnotationSets(); + int size = annotationSets.size(); + return new OpenCGAResult<>(clinicalDataResult.getTime(), clinicalDataResult.getEvents(), size, annotationSets, size); + } } @Override @@ -190,7 +220,8 @@ public OpenCGAResult update(Query query, ObjectMap parameters, } @Override - public OpenCGAResult update(long uid, ObjectMap parameters, List clinicalAuditList, QueryOptions queryOptions) + public OpenCGAResult update(long uid, ObjectMap parameters, List variableSetList, List clinicalAuditList, + QueryOptions queryOptions) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { Query query = new Query(QueryParams.UID.key(), uid); QueryOptions options = new QueryOptions() @@ -203,7 +234,8 @@ public OpenCGAResult update(long uid, ObjectMap parameters, List String clinicalAnalysisId = result.first().getId(); try { - return runTransaction(clientSession -> update(clientSession, result.first(), parameters, clinicalAuditList, queryOptions)); + return runTransaction(clientSession -> privateUpdate(clientSession, result.first(), parameters, variableSetList, + clinicalAuditList, queryOptions)); } catch (CatalogDBException e) { logger.error("Could not update clinical analysis {}: {}", clinicalAnalysisId, e.getMessage(), e); throw new CatalogDBException("Could not update clinical analysis " + clinicalAnalysisId + ": " + e.getMessage(), e.getCause()); @@ -211,26 +243,40 @@ public OpenCGAResult update(long uid, ObjectMap parameters, List } @Override - public OpenCGAResult update(Query query, ObjectMap parameters, List clinicalAuditList, QueryOptions queryOptions) - throws CatalogDBException { - return null; + public OpenCGAResult update(Query query, ObjectMap parameters, List variableSetList, List clinicalAuditList, + QueryOptions queryOptions) throws CatalogDBException { + throw new NotImplementedException("Not possible updating Clinical Analyses based on a query"); } - OpenCGAResult update(ClientSession clientSession, ClinicalAnalysis clinical, ObjectMap parameters, - List clinicalAuditList, QueryOptions queryOptions) + @Override + public OpenCGAResult update(long uid, ObjectMap parameters, List variableSetList, QueryOptions queryOptions) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throw new NotImplementedException("Use other update method passing the ClinicalAuditList"); + } + + @Override + public OpenCGAResult update(Query query, ObjectMap parameters, List variableSetList, QueryOptions queryOptions) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + throw new NotImplementedException("Use other update method passing the ClinicalAuditList"); + } + + OpenCGAResult privateUpdate(ClientSession clientSession, ClinicalAnalysis clinical, ObjectMap parameters, + List variableSetList, List clinicalAuditList, QueryOptions queryOptions) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { long tmpStartTime = startQuery(); String clinicalAnalysisId = clinical.getId(); long clinicalAnalysisUid = clinical.getUid(); + DataResult result = updateAnnotationSets(clientSession, clinicalAnalysisUid, parameters, variableSetList, queryOptions, false); + + // Perform the update Query query = new Query(QueryParams.UID.key(), clinicalAnalysisUid); UpdateDocument updateDocument = parseAndValidateUpdateParams(parameters, clinicalAuditList, query, queryOptions); Document updateOperation = updateDocument.toFinalUpdateDocument(); - List events = new ArrayList<>(); if (!updateOperation.isEmpty() || !updateDocument.getNestedUpdateList().isEmpty()) { - DataResult update; + DataResult update; if (!updateOperation.isEmpty()) { Bson bsonQuery = Filters.eq(PRIVATE_UID, clinicalAnalysisUid); @@ -270,7 +316,7 @@ OpenCGAResult update(ClientSession clientSession, ClinicalAnalysis clinical, Obj } } - } else { + } else if (result.getNumUpdated() == 0) { throw new CatalogDBException("Nothing to update"); } @@ -679,7 +725,7 @@ public DBIterator iterator(Query query, QueryOptions options) public DBIterator iterator(ClientSession clientSession, Query query, QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { MongoDBIterator mongoCursor = getMongoCursor(clientSession, query, options, null); - return new ClinicalAnalysisCatalogMongoDBIterator<>(mongoCursor, clientSession, clinicalConverter, dbAdaptorFactory, options); + return new ClinicalAnalysisCatalogMongoDBIterator<>(mongoCursor, clientSession, clinicalConverter, null, dbAdaptorFactory, options); } @Override @@ -694,7 +740,7 @@ private DBIterator nativeIterator(ClientSession clientSession, Query q queryOptions.put(NATIVE_QUERY, true); MongoDBIterator mongoCursor = getMongoCursor(clientSession, query, queryOptions); - return new ClinicalAnalysisCatalogMongoDBIterator(mongoCursor, clientSession, null, dbAdaptorFactory, queryOptions); + return new ClinicalAnalysisCatalogMongoDBIterator(mongoCursor, clientSession, null, null, dbAdaptorFactory, queryOptions); } @Override @@ -702,7 +748,12 @@ public DBIterator iterator(long studyUid, Query query, QueryOp throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { query.put(PRIVATE_STUDY_UID, studyUid); MongoDBIterator mongoCursor = getMongoCursor(query, options, user); - return new ClinicalAnalysisCatalogMongoDBIterator(mongoCursor, null, clinicalConverter, dbAdaptorFactory, studyUid, user, options); + Document studyDocument = getStudyDocument(null, studyUid); + UnaryOperator iteratorFilter = (d) -> filterAnnotationSets(studyDocument, d, user, + StudyPermissions.Permissions.VIEW_CLINICAL_ANNOTATIONS.name(), + ClinicalAnalysisPermissions.VIEW_ANNOTATIONS.name()); + return new ClinicalAnalysisCatalogMongoDBIterator(mongoCursor, null, clinicalConverter, iteratorFilter, dbAdaptorFactory, studyUid, + user, options); } @Override @@ -710,10 +761,14 @@ public DBIterator nativeIterator(long studyUid, Query query, QueryOptions option throws CatalogDBException, CatalogAuthorizationException, CatalogParameterException { QueryOptions queryOptions = options != null ? new QueryOptions(options) : new QueryOptions(); queryOptions.put(NATIVE_QUERY, true); - query.put(PRIVATE_STUDY_UID, studyUid); MongoDBIterator mongoCursor = getMongoCursor(query, queryOptions, user); - return new ClinicalAnalysisCatalogMongoDBIterator(mongoCursor, null, null, dbAdaptorFactory, studyUid, user, options); + Document studyDocument = getStudyDocument(null, studyUid); + UnaryOperator iteratorFilter = (d) -> filterAnnotationSets(studyDocument, d, user, + StudyPermissions.Permissions.VIEW_CLINICAL_ANNOTATIONS.name(), + ClinicalAnalysisPermissions.VIEW_ANNOTATIONS.name()); + return new ClinicalAnalysisCatalogMongoDBIterator(mongoCursor, null, null, iteratorFilter, dbAdaptorFactory, studyUid, user, + options); } private MongoDBIterator getMongoCursor(ClientSession clientSession, Query query, QueryOptions options) @@ -823,14 +878,15 @@ public OpenCGAResult nativeInsert(Map clinicalAnalysis, String u } @Override - public OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, List clinicalAuditList, - QueryOptions options) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { + public OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, List variableSetList, + List clinicalAuditList, QueryOptions options) + throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { try { return runTransaction(clientSession -> { long tmpStartTime = startQuery(); logger.debug("Starting ClinicalAnalysis insert transaction for ClinicalAnalysis id '{}'", clinicalAnalysis.getId()); dbAdaptorFactory.getCatalogStudyDBAdaptor().checkId(studyId); - insert(clientSession, studyId, clinicalAnalysis, clinicalAuditList); + insert(clientSession, studyId, clinicalAnalysis, variableSetList, clinicalAuditList); return endWrite(tmpStartTime, 1, 1, 0, 0, null); }); } catch (Exception e) { @@ -839,7 +895,8 @@ public OpenCGAResult insert(long studyId, ClinicalAnalysis clinicalAnalysis, Lis } } - ClinicalAnalysis insert(ClientSession clientSession, long studyId, ClinicalAnalysis clinicalAnalysis, List clinicalAudit) + ClinicalAnalysis insert(ClientSession clientSession, long studyId, ClinicalAnalysis clinicalAnalysis, List variableSetList, + List clinicalAudit) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { if (clinicalAnalysis.getInterpretation() != null) { InterpretationMongoDBAdaptor interpretationDBAdaptor = dbAdaptorFactory.getInterpretationDBAdaptor(); @@ -865,7 +922,7 @@ ClinicalAnalysis insert(ClientSession clientSession, long studyId, ClinicalAnaly clinicalAnalysis.setUuid(UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.CLINICAL)); } - Document clinicalDocument = clinicalConverter.convertToStorageType(clinicalAnalysis); + Document clinicalDocument = clinicalConverter.convertToStorageType(clinicalAnalysis, variableSetList); if (StringUtils.isNotEmpty(clinicalAnalysis.getCreationDate())) { clinicalDocument.put(PRIVATE_CREATION_DATE, TimeUtils.toDate(clinicalAnalysis.getCreationDate())); } else { @@ -1001,8 +1058,8 @@ void updateClinicalAnalysisFamilyReferences(ClientSession clientSession, Family } ObjectMap params = new ObjectMap(QueryParams.FAMILY.key(), familyCopy); - OpenCGAResult result = dbAdaptorFactory.getClinicalAnalysisDBAdaptor().update(clientSession, clinicalAnalysis, params, - null, QueryOptions.empty()); + OpenCGAResult result = dbAdaptorFactory.getClinicalAnalysisDBAdaptor().privateUpdate(clientSession, clinicalAnalysis, + params, Collections.emptyList(), null, QueryOptions.empty()); if (result.getNumUpdated() != 1) { throw new CatalogDBException("ClinicalAnalysis '" + clinicalAnalysis.getId() + "' could not be updated to the latest " + "family version of '" + family.getId() + "'"); @@ -1059,7 +1116,7 @@ void updateClinicalAnalysisPanelReferences(ClientSession clientSession, Panel pa actionMap.put(PANELS.key(), ParamUtils.BasicUpdateAction.SET); QueryOptions updateOptions = new QueryOptions(Constants.ACTIONS, actionMap); ObjectMap params = new ObjectMap(PANELS.key(), panelList); - update(clientSession, clinicalAnalysis, params, null, updateOptions); + privateUpdate(clientSession, clinicalAnalysis, params, Collections.emptyList(), null, updateOptions); // Update references from Interpretations dbAdaptorFactory.getInterpretationDBAdaptor().updateInterpretationPanelReferences(clientSession, clinicalAnalysis, panel); @@ -1082,6 +1139,7 @@ protected Bson parseQuery(Query query, Document extraQuery) private Bson parseQuery(Query query, Document extraQuery, String user) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { List andBsonList = new ArrayList<>(); + Document annotationDocument = null; Query queryCopy = new Query(query); queryCopy.remove(QueryParams.DELETED.key()); @@ -1094,9 +1152,13 @@ private Bson parseQuery(Query query, Document extraQuery, String user) andBsonList.addAll(AuthorizationMongoDBUtils.parseAclQuery(studyDocument, queryCopy, Enums.Resource.CLINICAL_ANALYSIS, user, configuration)); } else { - // Get the document query needed to check the permissions as well - andBsonList.add(getQueryForAuthorisedEntries(studyDocument, user, - ClinicalAnalysisPermissions.VIEW.name(), Enums.Resource.CLINICAL_ANALYSIS, configuration)); + if (containsAnnotationQuery(query)) { + andBsonList.add(getQueryForAuthorisedEntries(studyDocument, user, + ClinicalAnalysisPermissions.VIEW_ANNOTATIONS.name(), Enums.Resource.CLINICAL_ANALYSIS, configuration)); + } else { + andBsonList.add(getQueryForAuthorisedEntries(studyDocument, user, ClinicalAnalysisPermissions.VIEW.name(), + Enums.Resource.CLINICAL_ANALYSIS, configuration)); + } } queryCopy.remove(ParamConstants.ACL_PARAM); @@ -1107,6 +1169,9 @@ private Bson parseQuery(Query query, Document extraQuery, String user) QueryParams queryParam = QueryParams.getParam(entry.getKey()) != null ? QueryParams.getParam(entry.getKey()) : QueryParams.getParam(key); if (queryParam == null) { + if (Constants.PRIVATE_ANNOTATION_PARAM_TYPES.equals(entry.getKey())) { + continue; + } throw new CatalogDBException("Unexpected parameter " + entry.getKey() + ". The parameter does not exist or cannot be " + "queried for."); } @@ -1154,6 +1219,12 @@ private Bson parseQuery(Query query, Document extraQuery, String user) queryCopy.getString(queryParam.key()))); addAutoOrQuery(INTERNAL_STATUS_ID.key(), queryParam.key(), queryCopy, INTERNAL_STATUS_ID.type(), andBsonList); break; + case ANNOTATION: + if (annotationDocument == null) { + annotationDocument = createAnnotationQuery(queryCopy.getString(QueryParams.ANNOTATION.key()), + queryCopy.get(Constants.PRIVATE_ANNOTATION_PARAM_TYPES, ObjectMap.class)); + } + break; // Other parameter that can be queried. case ID: case UUID: @@ -1179,11 +1250,14 @@ private Bson parseQuery(Query query, Document extraQuery, String user) throw new CatalogDBException("Cannot query by parameter " + queryParam.key()); } } catch (Exception e) { - logger.error("Error with " + entry.getKey() + " " + entry.getValue()); + logger.error("Error with {}: {}", entry.getKey(), entry.getValue()); throw new CatalogDBException(e); } } + if (annotationDocument != null && !annotationDocument.isEmpty()) { + andBsonList.add(annotationDocument); + } if (extraQuery != null && !extraQuery.isEmpty()) { andBsonList.add(extraQuery); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java index 6437a0293b2..d9c6857200a 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/IndividualMongoDBAdaptor.java @@ -625,8 +625,8 @@ private void updateClinicalAnalysisIndividualReferences(ClientSession clientSess ObjectMap params = new ObjectMap(ClinicalAnalysisDBAdaptor.QueryParams.PROBAND.key(), individualCopy); - OpenCGAResult result = dbAdaptorFactory.getClinicalAnalysisDBAdaptor().update(clientSession, clinicalAnalysis, params, null, - QueryOptions.empty()); + OpenCGAResult result = dbAdaptorFactory.getClinicalAnalysisDBAdaptor().privateUpdate(clientSession, clinicalAnalysis, + params, Collections.emptyList(), null, QueryOptions.empty()); if (result.getNumUpdated() != 1) { throw new CatalogDBException("ClinicalAnalysis '" + clinicalAnalysis.getId() + "' could not be updated to the latest " + "individual version of '" + individual.getId() + "'"); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java index cf2b0a64eaa..97b1d50546b 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/InterpretationMongoDBAdaptor.java @@ -200,7 +200,7 @@ private void updateClinicalAnalysisReferences(ClientSession clientSession, Inter } // Update interpretation(s) in ClinicalAnalysis - clinicalDBAdaptor.update(clientSession, ca, params, clinicalAuditList, options); + clinicalDBAdaptor.privateUpdate(clientSession, ca, params, Collections.emptyList(), clinicalAuditList, options); break; case SECONDARY: // Add to secondaryInterpretations array in ClinicalAnalysis @@ -215,7 +215,7 @@ private void updateClinicalAnalysisReferences(ClientSession clientSession, Inter params.put(ClinicalAnalysisDBAdaptor.QueryParams.INTERPRETATION.key(), null); } - clinicalDBAdaptor.update(clientSession, ca, params, clinicalAuditList, options); + clinicalDBAdaptor.privateUpdate(clientSession, ca, params, Collections.emptyList(), clinicalAuditList, options); break; default: throw new IllegalStateException("Unknown action " + action); @@ -785,7 +785,8 @@ private void updateClinicalAnalysisInterpretationReference(ClientSession clientS params = new ObjectMap(ClinicalAnalysisDBAdaptor.QueryParams.SECONDARY_INTERPRETATIONS.key(), interpretationList); } - OpenCGAResult update = clinicalDBAdaptor.update(clientSession, ca, params, clinicalAuditList, options); + OpenCGAResult update = clinicalDBAdaptor.privateUpdate(clientSession, ca, params, Collections.emptyList(), clinicalAuditList, + options); if (update.getNumUpdated() != 1) { throw new CatalogDBException("Could not update interpretation reference in Clinical Analysis to new version"); } @@ -877,7 +878,8 @@ OpenCGAResult delete(ClientSession clientSession, Interpretation interpretation, actions.put(ClinicalAnalysisDBAdaptor.QueryParams.SECONDARY_INTERPRETATIONS.key(), ParamUtils.BasicUpdateAction.REMOVE); clinicalOptions.put(Constants.ACTIONS, actions); } - clinicalDBAdaptor.update(clientSession, clinicalAnalysis, clinicalParams, clinicalAuditList, clinicalOptions); + clinicalDBAdaptor.privateUpdate(clientSession, clinicalAnalysis, clinicalParams, Collections.emptyList(), clinicalAuditList, + clinicalOptions); Query query = new Query() .append(QueryParams.UID.key(), interpretation.getUid()) diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/ClinicalAnalysisConverter.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/ClinicalAnalysisConverter.java index 1244c9a7b7e..9fb50af19d7 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/ClinicalAnalysisConverter.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/converters/ClinicalAnalysisConverter.java @@ -32,7 +32,7 @@ /** * Created by pfurio on 05/06/17. */ -public class ClinicalAnalysisConverter extends OpenCgaMongoConverter { +public class ClinicalAnalysisConverter extends AnnotableConverter { public ClinicalAnalysisConverter() { super(ClinicalAnalysis.class); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/ClinicalAnalysisCatalogMongoDBIterator.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/ClinicalAnalysisCatalogMongoDBIterator.java index 05607ed5a68..fa4ead98ef1 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/ClinicalAnalysisCatalogMongoDBIterator.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/iterators/ClinicalAnalysisCatalogMongoDBIterator.java @@ -21,24 +21,26 @@ import org.bson.Document; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; -import org.opencb.commons.datastore.mongodb.GenericDocumentComplexConverter; import org.opencb.commons.datastore.mongodb.MongoDBIterator; import org.opencb.opencga.catalog.db.api.*; import org.opencb.opencga.catalog.db.mongodb.*; +import org.opencb.opencga.catalog.db.mongodb.converters.AnnotableConverter; import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogDBException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.core.common.JacksonUtils; +import org.opencb.opencga.core.models.common.Annotable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.*; +import java.util.function.UnaryOperator; import static org.opencb.opencga.catalog.db.api.ClinicalAnalysisDBAdaptor.QueryParams.*; import static org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor.NATIVE_QUERY; -public class ClinicalAnalysisCatalogMongoDBIterator extends CatalogMongoDBIterator { +public class ClinicalAnalysisCatalogMongoDBIterator extends AnnotableCatalogMongoDBIterator { private long studyUid; private String user; @@ -54,8 +56,6 @@ public class ClinicalAnalysisCatalogMongoDBIterator extends CatalogMongoDBIte private QueryOptions interpretationQueryOptions; private QueryOptions panelQueryOptions; - private QueryOptions options; - private Queue clinicalAnalysisListBuffer; private Logger logger; @@ -68,21 +68,20 @@ public class ClinicalAnalysisCatalogMongoDBIterator extends CatalogMongoDBIte private static final String UID_VERSION_SEP = "___"; public ClinicalAnalysisCatalogMongoDBIterator(MongoDBIterator mongoCursor, ClientSession clientSession, - GenericDocumentComplexConverter converter, MongoDBAdaptorFactory dbAdaptorFactory, - QueryOptions options) { - this(mongoCursor, clientSession, converter, dbAdaptorFactory, 0, null, options); + AnnotableConverter converter, UnaryOperator filter, + MongoDBAdaptorFactory dbAdaptorFactory, QueryOptions options) { + this(mongoCursor, clientSession, converter, filter, dbAdaptorFactory, 0, null, options); } public ClinicalAnalysisCatalogMongoDBIterator(MongoDBIterator mongoCursor, ClientSession clientSession, - GenericDocumentComplexConverter converter, MongoDBAdaptorFactory dbAdaptorFactory, - long studyUid, String user, QueryOptions options) { - super(mongoCursor, clientSession, converter, null); + AnnotableConverter converter, UnaryOperator filter, + MongoDBAdaptorFactory dbAdaptorFactory, long studyUid, String user, + QueryOptions options) { + super(mongoCursor, clientSession, converter, filter, options); this.user = user; this.studyUid = studyUid; - this.options = options; - this.fileDBAdaptor = dbAdaptorFactory.getCatalogFileDBAdaptor(); this.familyDBAdaptor = dbAdaptorFactory.getCatalogFamilyDBAdaptor(); this.individualDBAdaptor = dbAdaptorFactory.getCatalogIndividualDBAdaptor(); @@ -110,7 +109,7 @@ public E next() { addAclInformation(next, options); if (converter != null) { - return (E) converter.convertToDataModelType(next); + return (E) converter.convertToDataModelType(next, options); } else { return (E) next; } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java index da22c3da07b..63a0ca46dd6 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java @@ -19,7 +19,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.opencb.biodata.models.clinical.*; +import org.opencb.biodata.models.clinical.ClinicalAnalyst; +import org.opencb.biodata.models.clinical.ClinicalAudit; +import org.opencb.biodata.models.clinical.ClinicalComment; +import org.opencb.biodata.models.clinical.Disorder; import org.opencb.biodata.models.common.Status; import org.opencb.commons.datastore.core.Event; import org.opencb.commons.datastore.core.ObjectMap; @@ -34,16 +37,19 @@ import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.models.InternalGetDataResult; +import org.opencb.opencga.catalog.utils.AnnotationUtils; import org.opencb.opencga.catalog.utils.Constants; import org.opencb.opencga.catalog.utils.ParamUtils; import org.opencb.opencga.catalog.utils.UuidUtils; import org.opencb.opencga.core.api.ParamConstants; +import org.opencb.opencga.core.common.JacksonUtils; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.models.AclEntryList; import org.opencb.opencga.core.models.AclParams; import org.opencb.opencga.core.models.audit.AuditRecord; import org.opencb.opencga.core.models.clinical.*; +import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.Enums; import org.opencb.opencga.core.models.common.FlagAnnotation; import org.opencb.opencga.core.models.common.FlagValue; @@ -56,6 +62,7 @@ import org.opencb.opencga.core.models.sample.Sample; import org.opencb.opencga.core.models.study.Study; import org.opencb.opencga.core.models.study.StudyPermissions; +import org.opencb.opencga.core.models.study.VariableSet; import org.opencb.opencga.core.models.study.configuration.ClinicalConsent; import org.opencb.opencga.core.models.study.configuration.*; import org.opencb.opencga.core.models.user.User; @@ -64,6 +71,7 @@ import org.slf4j.LoggerFactory; import javax.annotation.Nullable; +import java.io.IOException; import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; @@ -75,7 +83,7 @@ /** * Created by pfurio on 05/06/17. */ -public class ClinicalAnalysisManager extends ResourceManager { +public class ClinicalAnalysisManager extends AnnotationSetManager { public static final QueryOptions INCLUDE_CLINICAL_IDS = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( ClinicalAnalysisDBAdaptor.QueryParams.ID.key(), ClinicalAnalysisDBAdaptor.QueryParams.UID.key(), @@ -204,9 +212,10 @@ public DBIterator iterator(String studyStr, Query query, Query options = ParamUtils.defaultObject(options, QueryOptions::new); String userId = catalogManager.getUserManager().getUserId(sessionId); - Study study = catalogManager.getStudyManager().resolveId(studyStr, userId); + Study study = catalogManager.getStudyManager().resolveId(studyStr, userId, StudyManager.INCLUDE_VARIABLE_SET); fixQueryObject(study, query, userId, sessionId); + AnnotationUtils.fixQueryOptionAnnotation(options); query.append(ClinicalAnalysisDBAdaptor.QueryParams.STUDY_UID.key(), study.getUid()); return clinicalDBAdaptor.iterator(study.getUid(), query, options, userId); @@ -222,7 +231,7 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis Boolean skipCreateDefaultInterpretation, QueryOptions options, String token) throws CatalogException { String userId = catalogManager.getUserManager().getUserId(token); - Study study = catalogManager.getStudyManager().resolveId(studyStr, userId, StudyManager.INCLUDE_CONFIGURATION); + Study study = catalogManager.getStudyManager().resolveId(studyStr, userId, StudyManager.INCLUDE_VARIABLE_SET_AND_CONFIGURATION); ObjectMap auditParams = new ObjectMap() .append("study", studyStr) @@ -258,6 +267,7 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis clinicalAnalysis.setQualityControl(ParamUtils.defaultObject(clinicalAnalysis.getQualityControl(), ClinicalAnalysisQualityControl::new)); clinicalAnalysis.setPanels(ParamUtils.defaultObject(clinicalAnalysis.getPanels(), Collections.emptyList())); + clinicalAnalysis.setAnnotationSets(ParamUtils.defaultObject(clinicalAnalysis.getAnnotationSets(), Collections.emptyList())); if (clinicalAnalysis.getQualityControl().getComments() != null) { for (ClinicalComment comment : clinicalAnalysis.getQualityControl().getComments()) { @@ -561,7 +571,8 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis clinicalAuditList.add(new ClinicalAudit(userId, ClinicalAudit.Action.CREATE_CLINICAL_ANALYSIS, "Create ClinicalAnalysis '" + clinicalAnalysis.getId() + "'", TimeUtils.getTime())); - OpenCGAResult insert = clinicalDBAdaptor.insert(study.getUid(), clinicalAnalysis, clinicalAuditList, options); + OpenCGAResult insert = clinicalDBAdaptor.insert(study.getUid(), clinicalAnalysis, study.getVariableSets(), + clinicalAuditList, options); insert.addEvents(events); auditManager.auditCreate(userId, Enums.Resource.CLINICAL_ANALYSIS, clinicalAnalysis.getId(), clinicalAnalysis.getUuid(), @@ -966,7 +977,7 @@ public OpenCGAResult update(String studyStr, Query query, Clin public OpenCGAResult update(String studyStr, Query query, ClinicalAnalysisUpdateParams updateParams, boolean ignoreException, QueryOptions options, String token) throws CatalogException { String userId = userManager.getUserId(token); - Study study = studyManager.resolveId(studyStr, userId, StudyManager.INCLUDE_CONFIGURATION); + Study study = studyManager.resolveId(studyStr, userId, StudyManager.INCLUDE_VARIABLE_SET_AND_CONFIGURATION); String operationId = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); @@ -988,6 +999,7 @@ public OpenCGAResult update(String studyStr, Query query, Clin DBIterator iterator; try { fixQueryObject(study, query, userId, token); + AnnotationUtils.fixQueryOptionAnnotation(options); query.append(ClinicalAnalysisDBAdaptor.QueryParams.STUDY_UID.key(), study.getUid()); iterator = clinicalDBAdaptor.iterator(study.getUid(), query, new QueryOptions(), userId); } catch (CatalogException e) { @@ -1026,7 +1038,7 @@ public OpenCGAResult update(String studyStr, Query query, Clin public OpenCGAResult update(String studyStr, String clinicalId, ClinicalAnalysisUpdateParams updateParams, QueryOptions options, String token) throws CatalogException { String userId = userManager.getUserId(token); - Study study = studyManager.resolveId(studyStr, userId, StudyManager.INCLUDE_CONFIGURATION); + Study study = studyManager.resolveId(studyStr, userId, StudyManager.INCLUDE_VARIABLE_SET_AND_CONFIGURATION); String operationId = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); @@ -1097,7 +1109,7 @@ public OpenCGAResult update(String studyStr, List clin public OpenCGAResult update(String studyStr, List clinicalIds, ClinicalAnalysisUpdateParams updateParams, boolean ignoreException, QueryOptions options, String token) throws CatalogException { String userId = userManager.getUserId(token); - Study study = studyManager.resolveId(studyStr, userId, StudyManager.INCLUDE_CONFIGURATION); + Study study = studyManager.resolveId(studyStr, userId, StudyManager.INCLUDE_VARIABLE_SET_AND_CONFIGURATION); String operationId = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); @@ -1157,6 +1169,25 @@ public OpenCGAResult update(String studyStr, List clin private OpenCGAResult update(Study study, ClinicalAnalysis clinicalAnalysis, ClinicalAnalysisUpdateParams updateParams, String userId, QueryOptions options) throws CatalogException { + ClinicalAnalysisUpdateParams updateParamsClone; + try { + updateParamsClone = JacksonUtils.copy(updateParams, ClinicalAnalysisUpdateParams.class); + } catch (IOException e) { + throw new CatalogException("Could not clone ClinicalAnalysisUpdateParams object"); + } + + ObjectMap parameters; + if (updateParamsClone != null) { + try { + parameters = updateParamsClone.getUpdateMap(); + } catch (JsonProcessingException e) { + throw new CatalogException("Could not parse ClinicalUpdateParams object: " + e.getMessage(), e); + } + } else { + throw new CatalogException("Empty update parameters. Nothing to update."); + } + ParamUtils.checkUpdateParametersMap(parameters); + options = ParamUtils.defaultObject(options, QueryOptions::new); if (study.getInternal() == null || study.getInternal().getConfiguration() == null || study.getInternal().getConfiguration().getClinical() == null) { @@ -1164,10 +1195,30 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } ClinicalAnalysisStudyConfiguration clinicalConfiguration = study.getInternal().getConfiguration().getClinical(); - authorizationManager.checkClinicalAnalysisPermission(study.getUid(), clinicalAnalysis.getUid(), userId, - ClinicalAnalysisPermissions.WRITE); - List events = new LinkedList<>(); + // Check permissions... + // Only check write annotation permissions if the user wants to update the annotation sets + if (updateParamsClone.getAnnotationSets() != null) { + authorizationManager.checkClinicalAnalysisPermission(study.getUid(), clinicalAnalysis.getUid(), userId, + ClinicalAnalysisPermissions.WRITE_ANNOTATIONS); + } + // Only check update permissions if the user wants to update anything apart from the annotation sets + if ((parameters.size() == 1 && !parameters.containsKey(SampleDBAdaptor.QueryParams.ANNOTATION_SETS.key())) + || parameters.size() > 1) { + authorizationManager.checkClinicalAnalysisPermission(study.getUid(), clinicalAnalysis.getUid(), userId, + ClinicalAnalysisPermissions.WRITE); + } + + if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.ANNOTATION_SETS.key())) { + Map actionMap = options.getMap(Constants.ACTIONS, new HashMap<>()); + if (!actionMap.containsKey(AnnotationSetManager.ANNOTATION_SETS) + && !actionMap.containsKey(AnnotationSetManager.ANNOTATIONS)) { + logger.warn("Assuming the user wants to add the list of annotation sets provided"); + actionMap.put(AnnotationSetManager.ANNOTATION_SETS, ParamUtils.BasicUpdateAction.ADD); + options.put(Constants.ACTIONS, actionMap); + } + } + List events = new LinkedList<>(); if (StringUtils.isNotEmpty(clinicalAnalysis.getCreationDate())) { ParamUtils.checkDateFormat(clinicalAnalysis.getCreationDate(), ClinicalAnalysisDBAdaptor.QueryParams.CREATION_DATE.key()); } @@ -1176,29 +1227,17 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli ClinicalAnalysisDBAdaptor.QueryParams.MODIFICATION_DATE.key()); } - ObjectMap parameters; - if (updateParams != null) { - try { - parameters = updateParams.getUpdateMap(); - } catch (JsonProcessingException e) { - throw new CatalogException("Could not parse ClinicalUpdateParams object: " + e.getMessage(), e); - } - } else { - throw new CatalogException("Empty update parameters. Nothing to update."); - } - ParamUtils.checkUpdateParametersMap(parameters); - Map actionMap = options.getMap(Constants.ACTIONS); - if (updateParams.getId() != null) { - ParamUtils.checkIdentifier(updateParams.getId(), ClinicalAnalysisDBAdaptor.QueryParams.ID.key()); + if (updateParamsClone.getId() != null) { + ParamUtils.checkIdentifier(updateParamsClone.getId(), ClinicalAnalysisDBAdaptor.QueryParams.ID.key()); } - if (StringUtils.isNotEmpty(updateParams.getDueDate()) && TimeUtils.toDate(updateParams.getDueDate()) == null) { + if (StringUtils.isNotEmpty(updateParamsClone.getDueDate()) && TimeUtils.toDate(updateParamsClone.getDueDate()) == null) { throw new CatalogException("Unrecognised due date. Accepted format is: yyyyMMddHHmmss"); } - if (updateParams.getComments() != null && !updateParams.getComments().isEmpty()) { - List comments = new ArrayList<>(updateParams.getComments().size()); + if (updateParamsClone.getComments() != null && !updateParamsClone.getComments().isEmpty()) { + List comments = new ArrayList<>(updateParamsClone.getComments().size()); ParamUtils.AddRemoveReplaceAction action = ParamUtils.AddRemoveReplaceAction.from(actionMap, ClinicalAnalysisDBAdaptor.QueryParams.COMMENTS.key(), ParamUtils.AddRemoveReplaceAction.ADD); @@ -1207,7 +1246,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli case ADD: // Ensure each comment has a different milisecond Calendar calendar = Calendar.getInstance(); - for (ClinicalCommentParam comment : updateParams.getComments()) { + for (ClinicalCommentParam comment : updateParamsClone.getComments()) { comments.add(new ClinicalComment(userId, comment.getMessage(), comment.getTags(), TimeUtils.getTimeMillis(calendar.getTime()))); calendar.add(Calendar.MILLISECOND, 1); @@ -1215,7 +1254,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli break; case REMOVE: case REPLACE: - for (ClinicalCommentParam comment : updateParams.getComments()) { + for (ClinicalCommentParam comment : updateParamsClone.getComments()) { if (StringUtils.isEmpty(comment.getDate())) { throw new CatalogException("Missing mandatory 'date' field. This field is mandatory when action is '" + action + "'."); @@ -1231,13 +1270,13 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } if (parameters.get(InterpretationDBAdaptor.QueryParams.ANALYST.key()) != null) { - if (StringUtils.isNotEmpty(updateParams.getAnalyst().getId())) { + if (StringUtils.isNotEmpty(updateParamsClone.getAnalyst().getId())) { QueryOptions userOptions = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.ID.key(), UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key())); // Check user exists - OpenCGAResult userResult = userDBAdaptor.get(updateParams.getAnalyst().getId(), userOptions); + OpenCGAResult userResult = userDBAdaptor.get(updateParamsClone.getAnalyst().getId(), userOptions); if (userResult.getNumResults() == 0) { - throw new CatalogException("User '" + updateParams.getAnalyst().getId() + "' not found"); + throw new CatalogException("User '" + updateParamsClone.getAnalyst().getId() + "' not found"); } parameters.put(InterpretationDBAdaptor.QueryParams.ANALYST.key(), new ClinicalAnalyst(userResult.first().getId(), @@ -1249,7 +1288,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } } if (parameters.get(ClinicalAnalysisDBAdaptor.QueryParams.QUALITY_CONTROL.key()) != null) { - ClinicalAnalysisQualityControl qualityControl = updateParams.getQualityControl().toClinicalQualityControl(); + ClinicalAnalysisQualityControl qualityControl = updateParamsClone.getQualityControl().toClinicalQualityControl(); if (qualityControl.getComments() != null) { for (ClinicalComment comment : qualityControl.getComments()) { comment.setDate(TimeUtils.getTime()); @@ -1259,27 +1298,28 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.QUALITY_CONTROL.key(), qualityControl); } - if (updateParams.getFiles() != null && !updateParams.getFiles().isEmpty()) { - clinicalAnalysis.setFiles(updateParams.getFiles().stream().map(FileReferenceParam::toFile).collect(Collectors.toList())); + if (updateParamsClone.getFiles() != null && !updateParamsClone.getFiles().isEmpty()) { + clinicalAnalysis.setFiles(updateParamsClone.getFiles().stream().map(FileReferenceParam::toFile).collect(Collectors.toList())); // Validate files validateFiles(study, clinicalAnalysis, userId); } - if (CollectionUtils.isNotEmpty(updateParams.getPanels()) && updateParams.getPanelLock() != null && updateParams.getPanelLock()) { + if (CollectionUtils.isNotEmpty(updateParamsClone.getPanels()) && updateParamsClone.getPanelLock() != null + && updateParamsClone.getPanelLock()) { throw new CatalogException("Updating the list of panels and setting 'panelLock' to true at the same time is not allowed."); } - if (CollectionUtils.isNotEmpty(updateParams.getPanels())) { - if (clinicalAnalysis.isPanelLock() && (updateParams.getPanelLock() == null || updateParams.getPanelLock())) { + if (CollectionUtils.isNotEmpty(updateParamsClone.getPanels())) { + if (clinicalAnalysis.isPanelLock() && (updateParamsClone.getPanelLock() == null || updateParamsClone.getPanelLock())) { throw new CatalogException("Cannot update panels from ClinicalAnalysis '" + clinicalAnalysis.getId() + "'. " + "'panelLocked' field from ClinicalAnalysis is set to true."); } // Validate and get panels - List panelIds = updateParams.getPanels().stream().map(PanelReferenceParam::getId).collect(Collectors.toList()); + List panelIds = updateParamsClone.getPanels().stream().map(PanelReferenceParam::getId).collect(Collectors.toList()); Query query = new Query(PanelDBAdaptor.QueryParams.ID.key(), panelIds); - OpenCGAResult panelResult = + OpenCGAResult panelResult = panelDBAdaptor.get(study.getUid(), query, PanelManager.INCLUDE_PANEL_IDS, userId); if (panelResult.getNumResults() < panelIds.size()) { throw new CatalogException("Some panels were not found or user doesn't have permissions to see them."); @@ -1288,7 +1328,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.PANELS.key(), panelResult.getResults()); } - if (updateParams.getPanelLock() != null && updateParams.getPanelLock() && !clinicalAnalysis.isPanelLock()) { + if (updateParamsClone.getPanelLock() != null && updateParamsClone.getPanelLock() && !clinicalAnalysis.isPanelLock()) { // if user wants to set panelLock to true // We need to check if the CA has interpretations. If so, the interpretations should contain at least one of the case panels // in order to set panelLock to true. Otherwise, that action is not allowed. @@ -1323,17 +1363,17 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } } - if (updateParams.getFiles() != null && !updateParams.getFiles().isEmpty()) { + if (updateParamsClone.getFiles() != null && !updateParamsClone.getFiles().isEmpty()) { parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), clinicalAnalysis.getFiles()); } - if (CollectionUtils.isNotEmpty(updateParams.getPanels())) { + if (CollectionUtils.isNotEmpty(updateParamsClone.getPanels())) { // Get panels Query query = new Query(PanelDBAdaptor.QueryParams.ID.key(), - updateParams.getPanels().stream().map(PanelReferenceParam::getId).collect(Collectors.toList())); - OpenCGAResult panelResult = + updateParamsClone.getPanels().stream().map(PanelReferenceParam::getId).collect(Collectors.toList())); + OpenCGAResult panelResult = panelDBAdaptor.get(study.getUid(), query, PanelManager.INCLUDE_PANEL_IDS, userId); - if (panelResult.getNumResults() < updateParams.getPanels().size()) { + if (panelResult.getNumResults() < updateParamsClone.getPanels().size()) { throw new CatalogException("Some panels were not found or user doesn't have permissions to see them"); } @@ -1342,7 +1382,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.DISORDER.key())) { // Assign the disorder to be updated to the clinicalAnalysis obtained from the DB so it can be checked in context - clinicalAnalysis.setDisorder(updateParams.getDisorder().toDisorder()); + clinicalAnalysis.setDisorder(updateParamsClone.getDisorder().toDisorder()); validateDisorder(clinicalAnalysis); // Fill parameter to be updated with complete disorder information parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.DISORDER.key(), clinicalAnalysis.getDisorder()); @@ -1358,7 +1398,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli // Validate user-defined parameters if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.PRIORITY.key())) { - clinicalAnalysis.setPriority(updateParams.getPriority().toClinicalPriorityAnnotation()); + clinicalAnalysis.setPriority(updateParamsClone.getPriority().toClinicalPriorityAnnotation()); validateCustomPriorityParameters(clinicalAnalysis, clinicalConfiguration); parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.PRIORITY.key(), clinicalAnalysis.getPriority()); } @@ -1368,7 +1408,8 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli currentFlags = clinicalAnalysis.getFlags().stream().map(FlagAnnotation::getId).collect(Collectors.toSet()); } - clinicalAnalysis.setFlags(updateParams.getFlags().stream().map(FlagValueParam::toFlagAnnotation).collect(Collectors.toList())); + clinicalAnalysis.setFlags(updateParamsClone.getFlags().stream().map(FlagValueParam::toFlagAnnotation) + .collect(Collectors.toList())); validateCustomFlagParameters(clinicalAnalysis, clinicalConfiguration); ParamUtils.BasicUpdateAction action = ParamUtils.BasicUpdateAction.from(actionMap, @@ -1389,22 +1430,22 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.FLAGS.key(), clinicalAnalysis.getFlags()); } if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.CONSENT.key())) { - clinicalAnalysis.setConsent(updateParams.getConsent().toClinicalConsentAnnotation()); + clinicalAnalysis.setConsent(updateParamsClone.getConsent().toClinicalConsentAnnotation()); validateCustomConsentParameters(clinicalAnalysis, clinicalConfiguration); parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.CONSENT.key(), clinicalAnalysis.getConsent()); } if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.STATUS.key())) { - clinicalAnalysis.setStatus(updateParams.getStatus().toStatus()); + clinicalAnalysis.setStatus(updateParamsClone.getStatus().toStatus()); validateStatusParameter(clinicalAnalysis, clinicalConfiguration); parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.STATUS.key(), clinicalAnalysis.getStatus()); - if (StringUtils.isNotEmpty(updateParams.getStatus().getId())) { + if (StringUtils.isNotEmpty(updateParamsClone.getStatus().getId())) { List clinicalStatusValues = clinicalConfiguration.getStatus().get(clinicalAnalysis.getType()); for (ClinicalStatusValue clinicalStatusValue : clinicalStatusValues) { - if (updateParams.getStatus().getId().equals(clinicalStatusValue.getId())) { + if (updateParamsClone.getStatus().getId().equals(clinicalStatusValue.getId())) { if (clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { String msg = "User '" + userId + "' changed case '" + clinicalAnalysis.getId() + "' to status '" - + updateParams.getStatus().getId() + "', which is of type CLOSED. Automatically locking " + + updateParamsClone.getStatus().getId() + "', which is of type CLOSED. Automatically locking " + "ClinicalAnalysis"; logger.info(msg); parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.LOCKED.key(), true); @@ -1415,9 +1456,11 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } } + checkUpdateAnnotations(study, clinicalAnalysis, parameters, options, VariableSet.AnnotableDataModels.CLINICAL_ANALYSIS, + clinicalDBAdaptor, userId); ClinicalAudit clinicalAudit = new ClinicalAudit(userId, ClinicalAudit.Action.UPDATE_CLINICAL_ANALYSIS, "Update ClinicalAnalysis '" + clinicalAnalysis.getId() + "'", TimeUtils.getTime()); - OpenCGAResult update = clinicalDBAdaptor.update(clinicalAnalysis.getUid(), parameters, + OpenCGAResult update = clinicalDBAdaptor.update(clinicalAnalysis.getUid(), parameters, study.getVariableSets(), Collections.singletonList(clinicalAudit), options); update.addEvents(events); if (options.getBoolean(ParamConstants.INCLUDE_RESULT_PARAM)) { @@ -1494,9 +1537,11 @@ public OpenCGAResult search(String studyId, Query query, Query options = ParamUtils.defaultObject(options, QueryOptions::new); String userId = catalogManager.getUserManager().getUserId(token); - Study study = catalogManager.getStudyManager().resolveId(studyId, userId); + Study study = catalogManager.getStudyManager().resolveId(studyId, userId, StudyManager.INCLUDE_VARIABLE_SET); fixQueryObject(study, query, userId, token); + AnnotationUtils.fixQueryOptionAnnotation(options); + query.append(ClinicalAnalysisDBAdaptor.QueryParams.STUDY_UID.key(), study.getUid()); return clinicalDBAdaptor.get(study.getUid(), query, options, userId); @@ -1507,7 +1552,7 @@ public OpenCGAResult distinct(String studyId, List fields, Query quer query = ParamUtils.defaultObject(query, Query::new); String userId = userManager.getUserId(token); - Study study = catalogManager.getStudyManager().resolveId(studyId, userId); + Study study = catalogManager.getStudyManager().resolveId(studyId, userId, StudyManager.INCLUDE_VARIABLE_SET); ObjectMap auditParams = new ObjectMap() .append("studyId", studyId) @@ -1532,6 +1577,9 @@ public OpenCGAResult distinct(String studyId, List fields, Query quer } protected void fixQueryObject(Study study, Query query, String user, String token) throws CatalogException { + // Fix query if it contains any annotation + AnnotationUtils.fixQueryAnnotationSearch(study, query); + changeQueryId(query, ParamConstants.CLINICAL_DISORDER_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.DISORDER.key()); changeQueryId(query, ParamConstants.CLINICAL_ANALYST_ID_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.ANALYST_ID.key()); changeQueryId(query, ParamConstants.CLINICAL_PRIORITY_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.PRIORITY_ID.key()); @@ -1689,7 +1737,7 @@ protected void fixQueryObject(Study study, Query query, String user, String toke public OpenCGAResult count(String studyId, Query query, String token) throws CatalogException { String userId = catalogManager.getUserManager().getUserId(token); - Study study = catalogManager.getStudyManager().resolveId(studyId, userId); + Study study = catalogManager.getStudyManager().resolveId(studyId, userId, StudyManager.INCLUDE_VARIABLE_SET); ObjectMap auditParams = new ObjectMap() .append("studyId", studyId) @@ -1837,7 +1885,7 @@ public OpenCGAResult delete(String studyStr, Query query, QueryOptions options, OpenCGAResult result = OpenCGAResult.empty(); String userId = catalogManager.getUserManager().getUserId(token); - Study study = catalogManager.getStudyManager().resolveId(studyStr, userId); + Study study = catalogManager.getStudyManager().resolveId(studyStr, userId, StudyManager.INCLUDE_VARIABLE_SET); String operationUuid = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); @@ -1855,6 +1903,7 @@ public OpenCGAResult delete(String studyStr, Query query, QueryOptions options, DBIterator iterator; try { fixQueryObject(study, finalQuery, userId, token); + AnnotationUtils.fixQueryOptionAnnotation(options); finalQuery.append(ClinicalAnalysisDBAdaptor.QueryParams.STUDY_UID.key(), study.getUid()); iterator = clinicalDBAdaptor.iterator(study.getUid(), finalQuery, INCLUDE_CLINICAL_INTERPRETATION_IDS, userId); @@ -1922,9 +1971,10 @@ public OpenCGAResult groupBy(@Nullable String studyStr, Query query, List updateAnnotations(String studyStr, String clinicalStr, String annotationSetId, + Map annotations, ParamUtils.CompleteUpdateAction action, + QueryOptions options, String token) throws CatalogException { + if (annotations == null || annotations.isEmpty()) { + throw new CatalogException("Missing array of annotations."); + } + ClinicalAnalysisUpdateParams clinicalUpdateParams = new ClinicalAnalysisUpdateParams() + .setAnnotationSets(Collections.singletonList(new AnnotationSet(annotationSetId, null, annotations))); + options = ParamUtils.defaultObject(options, QueryOptions::new); + options.put(Constants.ACTIONS, new ObjectMap(AnnotationSetManager.ANNOTATIONS, action)); + + return update(studyStr, clinicalStr, clinicalUpdateParams, options, token); + } + // ************************** ACLs ******************************** // public OpenCGAResult> getAcls( String studyStr, List clinicalList, String member, boolean ignoreException, String token) throws CatalogException { diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/StudyManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/StudyManager.java index e9e48ab01f4..184bbe18b67 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/StudyManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/StudyManager.java @@ -110,9 +110,12 @@ public class StudyManager extends AbstractManager { public static final QueryOptions INCLUDE_STUDY_IDS = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( StudyDBAdaptor.QueryParams.UID.key(), StudyDBAdaptor.QueryParams.ID.key(), StudyDBAdaptor.QueryParams.UUID.key(), StudyDBAdaptor.QueryParams.FQN.key())); - static final QueryOptions INCLUDE_VARIABLE_SET = new QueryOptions(QueryOptions.INCLUDE, StudyDBAdaptor.QueryParams.VARIABLE_SET.key()); - static final QueryOptions INCLUDE_CONFIGURATION = - new QueryOptions(QueryOptions.INCLUDE, StudyDBAdaptor.QueryParams.INTERNAL_CONFIGURATION.key()); + static final QueryOptions INCLUDE_VARIABLE_SET = keepFieldInQueryOptions(INCLUDE_STUDY_IDS, + StudyDBAdaptor.QueryParams.VARIABLE_SET.key()); + static final QueryOptions INCLUDE_CONFIGURATION = keepFieldInQueryOptions(INCLUDE_STUDY_IDS, + StudyDBAdaptor.QueryParams.INTERNAL_CONFIGURATION.key()); + static final QueryOptions INCLUDE_VARIABLE_SET_AND_CONFIGURATION = keepFieldsInQueryOptions(INCLUDE_STUDY_IDS, + Arrays.asList(StudyDBAdaptor.QueryParams.INTERNAL_CONFIGURATION.key(), StudyDBAdaptor.QueryParams.VARIABLE_SET.key())); protected Logger logger; diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java index d29de6b553a..fbce0a4576f 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/AbstractManagerTest.java @@ -49,7 +49,7 @@ import java.util.List; @Category(MediumTests.class) -public class AbstractManagerTest extends GenericTest { +public class AbstractManagerTest extends GenericTest { @Rule public ExpectedException thrown = ExpectedException.none(); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java index d703b598e44..2f78a376527 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java @@ -52,6 +52,7 @@ import org.opencb.opencga.core.models.AclEntryList; import org.opencb.opencga.core.models.AclParams; import org.opencb.opencga.core.models.clinical.*; +import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.FlagAnnotation; import org.opencb.opencga.core.models.common.FlagValue; import org.opencb.opencga.core.models.common.StatusParam; @@ -70,6 +71,8 @@ import org.opencb.opencga.core.models.sample.SamplePermissions; import org.opencb.opencga.core.models.sample.SampleUpdateParams; import org.opencb.opencga.core.models.study.Study; +import org.opencb.opencga.core.models.study.Variable; +import org.opencb.opencga.core.models.study.VariableSet; import org.opencb.opencga.core.models.study.configuration.ClinicalConsent; import org.opencb.opencga.core.models.study.configuration.*; import org.opencb.opencga.core.models.user.Account; @@ -3494,4 +3497,127 @@ public void fetchCasesWithSameProbandAndDifferentSample() throws CatalogExceptio assertEquals(1, result.getResults().get(1).getProband().getSamples().size()); assertEquals(proband.getSamples().get(1).getId(), result.getResults().get(1).getProband().getSamples().get(0).getId()); } + + // Annotation sets + @Test + public void searchByInternalAnnotationSetTest() throws CatalogException { + Set variables = new HashSet<>(); + variables.add(new Variable().setId("a").setType(Variable.VariableType.STRING)); + variables.add(new Variable().setId("b").setType(Variable.VariableType.MAP_INTEGER).setAllowedKeys(Arrays.asList("b1", "b2"))); + VariableSet variableSet = new VariableSet("myInternalVset", "", false, false, true, "", variables, null, 1, null); + catalogManager.getStudyManager().createVariableSet(STUDY, variableSet, sessionIdUser); + + Map annotations = new HashMap<>(); + annotations.put("a", "hello"); + annotations.put("b", new ObjectMap("b1", 2).append("b2", 3)); + AnnotationSet annotationSet = new AnnotationSet("annSet", variableSet.getId(), annotations); + + annotations = new HashMap<>(); + annotations.put("a", "bye"); + annotations.put("b", new ObjectMap("b1", Integer.MAX_VALUE + 1L).append("b2", 5)); + AnnotationSet annotationSet2 = new AnnotationSet("annSet2", variableSet.getId(), annotations); + + DataResult clinicalAnalysisDataResult = createDummyEnvironment(true, true); + ClinicalAnalysis clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(STUDY, clinicalAnalysisDataResult.first().getId(), + new ClinicalAnalysisUpdateParams().setAnnotationSets(Arrays.asList(annotationSet, annotationSet2)), INCLUDE_RESULT, sessionIdUser).first(); + assertEquals(0, clinicalAnalysis.getAnnotationSets().size()); + + // Create a different case with different annotations + annotations = new HashMap<>(); + annotations.put("a", "hi"); + annotations.put("b", new ObjectMap("b1", 12).append("b2", 13)); + annotationSet = new AnnotationSet("annSet", variableSet.getId(), annotations); + + annotations = new HashMap<>(); + annotations.put("a", "goodbye"); + annotations.put("b", new ObjectMap("b1", 14).append("b2", 15)); + annotationSet2 = new AnnotationSet("annSet2", variableSet.getId(), annotations); + + DataResult clinicalAnalysisDataResult2 = createDummyEnvironment(false, true); + ClinicalAnalysis clinicalAnalysis2 = catalogManager.getClinicalAnalysisManager().update(STUDY, clinicalAnalysisDataResult2.first().getId(), + new ClinicalAnalysisUpdateParams().setAnnotationSets(Arrays.asList(annotationSet, annotationSet2)), INCLUDE_RESULT, sessionIdUser).first(); + assertEquals(0, clinicalAnalysis2.getAnnotationSets().size()); + + // Query by one of the annotations + Query query = new Query(Constants.ANNOTATION, "myInternalVset:a=hello"); + assertEquals(1, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + assertEquals(clinicalAnalysis.getId(), catalogManager.getClinicalAnalysisManager().search(STUDY, query, ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, sessionIdUser).first() + .getId()); + + query = new Query(Constants.ANNOTATION, "myInternalVset:b.b1=" + (Integer.MAX_VALUE + 1L)); + assertEquals(1, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + assertEquals(clinicalAnalysis.getId(), catalogManager.getClinicalAnalysisManager().search(STUDY, query, ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, sessionIdUser).first() + .getId()); + + query = new Query(Constants.ANNOTATION, "b.b1=14"); + assertEquals(1, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + assertEquals(clinicalAnalysis2.getId(), catalogManager.getClinicalAnalysisManager().search(STUDY, query, ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, sessionIdUser).first() + .getId()); + + query = new Query(Constants.ANNOTATION, "a=goodbye"); + assertEquals(1, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + assertEquals(clinicalAnalysis2.getId(), catalogManager.getClinicalAnalysisManager().search(STUDY, query, ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, sessionIdUser).first() + .getId()); + + // Update sample annotation to be exactly the same as sample2 + ObjectMap action = new ObjectMap(ClinicalAnalysisDBAdaptor.QueryParams.ANNOTATION_SETS.key(), ParamUtils.BasicUpdateAction.SET); + QueryOptions options = new QueryOptions(Constants.ACTIONS, action); + catalogManager.getClinicalAnalysisManager().update(STUDY, clinicalAnalysis.getId(), + new ClinicalAnalysisUpdateParams().setAnnotationSets(Arrays.asList(annotationSet, annotationSet2)), options, sessionIdUser); + + query = new Query(Constants.ANNOTATION, "myInternalVset:a=hello"); + assertEquals(0, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + + query = new Query(Constants.ANNOTATION, "myInternalVset:b.b1=4"); + assertEquals(0, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + + query = new Query(Constants.ANNOTATION, "b.b1=14"); + assertEquals(2, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + assertTrue(Arrays.asList(clinicalAnalysis.getId(), clinicalAnalysis2.getId()) + .containsAll(catalogManager.getClinicalAnalysisManager().search(STUDY, query, ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, sessionIdUser) + .getResults().stream().map(ClinicalAnalysis::getId).collect(Collectors.toList()))); + + query = new Query(Constants.ANNOTATION, "a=goodbye"); + assertEquals(2, catalogManager.getClinicalAnalysisManager().count(STUDY, query, sessionIdUser).getNumMatches()); + assertTrue(Arrays.asList(clinicalAnalysis.getId(), clinicalAnalysis2.getId()) + .containsAll(catalogManager.getClinicalAnalysisManager().search(STUDY, query, ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, sessionIdUser) + .getResults().stream().map(ClinicalAnalysis::getId).collect(Collectors.toList()))); + } + + @Test + public void testSearchAnnotation() throws CatalogException { + List variables = new ArrayList<>(); + variables.add(new Variable("var_name", "", "", Variable.VariableType.STRING, "", true, false, Collections.emptyList(), null, 0, "", + "", null, Collections.emptyMap())); + variables.add(new Variable("AGE", "", "", Variable.VariableType.INTEGER, "", false, false, Collections.emptyList(), null, 0, "", "", + null, Collections.emptyMap())); + variables.add(new Variable("HEIGHT", "", "", Variable.VariableType.DOUBLE, "", false, false, Collections.emptyList(), null, 0, "", + "", null, Collections.emptyMap())); + variables.add(new Variable("OTHER", "", "", Variable.VariableType.OBJECT, null, false, false, null, null, 1, "", "", null, + Collections.emptyMap())); + VariableSet vs1 = catalogManager.getStudyManager().createVariableSet(STUDY, "vs1", "vs1", false, false, "", null, variables, + Collections.singletonList(VariableSet.AnnotableDataModels.CLINICAL_ANALYSIS), sessionIdUser).first(); + + ObjectMap annotations = new ObjectMap() + .append("var_name", "Joe") + .append("AGE", 25) + .append("HEIGHT", 180); + AnnotationSet annotationSet = new AnnotationSet("annotation1", vs1.getId(), annotations); + + DataResult clinicalAnalysisDataResult = createDummyEnvironment(true, true); + createDummyEnvironment(false, true); + catalogManager.getClinicalAnalysisManager().update(STUDY, clinicalAnalysisDataResult.first().getId(), + new ClinicalAnalysisUpdateParams().setAnnotationSets(Collections.singletonList(annotationSet)), QueryOptions.empty(), + sessionIdUser); + + Query query = new Query(Constants.ANNOTATION, "var_name=Joe;" + vs1.getId() + ":AGE=25"); + DataResult annotDataResult = catalogManager.getClinicalAnalysisManager().search(STUDY, query, + QueryOptions.empty(), sessionIdUser); + assertEquals(1, annotDataResult.getNumResults()); + + query.put(Constants.ANNOTATION, "var_name=Joe;" + vs1.getId() + ":AGE=23"); + annotDataResult = catalogManager.getClinicalAnalysisManager().search(STUDY, query, QueryOptions.empty(), sessionIdUser); + assertEquals(0, annotDataResult.getNumResults()); + } + } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java index 1ba86bb4d1d..55ffc934572 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java @@ -24,7 +24,8 @@ import org.opencb.commons.annotations.DataClass; import org.opencb.commons.annotations.DataField; import org.opencb.opencga.core.api.FieldConstants; -import org.opencb.opencga.core.models.PrivateStudyUid; +import org.opencb.opencga.core.models.common.Annotable; +import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.FlagAnnotation; import org.opencb.opencga.core.models.family.Family; import org.opencb.opencga.core.models.file.File; @@ -41,7 +42,7 @@ */ @DataClass(id = "ClinicalAnalysis", since = "1.0", description = "ClinicalAnalysis data model hosts information about any analysis.") -public class ClinicalAnalysis extends PrivateStudyUid { +public class ClinicalAnalysis extends Annotable { /** * ClinicalAnalysis ID is a mandatory parameter when creating a new ClinicalAnalysis, this ID cannot be changed at the moment. @@ -212,7 +213,7 @@ public ClinicalAnalysis(String id, String description, Type type, Disorder disor ClinicalReport report, ClinicalPriorityAnnotation priority, List flags, String creationDate, String modificationDate, String dueDate, int release, List comments, ClinicalAnalysisQualityControl qualityControl, List audit, ClinicalAnalysisInternal internal, - Map attributes, Status status) { + List annotationSets, Map attributes, Status status) { this.id = id; this.description = description; this.type = type; @@ -238,6 +239,7 @@ public ClinicalAnalysis(String id, String description, Type type, Disorder disor this.comments = comments; this.audit = audit; this.internal = internal; + this.annotationSets = annotationSets; this.attributes = attributes; this.status = status; } @@ -271,6 +273,7 @@ public String toString() { sb.append(", comments=").append(comments); sb.append(", audit=").append(audit); sb.append(", internal=").append(internal); + sb.append(", annotationSets=").append(annotationSets); sb.append(", attributes=").append(attributes); sb.append(", status=").append(status); sb.append('}'); @@ -514,6 +517,12 @@ public ClinicalAnalysis setInternal(ClinicalAnalysisInternal internal) { return this; } + @Override + public ClinicalAnalysis setAnnotationSets(List annotationSets) { + super.setAnnotationSets(annotationSets); + return this; + } + public Map getAttributes() { return attributes; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java index cd0d5243f7b..9d91754d5be 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java @@ -18,6 +18,7 @@ import org.opencb.biodata.models.clinical.ClinicalAnalyst; import org.opencb.opencga.core.common.TimeUtils; +import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.StatusParam; import org.opencb.opencga.core.models.family.Family; import org.opencb.opencga.core.models.file.File; @@ -61,6 +62,7 @@ public class ClinicalAnalysisCreateParams { private PriorityParam priority; private List flags; + private List annotationSets; private Map attributes; private StatusParam status; @@ -74,7 +76,8 @@ public ClinicalAnalysisCreateParams(String id, String description, ClinicalAnaly ClinicalConsentAnnotationParam consent, String creationDate, String modificationDate, String dueDate, List comments, ClinicalAnalysisQualityControlUpdateParam qualityControl, PriorityParam priority, - List flags, Map attributes, StatusParam status) { + List flags, List annotationSets, Map attributes, + StatusParam status) { this.id = id; this.description = description; this.type = type; @@ -95,6 +98,7 @@ public ClinicalAnalysisCreateParams(String id, String description, ClinicalAnaly this.qualityControl = qualityControl; this.priority = priority; this.flags = flags; + this.annotationSets = annotationSets; this.attributes = attributes; this.status = status; } @@ -128,6 +132,7 @@ public static ClinicalAnalysisCreateParams of(ClinicalAnalysis clinicalAnalysis) clinicalAnalysis.getFlags() != null ? clinicalAnalysis.getFlags().stream().map(FlagValueParam::of).collect(Collectors.toList()) : null, + clinicalAnalysis.getAnnotationSets(), clinicalAnalysis.getAttributes(), StatusParam.of(clinicalAnalysis.getStatus())); } @@ -154,6 +159,7 @@ public String toString() { sb.append(", comments=").append(comments); sb.append(", priority=").append(priority); sb.append(", flags=").append(flags); + sb.append(", annotationSets=").append(annotationSets); sb.append(", attributes=").append(attributes); sb.append(", status=").append(status); sb.append('}'); @@ -216,7 +222,7 @@ public ClinicalAnalysis toClinicalAnalysis() { flags != null ? flags.stream().map(FlagValueParam::toFlagAnnotation).collect(Collectors.toList()) : null, creationDate, modificationDate, dueDate, 1, comments != null ? comments.stream().map(ClinicalCommentParam::toClinicalComment).collect(Collectors.toList()) : null, qualityControl != null ? qualityControl.toClinicalQualityControl() : null, new LinkedList<>(), null, - attributes, status != null ? status.toStatus() : null); + annotationSets, attributes, status != null ? status.toStatus() : null); } public String getId() { @@ -399,6 +405,15 @@ public ClinicalAnalysisCreateParams setFlags(List flags) { return this; } + public List getAnnotationSets() { + return annotationSets; + } + + public ClinicalAnalysisCreateParams setAnnotationSets(List annotationSets) { + this.annotationSets = annotationSets; + return this; + } + public Map getAttributes() { return attributes; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisPermissions.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisPermissions.java index af45797dbf2..e0cdfadd0c0 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisPermissions.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisPermissions.java @@ -6,7 +6,10 @@ public enum ClinicalAnalysisPermissions { NONE(Collections.emptyList()), VIEW(Collections.emptyList()), WRITE(Collections.singletonList(VIEW)), - DELETE(Arrays.asList(VIEW, WRITE)); + DELETE(Arrays.asList(VIEW, WRITE)), + VIEW_ANNOTATIONS(Collections.singletonList(VIEW)), + WRITE_ANNOTATIONS(Arrays.asList(VIEW_ANNOTATIONS, VIEW)), + DELETE_ANNOTATIONS(Arrays.asList(VIEW_ANNOTATIONS, WRITE_ANNOTATIONS, VIEW)); private final List implicitPermissions; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java index a30f469e7a6..1cec037fb1c 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.core.JsonProcessingException; import org.opencb.commons.datastore.core.ObjectMap; +import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.StatusParam; import org.opencb.opencga.core.models.file.FileReferenceParam; import org.opencb.opencga.core.models.panel.Panel; @@ -62,6 +63,7 @@ public class ClinicalAnalysisUpdateParams { private PriorityParam priority; // id private List flags; // id + private List annotationSets; private Map attributes; private StatusParam status; @@ -74,7 +76,8 @@ public ClinicalAnalysisUpdateParams(String id, String description, ClinicalAnaly ClinicalReport report, ClinicalAnalysisQualityControlUpdateParam qualityControl, ClinicalConsentAnnotationParam consent, String creationDate, String modificationDate, String dueDate, List comments, PriorityParam priority, - List flags, Map attributes, StatusParam status) { + List flags, List annotationSets, Map attributes, + StatusParam status) { this.id = id; this.description = description; this.type = type; @@ -95,6 +98,7 @@ public ClinicalAnalysisUpdateParams(String id, String description, ClinicalAnaly this.comments = comments; this.priority = priority; this.flags = flags; + this.annotationSets = annotationSets; this.attributes = attributes; this.status = status; } @@ -120,7 +124,8 @@ public ClinicalAnalysis toClinicalAnalysis() { flags != null ? flags.stream().map(FlagValueParam::toFlagAnnotation).collect(Collectors.toList()) : null, creationDate, modificationDate, dueDate, 1, comments != null ? comments.stream().map(ClinicalCommentParam::toClinicalComment).collect(Collectors.toList()) : null, - qualityControl != null ? qualityControl.toClinicalQualityControl() : null, null, null, attributes, status != null ? status.toStatus() : null); + qualityControl != null ? qualityControl.toClinicalQualityControl() : null, null, null, annotationSets, attributes, + status != null ? status.toStatus() : null); } @Override @@ -146,6 +151,7 @@ public String toString() { sb.append(", comments=").append(comments); sb.append(", priority=").append(priority); sb.append(", flags=").append(flags); + sb.append(", annotationSets=").append(annotationSets); sb.append(", attributes=").append(attributes); sb.append(", status=").append(status); sb.append('}'); @@ -323,6 +329,15 @@ public ClinicalAnalysisUpdateParams setFlags(List flags) { return this; } + public List getAnnotationSets() { + return annotationSets; + } + + public ClinicalAnalysisUpdateParams setAnnotationSets(List annotationSets) { + this.annotationSets = annotationSets; + return this; + } + public Map getAttributes() { return attributes; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/StudyPermissions.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/StudyPermissions.java index 3eefb1a5c63..059af8182ab 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/StudyPermissions.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/StudyPermissions.java @@ -103,7 +103,13 @@ public enum Permissions { WRITE_CLINICAL_ANALYSIS(Collections.singletonList(VIEW_CLINICAL_ANALYSIS), ClinicalAnalysisPermissions.WRITE.name(), CLINICAL_ANALYSIS), DELETE_CLINICAL_ANALYSIS(Arrays.asList(VIEW_CLINICAL_ANALYSIS, WRITE_CLINICAL_ANALYSIS), - ClinicalAnalysisPermissions.DELETE.name(), CLINICAL_ANALYSIS); + ClinicalAnalysisPermissions.DELETE.name(), CLINICAL_ANALYSIS), + VIEW_CLINICAL_ANNOTATIONS(Collections.singletonList(VIEW_CLINICAL_ANALYSIS), ClinicalAnalysisPermissions.VIEW_ANNOTATIONS.name(), + CLINICAL_ANALYSIS), + WRITE_CLINICAL_ANNOTATIONS(Arrays.asList(VIEW_CLINICAL_ANALYSIS, VIEW_CLINICAL_ANNOTATIONS), + ClinicalAnalysisPermissions.WRITE_ANNOTATIONS.name(), CLINICAL_ANALYSIS), + DELETE_CLINICAL_ANNOTATIONS(Arrays.asList(VIEW_CLINICAL_ANALYSIS, VIEW_CLINICAL_ANNOTATIONS, WRITE_CLINICAL_ANNOTATIONS), + ClinicalAnalysisPermissions.DELETE_ANNOTATIONS.name(), CLINICAL_ANALYSIS); private final static Map map; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/VariableSet.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/VariableSet.java index 7ffdb8a460c..c2ac1f3ba43 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/VariableSet.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/VariableSet.java @@ -45,7 +45,8 @@ public enum AnnotableDataModels { COHORT, INDIVIDUAL, FAMILY, - FILE + FILE, + CLINICAL_ANALYSIS } public VariableSet() { diff --git a/opencga-master/src/main/java/org/opencb/opencga/master/monitor/daemons/ExecutionDaemon.java b/opencga-master/src/main/java/org/opencb/opencga/master/monitor/daemons/ExecutionDaemon.java index e7920c53303..b014cce49ec 100644 --- a/opencga-master/src/main/java/org/opencb/opencga/master/monitor/daemons/ExecutionDaemon.java +++ b/opencga-master/src/main/java/org/opencb/opencga/master/monitor/daemons/ExecutionDaemon.java @@ -26,6 +26,7 @@ import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryOptions; +import org.opencb.opencga.analysis.clinical.ClinicalTsvAnnotationLoader; import org.opencb.opencga.analysis.clinical.exomiser.ExomiserInterpretationAnalysis; import org.opencb.opencga.analysis.clinical.rga.AuxiliarRgaAnalysis; import org.opencb.opencga.analysis.clinical.rga.RgaAnalysis; @@ -242,6 +243,7 @@ public class ExecutionDaemon extends MonitorParentDaemon { put(RgaAnalysis.ID, "clinical " + RgaAnalysis.ID + "-run"); put(AuxiliarRgaAnalysis.ID, "clinical " + AuxiliarRgaAnalysis.ID + "-run"); + put(ClinicalTsvAnnotationLoader.ID, "clinical tsv-load"); put(JulieTool.ID, "variant julie-run"); diff --git a/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java b/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java index 7906588ad23..5c33dd532b2 100644 --- a/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java +++ b/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java @@ -21,6 +21,7 @@ import org.opencb.biodata.models.clinical.interpretation.ClinicalVariant; import org.opencb.commons.datastore.core.*; import org.opencb.opencga.analysis.clinical.ClinicalInterpretationManager; +import org.opencb.opencga.analysis.clinical.ClinicalTsvAnnotationLoader; import org.opencb.opencga.analysis.clinical.exomiser.ExomiserInterpretationAnalysis; import org.opencb.opencga.analysis.clinical.rga.AuxiliarRgaAnalysis; import org.opencb.opencga.analysis.clinical.rga.RgaAnalysis; @@ -43,7 +44,9 @@ import org.opencb.opencga.core.models.AclParams; import org.opencb.opencga.core.models.analysis.knockout.*; import org.opencb.opencga.core.models.clinical.*; +import org.opencb.opencga.core.models.common.TsvAnnotationParams; import org.opencb.opencga.core.models.job.Job; +import org.opencb.opencga.core.models.sample.Sample; import org.opencb.opencga.core.models.study.configuration.ClinicalAnalysisStudyConfiguration; import org.opencb.opencga.core.tools.annotations.*; @@ -212,9 +215,14 @@ public Response update( @QueryParam("filesAction") ParamUtils.BasicUpdateAction filesAction, @ApiParam(value = "Action to be performed if the array of panels is being updated.", allowableValues = "ADD,SET,REMOVE", defaultValue = "ADD") @QueryParam("panelsAction") ParamUtils.BasicUpdateAction panelsAction, + @ApiParam(value = "Action to be performed if the array of annotationSets is being updated.", allowableValues = "ADD,SET,REMOVE", defaultValue = "ADD") + @QueryParam("annotationSetsAction") ParamUtils.BasicUpdateAction annotationSetsAction, @ApiParam(value = ParamConstants.INCLUDE_RESULT_DESCRIPTION, defaultValue = "false") @QueryParam(ParamConstants.INCLUDE_RESULT_PARAM) boolean includeResult, @ApiParam(name = "body", value = "JSON containing clinical analysis information", required = true) ClinicalAnalysisUpdateParams params) { try { + if (annotationSetsAction == null) { + annotationSetsAction = ParamUtils.BasicUpdateAction.ADD; + } if (commentsAction == null) { commentsAction = ParamUtils.AddRemoveReplaceAction.ADD; } @@ -229,6 +237,7 @@ public Response update( } Map actionMap = new HashMap<>(); + actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.ANNOTATION_SETS.key(), annotationSetsAction); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.COMMENTS.key(), commentsAction); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.FLAGS.key(), flagsAction); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), filesAction); @@ -241,6 +250,55 @@ public Response update( } } + @POST + @Path("/annotationSets/load") + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Load annotation sets from a TSV file", response = Job.class) + public Response loadTsvAnnotations( + @ApiParam(value = ParamConstants.STUDY_DESCRIPTION) @QueryParam(ParamConstants.STUDY_PARAM) String studyStr, + @ApiParam(value = ParamConstants.VARIABLE_SET_DESCRIPTION, required = true) @QueryParam("variableSetId") String variableSetId, + @ApiParam(value = "Path where the TSV file is located in OpenCGA or where it should be located.", required = true) + @QueryParam("path") String path, + @ApiParam(value = "Flag indicating whether to create parent directories if they don't exist (only when TSV file was not " + + "previously associated).") + @DefaultValue("false") @QueryParam("parents") boolean parents, + @ApiParam(value = "Annotation set id. If not provided, variableSetId will be used.") @QueryParam("annotationSetId") String annotationSetId, + @ApiParam(value = ParamConstants.TSV_ANNOTATION_DESCRIPTION) TsvAnnotationParams params) { + try { + ObjectMap additionalParams = new ObjectMap() + .append("parents", parents) + .append("annotationSetId", annotationSetId); + + return createOkResponse(catalogManager.getClinicalAnalysisManager().loadTsvAnnotations(studyStr, variableSetId, path, params, + additionalParams, ClinicalTsvAnnotationLoader.ID, token)); + } catch (Exception e) { + return createErrorResponse(e); + } + } + + @POST + @Path("/{clinicalAnalysis}/annotationSets/{annotationSet}/annotations/update") + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Update annotations from an annotationSet", response = Sample.class) + public Response updateAnnotations( + @ApiParam(value = "Clinical analysis ID") @PathParam("clinicalAnalysis") String clinicalId, + @ApiParam(value = ParamConstants.STUDY_DESCRIPTION) @QueryParam(ParamConstants.STUDY_PARAM) String studyStr, + @ApiParam(value = ParamConstants.ANNOTATION_SET_ID) @PathParam("annotationSet") String annotationSetId, + @ApiParam(value = ParamConstants.ANNOTATION_SET_UPDATE_ACTION_DESCRIPTION, allowableValues = "ADD,SET,REMOVE,RESET,REPLACE", + defaultValue = "ADD") + @QueryParam("action") ParamUtils.CompleteUpdateAction action, + @ApiParam(value = ParamConstants.ANNOTATION_SET_UPDATE_PARAMS_DESCRIPTION) Map updateParams) { + try { + if (action == null) { + action = ParamUtils.CompleteUpdateAction.ADD; + } + return createOkResponse(catalogManager.getClinicalAnalysisManager().updateAnnotations(studyStr, clinicalId, annotationSetId, + updateParams, action, queryOptions, token)); + } catch (Exception e) { + return createErrorResponse(e); + } + } + @DELETE @Path("/{clinicalAnalyses}/delete") @ApiOperation(value = "Delete clinical analyses", response = ClinicalAnalysis.class) @@ -263,7 +321,9 @@ public Response delete( @ApiImplicitParam(name = QueryOptions.INCLUDE, value = ParamConstants.INCLUDE_DESCRIPTION, example = "name,attributes", dataType = "string", paramType = "query"), @ApiImplicitParam(name = QueryOptions.EXCLUDE, value = ParamConstants.EXCLUDE_DESCRIPTION, - example = "id,status", dataType = "string", paramType = "query") + example = "id,status", dataType = "string", paramType = "query"), + @ApiImplicitParam(name = ParamConstants.FLATTEN_ANNOTATIONS, value = "Flatten the annotations?", defaultValue = "false", + dataType = "boolean", paramType = "query") }) public Response info( @ApiParam(value = ParamConstants.CLINICAL_ANALYSES_DESCRIPTION) @PathParam(value = "clinicalAnalysis") String clinicalAnalysisStr, @@ -289,7 +349,9 @@ public Response info( @ApiImplicitParam(name = QueryOptions.EXCLUDE, value = ParamConstants.EXCLUDE_DESCRIPTION, example = "id,status", dataType = "string", paramType = "query"), @ApiImplicitParam(name = QueryOptions.LIMIT, value = ParamConstants.LIMIT_DESCRIPTION, dataType = "integer", paramType = "query"), @ApiImplicitParam(name = QueryOptions.SKIP, value = ParamConstants.SKIP_DESCRIPTION, dataType = "integer", paramType = "query"), - @ApiImplicitParam(name = QueryOptions.COUNT, value = ParamConstants.COUNT_DESCRIPTION, defaultValue = "false", dataType = "boolean", paramType = "query") + @ApiImplicitParam(name = QueryOptions.COUNT, value = ParamConstants.COUNT_DESCRIPTION, defaultValue = "false", dataType = "boolean", paramType = "query"), + @ApiImplicitParam(name = ParamConstants.FLATTEN_ANNOTATIONS, value = "Flatten the annotations?", defaultValue = "false", + dataType = "boolean", paramType = "query") }) public Response search( @ApiParam(value = ParamConstants.STUDY_DESCRIPTION) @QueryParam(ParamConstants.STUDY_PARAM) String studyStr, @@ -317,6 +379,7 @@ public Response search( @ApiParam(value = ParamConstants.CLINICAL_RELEASE_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_RELEASE_PARAM) String release, @ApiParam(value = ParamConstants.CLINICAL_STATUS_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_STATUS_PARAM) String status, @ApiParam(value = ParamConstants.CLINICAL_INTERNAL_STATUS_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_INTERNAL_STATUS_PARAM) String internalStatus, + @ApiParam(value = ParamConstants.ANNOTATION_DESCRIPTION) @QueryParam(Constants.ANNOTATION) String annotation, @ApiParam(value = ParamConstants.DELETED_DESCRIPTION) @QueryParam(ParamConstants.DELETED_PARAM) boolean deleted) { try { query.remove(ParamConstants.STUDY_PARAM); @@ -356,6 +419,7 @@ public Response distinct( @ApiParam(value = ParamConstants.CLINICAL_RELEASE_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_RELEASE_PARAM) String release, @ApiParam(value = ParamConstants.CLINICAL_STATUS_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_STATUS_PARAM) String status, @ApiParam(value = ParamConstants.CLINICAL_INTERNAL_STATUS_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_INTERNAL_STATUS_PARAM) String internalStatus, + @ApiParam(value = ParamConstants.ANNOTATION_DESCRIPTION) @QueryParam(Constants.ANNOTATION) String annotation, @ApiParam(value = ParamConstants.DELETED_DESCRIPTION) @QueryParam(ParamConstants.DELETED_PARAM) boolean deleted, @ApiParam(value = ParamConstants.DISTINCT_FIELD_DESCRIPTION, required = true) @QueryParam(ParamConstants.DISTINCT_FIELD_PARAM) String field) { try { From 6b9c5ecb7a6749721c01d2793ae81bb1c76b4c63 Mon Sep 17 00:00:00 2001 From: pfurio Date: Thu, 16 Nov 2023 16:32:28 +0100 Subject: [PATCH 2/7] app: add annotationset migration for cases, #TASK-5198 --- .../AddAnnotationSetsInClinicalAnalysis.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java new file mode 100644 index 00000000000..d61a6cb8a09 --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java @@ -0,0 +1,41 @@ +package org.opencb.opencga.app.migrations.v2_12_0.catalog; + + +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.AnnotationMongoDBAdaptor; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Arrays; +import java.util.Collections; + +@Migration(id = "add_annotation_sets_to_clinical_analysis" , + description = "Add private annotation fields to ClinicalAnalysis documents", + version = "2.12.0", + domain = Migration.MigrationDomain.CATALOG, + language = Migration.MigrationLanguage.JAVA, + date = 20231116 +) +public class AddAnnotationSetsInClinicalAnalysis extends MigrationTool { + + @Override + protected void run() throws Exception { + Bson query = Filters.exists(AnnotationMongoDBAdaptor.AnnotationSetParams.ANNOTATION_SETS.key(), false); + Document update = new Document("$set", new Document() + .append(AnnotationMongoDBAdaptor.AnnotationSetParams.ANNOTATION_SETS.key(), Collections.emptyList()) + .append(AnnotationMongoDBAdaptor.AnnotationSetParams.INTERNAL_ANNOTATION_SETS.key(), Collections.emptyList()) + .append(AnnotationMongoDBAdaptor.AnnotationSetParams.PRIVATE_VARIABLE_SET_MAP.key(), Collections.emptyMap()) + .append(AnnotationMongoDBAdaptor.AnnotationSetParams.PRIVATE_INTERNAL_VARIABLE_SET_MAP.key(), Collections.emptyMap()) + ); + // Initialise private fields in all Clinical Analysis documents + for (String collection : Arrays.asList(MongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, + MongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION)) { + MongoCollection mongoCollection = getMongoCollection(collection); + mongoCollection.updateMany(query, update); + } + } +} From 31fdc712bf118f620334dbd2fa364ebfb9ef5e5d Mon Sep 17 00:00:00 2001 From: pfurio Date: Fri, 17 Nov 2023 11:01:49 +0100 Subject: [PATCH 3/7] app: log the documents updated, #TASK-5198 --- .../v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java index d61a6cb8a09..018b0cc28e7 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java @@ -3,6 +3,7 @@ import com.mongodb.client.MongoCollection; import com.mongodb.client.model.Filters; +import com.mongodb.client.result.UpdateResult; import org.bson.Document; import org.bson.conversions.Bson; import org.opencb.opencga.catalog.db.mongodb.AnnotationMongoDBAdaptor; @@ -35,7 +36,8 @@ protected void run() throws Exception { for (String collection : Arrays.asList(MongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, MongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION)) { MongoCollection mongoCollection = getMongoCollection(collection); - mongoCollection.updateMany(query, update); + UpdateResult updateResult = mongoCollection.updateMany(query, update); + logger.info("{} clinical analysis documents updated from the {} collection", updateResult.getModifiedCount(), collection); } } } From e1ca92f2670ab71cfb6a70fa1368e1a6ba8b0bce Mon Sep 17 00:00:00 2001 From: pfurio Date: Tue, 28 Nov 2023 17:00:40 +0100 Subject: [PATCH 4/7] catalog: add new fields to Clinical report, #TASK-5198 --- ...ationSetsInClinicalAnalysisMigration.java} | 4 +- ...pleteClinicalReportDataModelMigration.java | 32 ++ .../db/api/ClinicalAnalysisDBAdaptor.java | 58 +++- .../ClinicalAnalysisMongoDBAdaptor.java | 42 ++- .../db/mongodb/StudyMongoDBAdaptor.java | 7 + .../converters/ClinicalAnalysisConverter.java | 47 ++- .../managers/ClinicalAnalysisManager.java | 306 +++++++++++++++--- .../opencga/catalog/managers/FileUtils.java | 3 + .../managers/ClinicalAnalysisManagerTest.java | 201 +++++++++++- .../opencga/core/api/FieldConstants.java | 7 +- .../models/clinical/ClinicalAnalysis.java | 58 +++- .../ClinicalAnalysisCreateParams.java | 66 +++- ...icalAnalysisQualityControlUpdateParam.java | 19 ++ .../ClinicalAnalysisUpdateParams.java | 48 ++- .../core/models/clinical/ClinicalReport.java | 52 ++- .../core/models/clinical/ClinicalRequest.java | 80 +++++ .../models/clinical/ClinicalResponsible.java | 115 +++++++ .../opencb/opencga/core/models/file/File.java | 1 + .../rest/analysis/ClinicalWebService.java | 6 + 19 files changed, 1032 insertions(+), 120 deletions(-) rename opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/{AddAnnotationSetsInClinicalAnalysis.java => AddAnnotationSetsInClinicalAnalysisMigration.java} (95%) create mode 100644 opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java create mode 100644 opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalRequest.java create mode 100644 opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalResponsible.java diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysisMigration.java similarity index 95% rename from opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java rename to opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysisMigration.java index 018b0cc28e7..0ab4fceb81a 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysis.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/AddAnnotationSetsInClinicalAnalysisMigration.java @@ -15,13 +15,13 @@ import java.util.Collections; @Migration(id = "add_annotation_sets_to_clinical_analysis" , - description = "Add private annotation fields to ClinicalAnalysis documents", + description = "Add private annotation fields to ClinicalAnalysis documents #TASK-5198", version = "2.12.0", domain = Migration.MigrationDomain.CATALOG, language = Migration.MigrationLanguage.JAVA, date = 20231116 ) -public class AddAnnotationSetsInClinicalAnalysis extends MigrationTool { +public class AddAnnotationSetsInClinicalAnalysisMigration extends MigrationTool { @Override protected void run() throws Exception { diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java new file mode 100644 index 00000000000..b4fa490c90a --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java @@ -0,0 +1,32 @@ +package org.opencb.opencga.app.migrations.v2_12_0.catalog; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Arrays; +import java.util.Collections; + +@Migration(id = "complete_clinical_report_data_model" , + description = "Complete Clinical Report data model #TASK-5198", + version = "2.12.0", + domain = Migration.MigrationDomain.CATALOG, + language = Migration.MigrationLanguage.JAVA, + date = 20231128 +) +public class CompleteClinicalReportDataModelMigration extends MigrationTool { + + @Override + protected void run() throws Exception { + migrateCollection( + Arrays.asList(MongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, MongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION), + Filters.exists("analyst"), + Projections.include(Collections.singletonList("analyst")), + (document, bulk) -> { + + }); + } + +} diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java index ac30c48e9d2..a4b3d8f19b4 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/ClinicalAnalysisDBAdaptor.java @@ -69,10 +69,14 @@ enum QueryParams implements QueryParam { CONSENT("consent", OBJECT, ""), PRIORITY("priority", OBJECT, ""), PRIORITY_ID("priority.id", TEXT, ""), - ANALYST("analyst", TEXT_ARRAY, ""), - ANALYST_ID("analyst.id", TEXT, ""), - ANALYST_ASSIGNED_BY("analyst.assignedBy", TEXT, ""), + ANALYSTS("analysts", TEXT_ARRAY, ""), + ANALYSTS_ID("analysts.id", TEXT, ""), + ANALYSTS_ASSIGNED_BY("analysts.assignedBy", TEXT, ""), REPORT("report", OBJECT, ""), + REPORT_SUPPORTING_EVIDENCES("report.supportingEvidences", TEXT_ARRAY, ""), + REPORT_FILES("report.files", TEXT_ARRAY, ""), + REQUEST("request", OBJECT, ""), + RESPONSIBLE("responsible", OBJECT, ""), FLAGS("flags", OBJECT, ""), FLAGS_ID("flags.id", TEXT, ""), RELEASE("release", INTEGER, ""), @@ -160,6 +164,54 @@ public static QueryParams getParam(String key) { } } + enum ReportQueryParams implements QueryParam { + COMMENTS("comments", OBJECT, ""), + SUPPORTING_EVIDENCES("supportingEvidences", TEXT_ARRAY, ""), + FILES("files", TEXT_ARRAY, ""); + + private static Map map; + + static { + map = new LinkedMap(); + for (ReportQueryParams params : ReportQueryParams.values()) { + map.put(params.key(), params); + } + } + + private final String key; + private Type type; + private String description; + + ReportQueryParams(String key, Type type, String description) { + this.key = key; + this.type = type; + this.description = description; + } + + @Override + public String key() { + return key; + } + + @Override + public Type type() { + return type; + } + + @Override + public String description() { + return description; + } + + public static Map getMap() { + return map; + } + + public static ReportQueryParams getParam(String key) { + return map.get(key); + } + } + default boolean exists(long clinicalAnalysisId) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { return count(new Query(QueryParams.UID.key(), clinicalAnalysisId)).getNumMatches() > 0; } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java index 67f9a035aa0..996a7eaac48 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/ClinicalAnalysisMongoDBAdaptor.java @@ -25,6 +25,7 @@ import org.apache.commons.lang3.time.StopWatch; import org.bson.Document; import org.bson.conversions.Bson; +import org.opencb.biodata.models.clinical.ClinicalAnalyst; import org.opencb.biodata.models.clinical.ClinicalAudit; import org.opencb.biodata.models.clinical.ClinicalComment; import org.opencb.commons.datastore.core.*; @@ -155,6 +156,20 @@ static void fixFilesForRemoval(ObjectMap parameters) { parameters.put(FILES.key(), fileParamList); } + static void fixAnalystsForRemoval(ObjectMap parameters) { + if (parameters.get(ANALYSTS.key()) == null) { + return; + } + + List analystParamList = new LinkedList<>(); + for (Object analyst : parameters.getAsList(ANALYSTS.key())) { + if (analyst instanceof ClinicalAnalyst) { + analystParamList.add(new Document("id", ((ClinicalAnalyst) analyst).getId())); + } + } + parameters.put(ANALYSTS.key(), analystParamList); + } + @Override public OpenCGAResult getAnnotationSet(long id, @Nullable String annotationSetName) throws CatalogDBException, CatalogParameterException, CatalogAuthorizationException { @@ -382,8 +397,8 @@ UpdateDocument parseAndValidateUpdateParams(ObjectMap parameters, List actionMap = queryOptions.getMap(Constants.ACTIONS, new HashMap<>()); @@ -420,8 +436,26 @@ UpdateDocument parseAndValidateUpdateParams(ObjectMap parameters, List variableSetList) { + Document document = super.convertToStorageType(clinicalAnalysis, variableSetList); document.put(ClinicalAnalysisDBAdaptor.QueryParams.UID.key(), clinicalAnalysis.getUid()); document.put(ClinicalAnalysisDBAdaptor.QueryParams.STUDY_UID.key(), clinicalAnalysis.getStudyUid()); @@ -56,6 +55,24 @@ public void validateDocumentToUpdate(Document document) { validateProbandToUpdate(document); validatePanelsToUpdate(document); validateFilesToUpdate(document); + validateReportToUpdate(document); + } + + public void validateReportToUpdate(Document document) { + Document report = document.get(ClinicalAnalysisDBAdaptor.QueryParams.REPORT.key(), Document.class); + if (report != null) { + List files = report.getList(ClinicalAnalysisDBAdaptor.ReportQueryParams.SUPPORTING_EVIDENCES.key(), Document.class); + if (CollectionUtils.isNotEmpty(files)) { + List filteredFiles = getReducedFileDocuments(files); + report.put(ClinicalAnalysisDBAdaptor.ReportQueryParams.SUPPORTING_EVIDENCES.key(), filteredFiles); + } + + files = report.getList(ClinicalAnalysisDBAdaptor.ReportQueryParams.FILES.key(), Document.class); + if (CollectionUtils.isNotEmpty(files)) { + List filteredFiles = getReducedFileDocuments(files); + report.put(ClinicalAnalysisDBAdaptor.ReportQueryParams.FILES.key(), filteredFiles); + } + } } public void validateInterpretationToUpdate(Document document) { @@ -141,6 +158,11 @@ public void validatePanelsToUpdate(Document document) { public void validateFilesToUpdate(Document document) { List files = (List) document.get(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key()); + List reducedFiles = getReducedFileDocuments(files); + document.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), reducedFiles); + } + + private static List getReducedFileDocuments(List files) { if (files != null) { // We make sure we don't store duplicates Map fileMap = new HashMap<>(); @@ -154,12 +176,13 @@ public void validateFilesToUpdate(Document document) { } } - document.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), - fileMap.entrySet().stream() - .map(entry -> new Document() - .append(FileDBAdaptor.QueryParams.PATH.key(), entry.getValue().getPath()) - .append(FileDBAdaptor.QueryParams.UID.key(), entry.getValue().getUid())) - .collect(Collectors.toList())); + return fileMap.values().stream() + .map(file -> new Document() + .append(FileDBAdaptor.QueryParams.PATH.key(), file.getPath()) + .append(FileDBAdaptor.QueryParams.UID.key(), file.getUid())) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java index 63a0ca46dd6..069a8e25d4e 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java @@ -37,10 +37,7 @@ import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.exceptions.CatalogParameterException; import org.opencb.opencga.catalog.models.InternalGetDataResult; -import org.opencb.opencga.catalog.utils.AnnotationUtils; -import org.opencb.opencga.catalog.utils.Constants; -import org.opencb.opencga.catalog.utils.ParamUtils; -import org.opencb.opencga.catalog.utils.UuidUtils; +import org.opencb.opencga.catalog.utils.*; import org.opencb.opencga.core.api.ParamConstants; import org.opencb.opencga.core.common.JacksonUtils; import org.opencb.opencga.core.common.TimeUtils; @@ -268,6 +265,25 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis ClinicalAnalysisQualityControl::new)); clinicalAnalysis.setPanels(ParamUtils.defaultObject(clinicalAnalysis.getPanels(), Collections.emptyList())); clinicalAnalysis.setAnnotationSets(ParamUtils.defaultObject(clinicalAnalysis.getAnnotationSets(), Collections.emptyList())); + clinicalAnalysis.setResponsible(ParamUtils.defaultObject(clinicalAnalysis.getResponsible(), ClinicalResponsible::new)); + clinicalAnalysis.setRequest(ParamUtils.defaultObject(clinicalAnalysis.getRequest(), ClinicalRequest::new)); + + // ---------- Check and init report fields + validateAndInitReport(study, clinicalAnalysis.getReport(), userId); + + // ---------- Check and init responsible fields + ClinicalResponsible responsible = clinicalAnalysis.getResponsible(); + if (StringUtils.isEmpty(responsible.getId())) { + responsible.setId(userId); + } + fillResponsible(responsible); + + // ---------- Check and init request fields + ClinicalRequest request = clinicalAnalysis.getRequest(); + if (StringUtils.isNotEmpty(request.getId())) { + request.setDate(ParamUtils.checkDateOrGetCurrentDate(request.getDate(), "request.date")); + fillResponsible(request.getResponsible()); + } if (clinicalAnalysis.getQualityControl().getComments() != null) { for (ClinicalComment comment : clinicalAnalysis.getQualityControl().getComments()) { @@ -301,20 +317,29 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis } // Analyst + List userList; QueryOptions userInclude = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.ID.key(), UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key())); - User user; - if (clinicalAnalysis.getAnalyst() == null || StringUtils.isEmpty(clinicalAnalysis.getAnalyst().getId())) { - user = userDBAdaptor.get(userId, userInclude).first(); + if (clinicalAnalysis.getAnalysts() == null) { + userList = userDBAdaptor.get(userId, userInclude).getResults(); } else { - // Validate user - OpenCGAResult result = userDBAdaptor.get(clinicalAnalysis.getAnalyst().getId(), userInclude); - if (result.getNumResults() == 0) { - throw new CatalogException("User '" + clinicalAnalysis.getAnalyst().getId() + "' not found"); + // Validate users + Set userIds = new HashSet<>(); + for (ClinicalAnalyst analyst : clinicalAnalysis.getAnalysts()) { + userIds.add(analyst.getId()); + } + Query query = new Query(UserDBAdaptor.QueryParams.ID.key(), userIds); + OpenCGAResult result = userDBAdaptor.get(query, userInclude); + if (result.getNumResults() < userIds.size()) { + throw new CatalogException("Some clinical analysts could not be found."); } - user = result.first(); + userList = result.getResults(); } - clinicalAnalysis.setAnalyst(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, TimeUtils.getTime())); + List clinicalAnalystList = new ArrayList<>(userList.size()); + for (User user : userList) { + clinicalAnalystList.add(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, TimeUtils.getTime())); + } + clinicalAnalysis.setAnalysts(clinicalAnalystList); if (TimeUtils.toDate(clinicalAnalysis.getDueDate()) == null) { throw new CatalogException("Unrecognised due date. Accepted format is: yyyyMMddHHmmss"); @@ -511,10 +536,17 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis } } } + List files = obtainFiles(study, clinicalAnalysis, userId); if (clinicalAnalysis.getFiles() != null && !clinicalAnalysis.getFiles().isEmpty()) { - validateFiles(study, clinicalAnalysis, userId); + Set fileIds = clinicalAnalysis.getFiles().stream().map(File::getId).collect(Collectors.toSet()); + String notFoundFiles = files.stream().map(File::getId).filter(f -> !fileIds.contains(f)).collect(Collectors.joining(", ")); + if (StringUtils.isNotEmpty(notFoundFiles)) { + throw new CatalogException("Files '" + notFoundFiles + "' not found or do not belong to any participant."); + } + List filteredFiles = files.stream().filter(f -> fileIds.contains(f.getId())).collect(Collectors.toList()); + clinicalAnalysis.setFiles(filteredFiles); } else { - obtainFiles(study, clinicalAnalysis, userId); + clinicalAnalysis.setFiles(files); } clinicalAnalysis.setCreationDate(ParamUtils.checkDateOrGetCurrentDate(clinicalAnalysis.getCreationDate(), @@ -593,6 +625,43 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis } } + private void validateAndInitReport(Study study, ClinicalReport report, String userId) throws CatalogException { + if (report == null) { + return; + } + if (StringUtils.isNotEmpty(report.getTitle()) || StringUtils.isNotEmpty(report.getOverview())) { + report.setDate(ParamUtils.checkDateOrGetCurrentDate(report.getDate(), "report.date")); + } + if (report.getComments() != null) { + for (ClinicalComment comment : report.getComments()) { + comment.setDate(TimeUtils.getTime()); + comment.setAuthor(userId); + } + } + if (CollectionUtils.isNotEmpty(report.getFiles())) { + List files = obtainFiles(study, userId, report.getFiles()); + report.setFiles(files); + } + if (CollectionUtils.isNotEmpty(report.getSupportingEvidences())) { + List files = obtainFiles(study, userId, report.getSupportingEvidences()); + report.setSupportingEvidences(files); + } + } + + private void fillResponsible(ClinicalResponsible responsible) throws CatalogException { + if (responsible == null) { + return; + } + QueryOptions userInclude = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.ID.key(), + UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key())); + OpenCGAResult result = userDBAdaptor.get(responsible.getId(), userInclude); + if (result.getNumResults() == 0) { + throw new CatalogException("Responsible user '" + responsible.getId() + "' not found."); + } + responsible.setName(ParamUtils.defaultString(responsible.getName(), result.first().getName())); + responsible.setEmail(ParamUtils.defaultString(responsible.getEmail(), result.first().getEmail())); + } + private void validateStatusParameter(ClinicalAnalysis clinicalAnalysis, ClinicalAnalysisStudyConfiguration clinicalConfiguration) throws CatalogException { // Status @@ -758,7 +827,7 @@ private void validateDisorder(ClinicalAnalysis clinicalAnalysis) throws CatalogE } } - private void obtainFiles(Study study, ClinicalAnalysis clinicalAnalysis, String userId) throws CatalogException { + private List obtainFiles(Study study, ClinicalAnalysis clinicalAnalysis, String userId) throws CatalogException { Set sampleSet = new HashSet<>(); if (clinicalAnalysis.getFamily() != null && clinicalAnalysis.getFamily().getMembers() != null) { for (Individual member : clinicalAnalysis.getFamily().getMembers()) { @@ -783,8 +852,18 @@ private void obtainFiles(Study study, ClinicalAnalysis clinicalAnalysis, String .append(FileDBAdaptor.QueryParams.SAMPLE_IDS.key(), new ArrayList<>(sampleSet)) .append(FileDBAdaptor.QueryParams.BIOFORMAT.key(), Arrays.asList(File.Bioformat.ALIGNMENT, File.Bioformat.VARIANT)); OpenCGAResult fileResults = fileDBAdaptor.get(study.getUid(), query, FileManager.INCLUDE_FILE_URI_PATH, userId); - clinicalAnalysis.setFiles(fileResults.getResults()); + return fileResults.getResults(); } + return Collections.emptyList(); + } + + private List obtainFiles(Study study, String userId, List files) throws CatalogException { + Query query = new Query(FileDBAdaptor.QueryParams.ID.key(), files.stream().map(File::getId).collect(Collectors.toSet())); + List results = fileDBAdaptor.get(study.getUid(), query, FileManager.INCLUDE_FILE_URI_PATH, userId).getResults(); + if (results.size() < files.size()) { + throw new CatalogException("Some of the files were not found"); + } + return results; } private void validateFiles(Study study, ClinicalAnalysis clinicalAnalysis, String userId) throws CatalogException { @@ -855,6 +934,103 @@ private void validateFiles(Study study, ClinicalAnalysis clinicalAnalysis, Strin // } } +// private void obtainFiles(Study study, ClinicalAnalysis clinicalAnalysis, String userId) throws CatalogException { +// Set sampleSet = new HashSet<>(); +// if (clinicalAnalysis.getFamily() != null && clinicalAnalysis.getFamily().getMembers() != null) { +// for (Individual member : clinicalAnalysis.getFamily().getMembers()) { +// if (member.getSamples() != null) { +// for (Sample sample : member.getSamples()) { +// sampleSet.add(sample.getId()); +// } +// } +// } +// } else if (clinicalAnalysis.getProband() != null && clinicalAnalysis.getProband().getSamples() != null) { +// for (Sample sample : clinicalAnalysis.getProband().getSamples()) { +// sampleSet.add(sample.getId()); +// } +// } +// +// if (clinicalAnalysis.getFiles() != null && !clinicalAnalysis.getFiles().isEmpty()) { +// throw new CatalogException("Cannot obtain map of files if this is already provided"); +// } +// +// if (!sampleSet.isEmpty()) { +// Query query = new Query() +// .append(FileDBAdaptor.QueryParams.SAMPLE_IDS.key(), new ArrayList<>(sampleSet)) +// .append(FileDBAdaptor.QueryParams.BIOFORMAT.key(), Arrays.asList(File.Bioformat.ALIGNMENT, File.Bioformat.VARIANT)); +// OpenCGAResult fileResults = fileDBAdaptor.get(study.getUid(), query, FileManager.INCLUDE_FILE_URI_PATH, userId); +// clinicalAnalysis.setFiles(fileResults.getResults()); +// } +// } + +// private void validateFiles(Study study, ClinicalAnalysis clinicalAnalysis, String userId) throws CatalogException { +// Map sampleMap = new HashMap<>(); +// if (clinicalAnalysis.getFamily() != null && clinicalAnalysis.getFamily().getMembers() != null) { +// for (Individual member : clinicalAnalysis.getFamily().getMembers()) { +// if (member.getSamples() != null) { +// for (Sample sample : member.getSamples()) { +// sampleMap.put(sample.getId(), sample.getUid()); +// } +// } +// } +// } else if (clinicalAnalysis.getProband() != null && clinicalAnalysis.getProband().getSamples() != null) { +// for (Sample sample : clinicalAnalysis.getProband().getSamples()) { +// sampleMap.put(sample.getId(), sample.getUid()); +// } +// } +// +// if (clinicalAnalysis.getFiles() == null || clinicalAnalysis.getFiles().isEmpty()) { +// throw new CatalogException("Found empty map of files"); +// } +// +// // Look for all the samples associated to the files +// Query query = new Query(FileDBAdaptor.QueryParams.ID.key(), +// clinicalAnalysis.getFiles().stream().map(File::getId).collect(Collectors.toList())); +// QueryOptions fileOptions = keepFieldInQueryOptions(FileManager.INCLUDE_FILE_URI_PATH, FileDBAdaptor.QueryParams.SAMPLE_IDS.key()); +// OpenCGAResult fileResults = fileDBAdaptor.get(study.getUid(), query, fileOptions, userId); +// +// if (fileResults.getNumResults() != clinicalAnalysis.getFiles().size()) { +// Set fileIds = clinicalAnalysis.getFiles().stream().map(File::getId).collect(Collectors.toSet()); +// String notFoundFiles = fileResults.getResults().stream().map(File::getId).filter(f -> !fileIds.contains(f)) +// .collect(Collectors.joining(", ")); +// throw new CatalogException("Files '" + notFoundFiles + "' not found"); +// } +// +// // Complete file information +// clinicalAnalysis.setFiles(fileResults.getResults()); +// +// // Validate the file ids passed are related to the samples +// for (File file : clinicalAnalysis.getFiles()) { +// if (CollectionUtils.isNotEmpty(file.getSampleIds())) { +// boolean found = false; +// for (String sampleId : file.getSampleIds()) { +// if (sampleMap.containsKey(sampleId)) { +// found = true; +// break; +// } +// } +// if (!found) { +// throw new CatalogException("Clinical analysis file (" + file.getId() + ") contains sample ids not related to any " +// + "member/proband"); +// } +// } +// } +// +//// for (File caFile : clinicalAnalysis.getFiles()) { +//// List fileIds = caFile.getFiles().stream().map(File::getId).collect(Collectors.toList()); +//// InternalGetDataResult fileResult = catalogManager.getFileManager().internalGet(study.getUid(), fileIds, new Query(), +//// new QueryOptions(), userId, false); +//// // Validate sample id belongs to files +//// for (File file : fileResult.getResults()) { +//// if (!file.getSamples().stream().map(Sample::getUid).collect(Collectors.toSet()) +//// .contains(sampleMap.get(caFile.getSampleId()))) { +//// throw new CatalogException("Associated file '" + file.getPath() + "' seems not to be related to sample '" +//// + caFile.getSampleId() + "'."); +//// } +//// } +//// } +// } + private Family getFullValidatedFamily(Family family, Study study, String sessionId) throws CatalogException { if (family == null) { return null; @@ -1175,16 +1351,30 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } catch (IOException e) { throw new CatalogException("Could not clone ClinicalAnalysisUpdateParams object"); } + if (updateParamsClone == null) { + throw new CatalogException("Empty update parameters. Nothing to update."); + } + + validateAndInitReport(study, updateParamsClone.getReport(), userId); + + // ---------- Check and init responsible fields + ClinicalResponsible responsible = updateParamsClone.getResponsible(); + if (responsible != null && StringUtils.isNotEmpty(responsible.getId())) { + fillResponsible(responsible); + } + + // ---------- Check and init request fields + ClinicalRequest request = updateParamsClone.getRequest(); + if (request != null && StringUtils.isNotEmpty(request.getId())) { + request.setDate(ParamUtils.checkDateOrGetCurrentDate(request.getDate(), "request.date")); + fillResponsible(request.getResponsible()); + } ObjectMap parameters; - if (updateParamsClone != null) { - try { - parameters = updateParamsClone.getUpdateMap(); - } catch (JsonProcessingException e) { - throw new CatalogException("Could not parse ClinicalUpdateParams object: " + e.getMessage(), e); - } - } else { - throw new CatalogException("Empty update parameters. Nothing to update."); + try { + parameters = updateParamsClone.getUpdateMap(); + } catch (JsonProcessingException e) { + throw new CatalogException("Could not parse ClinicalUpdateParams object: " + e.getMessage(), e); } ParamUtils.checkUpdateParametersMap(parameters); @@ -1269,22 +1459,44 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.COMMENTS.key(), comments); } - if (parameters.get(InterpretationDBAdaptor.QueryParams.ANALYST.key()) != null) { - if (StringUtils.isNotEmpty(updateParamsClone.getAnalyst().getId())) { - QueryOptions userOptions = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.ID.key(), - UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key())); - // Check user exists - OpenCGAResult userResult = userDBAdaptor.get(updateParamsClone.getAnalyst().getId(), userOptions); - if (userResult.getNumResults() == 0) { - throw new CatalogException("User '" + updateParamsClone.getAnalyst().getId() + "' not found"); - } + if (parameters.get(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key()) != null) { + ParamUtils.BasicUpdateAction action = ParamUtils.BasicUpdateAction.from(actionMap, + ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), ParamUtils.BasicUpdateAction.ADD); + List analystList = updateParamsClone.getAnalysts(); + switch (action) { + case ADD: + case SET: + QueryOptions userOptions = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.ID.key(), + UserDBAdaptor.QueryParams.NAME.key(), UserDBAdaptor.QueryParams.EMAIL.key())); - parameters.put(InterpretationDBAdaptor.QueryParams.ANALYST.key(), new ClinicalAnalyst(userResult.first().getId(), - userResult.first().getName(), userResult.first().getEmail(), userId, TimeUtils.getTime())); - } else { - // Remove assignee - parameters.put(InterpretationDBAdaptor.QueryParams.ANALYST.key(), new ClinicalAnalyst("", "", "", userId, - TimeUtils.getTime())); + Set analystIdList = new HashSet<>(); + for (ClinicalAnalystParam clinicalAnalystParam : analystList) { + analystIdList.add(clinicalAnalystParam.getId()); + } + + List clinicalAnalystList = new ArrayList<>(analystIdList.size()); + // Check analysts exist + if (!analystIdList.isEmpty()) { + Query query = new Query(UserDBAdaptor.QueryParams.ID.key(), analystIdList); + OpenCGAResult userResult = userDBAdaptor.get(query, userOptions); + if (userResult.getNumResults() < analystIdList.size()) { + throw new CatalogException("Some analysts were not found."); + } + for (User user : userResult.getResults()) { + clinicalAnalystList.add(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, + TimeUtils.getTime())); + } + } + parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), clinicalAnalystList); + break; + case REMOVE: + // Directly add those analysts. No need to check + List analysts = analystList.stream().map(ClinicalAnalystParam::toClinicalAnalyst) + .collect(Collectors.toList()); + parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), analysts); + break; + default: + throw new IllegalStateException("Unknown analysts action " + action); } } if (parameters.get(ClinicalAnalysisDBAdaptor.QueryParams.QUALITY_CONTROL.key()) != null) { @@ -1298,11 +1510,19 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.QUALITY_CONTROL.key(), qualityControl); } + if (updateParamsClone.getReport() != null && CollectionUtils.isNotEmpty(updateParamsClone.getReport().getFiles())) { + parameters.putNested(ClinicalAnalysisDBAdaptor.QueryParams.REPORT_FILES.key(), updateParamsClone.getReport().getFiles(), false); + } + if (updateParamsClone.getReport() != null && CollectionUtils.isNotEmpty(updateParamsClone.getReport().getSupportingEvidences())) { + parameters.putNested(ClinicalAnalysisDBAdaptor.QueryParams.REPORT_SUPPORTING_EVIDENCES.key(), + updateParamsClone.getReport().getSupportingEvidences(), false); + } if (updateParamsClone.getFiles() != null && !updateParamsClone.getFiles().isEmpty()) { clinicalAnalysis.setFiles(updateParamsClone.getFiles().stream().map(FileReferenceParam::toFile).collect(Collectors.toList())); // Validate files validateFiles(study, clinicalAnalysis, userId); + parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), clinicalAnalysis.getFiles()); } if (CollectionUtils.isNotEmpty(updateParamsClone.getPanels()) && updateParamsClone.getPanelLock() != null @@ -1363,10 +1583,6 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } } - if (updateParamsClone.getFiles() != null && !updateParamsClone.getFiles().isEmpty()) { - parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), clinicalAnalysis.getFiles()); - } - if (CollectionUtils.isNotEmpty(updateParamsClone.getPanels())) { // Get panels Query query = new Query(PanelDBAdaptor.QueryParams.ID.key(), @@ -1581,7 +1797,7 @@ protected void fixQueryObject(Study study, Query query, String user, String toke AnnotationUtils.fixQueryAnnotationSearch(study, query); changeQueryId(query, ParamConstants.CLINICAL_DISORDER_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.DISORDER.key()); - changeQueryId(query, ParamConstants.CLINICAL_ANALYST_ID_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.ANALYST_ID.key()); + changeQueryId(query, ParamConstants.CLINICAL_ANALYST_ID_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS_ID.key()); changeQueryId(query, ParamConstants.CLINICAL_PRIORITY_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.PRIORITY_ID.key()); changeQueryId(query, ParamConstants.CLINICAL_FLAGS_PARAM, ClinicalAnalysisDBAdaptor.QueryParams.FLAGS_ID.key()); changeQueryId(query, ParamConstants.CLINICAL_QUALITY_CONTROL_SUMMARY_PARAM, diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileUtils.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileUtils.java index 46423ef9a2f..02f5cae855b 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileUtils.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileUtils.java @@ -261,6 +261,7 @@ public static File.Bioformat detectBioformat(URI uri, File.Format format, File.C case BINARY: case UNKNOWN: case XML: + case PDF: return File.Bioformat.NONE; default: break; @@ -398,6 +399,8 @@ public static File.Format detectFormat(URI uri) { case "jpeg": case "tif": return File.Format.IMAGE; + case "pdf": + return File.Format.PDF; default: break; } diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java index 2f78a376527..400c85e23af 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java @@ -24,10 +24,7 @@ import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.ExpectedException; -import org.opencb.biodata.models.clinical.ClinicalAudit; -import org.opencb.biodata.models.clinical.ClinicalComment; -import org.opencb.biodata.models.clinical.ClinicalDiscussion; -import org.opencb.biodata.models.clinical.Disorder; +import org.opencb.biodata.models.clinical.*; import org.opencb.biodata.models.clinical.interpretation.ClinicalVariant; import org.opencb.biodata.models.clinical.interpretation.ClinicalVariantEvidence; import org.opencb.biodata.models.clinical.interpretation.InterpretationMethod; @@ -59,10 +56,7 @@ import org.opencb.opencga.core.models.family.Family; import org.opencb.opencga.core.models.family.FamilyPermissions; import org.opencb.opencga.core.models.family.FamilyUpdateParams; -import org.opencb.opencga.core.models.file.File; -import org.opencb.opencga.core.models.file.FileLinkParams; -import org.opencb.opencga.core.models.file.FileReferenceParam; -import org.opencb.opencga.core.models.file.FileUpdateParams; +import org.opencb.opencga.core.models.file.*; import org.opencb.opencga.core.models.individual.Individual; import org.opencb.opencga.core.models.individual.IndividualPermissions; import org.opencb.opencga.core.models.panel.Panel; @@ -76,6 +70,7 @@ import org.opencb.opencga.core.models.study.configuration.ClinicalConsent; import org.opencb.opencga.core.models.study.configuration.*; import org.opencb.opencga.core.models.user.Account; +import org.opencb.opencga.core.models.user.User; import org.opencb.opencga.core.response.OpenCGAResult; import org.opencb.opencga.core.testclassification.duration.MediumTests; @@ -292,6 +287,196 @@ public void createMultipleCasesSameFamily() throws CatalogException { } } + @Test + public void updateClinicalAnalystsTest() throws CatalogException { + ClinicalAnalysis case1 = createDummyEnvironment(true, true).first(); + + catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); + catalogManager.getUserManager().create(new User().setId("u2").setName("u2").setAccount(new Account()), TestParamConstants.PASSWORD, opencgaToken); + + // Add analysts + OpenCGAResult result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setAnalysts( + Arrays.asList(new ClinicalAnalystParam("u1"), new ClinicalAnalystParam("u2"))), INCLUDE_RESULT, sessionIdUser); + assertEquals(3, result.first().getAnalysts().size()); + assertTrue(result.first().getAnalysts().stream().map(ClinicalAnalyst::getId).collect(Collectors.toSet()).containsAll(Arrays.asList("u1", "u2"))); + + // Check analyst params + for (ClinicalAnalyst analyst : result.first().getAnalysts()) { + assertNotNull(analyst.getId()); + assertNotNull(analyst.getName()); + assertNotNull(analyst.getDate()); + assertEquals("user", analyst.getAssignedBy()); + } + + // Remove analysts + Map actionMap = new HashMap<>(); + actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), ParamUtils.BasicUpdateAction.REMOVE); + QueryOptions options = new QueryOptions() + .append(Constants.ACTIONS, actionMap) + .append(ParamConstants.INCLUDE_RESULT_PARAM, true); + result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setAnalysts( + Arrays.asList(new ClinicalAnalystParam("u1"), new ClinicalAnalystParam("u2"))), options, sessionIdUser); + assertEquals(1, result.first().getAnalysts().size()); + assertTrue(result.first().getAnalysts().stream().map(ClinicalAnalyst::getId).noneMatch(x -> Arrays.asList("u1", "u2").contains(x))); + + // Set analysts + actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), ParamUtils.BasicUpdateAction.SET); + options = new QueryOptions() + .append(Constants.ACTIONS, actionMap) + .append(ParamConstants.INCLUDE_RESULT_PARAM, true); + result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setAnalysts( + Arrays.asList(new ClinicalAnalystParam("u1"), new ClinicalAnalystParam("u2"))), options, sessionIdUser); + assertEquals(2, result.first().getAnalysts().size()); + assertTrue(result.first().getAnalysts().stream().map(ClinicalAnalyst::getId).allMatch(x -> Arrays.asList("u1", "u2").contains(x))); + + thrown.expect(CatalogException.class); + thrown.expectMessage("not found"); + catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setAnalysts( + Arrays.asList(new ClinicalAnalystParam("unknown"), new ClinicalAnalystParam("u2"))), options, sessionIdUser); + } + + @Test + public void updateClinicalAnalysisRequest() throws CatalogException { + ClinicalAnalysis case1 = createDummyEnvironment(true, true).first(); + assertTrue(StringUtils.isEmpty(case1.getRequest().getId())); + + catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setEmail("mail@mail.com").setAccount(new Account()), + TestParamConstants.PASSWORD, opencgaToken); + + ClinicalRequest request = new ClinicalRequest("requestId", "bla", null, new ClinicalResponsible().setId("u1"), new HashMap<>()); + + // Change request + OpenCGAResult result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setRequest(request), INCLUDE_RESULT, sessionIdUser); + assertNotNull(result.first().getRequest()); + assertTrue(StringUtils.isNotEmpty(result.first().getRequest().getDate())); + assertEquals("requestId", result.first().getRequest().getId()); + assertEquals("u1", result.first().getRequest().getResponsible().getId()); + assertEquals("u1", result.first().getRequest().getResponsible().getName()); + assertEquals("mail@mail.com", result.first().getRequest().getResponsible().getEmail()); + + // Remove request responsible + request.setResponsible(null); + result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setRequest(request), INCLUDE_RESULT, sessionIdUser); + assertNotNull(result.first().getRequest()); + assertTrue(StringUtils.isNotEmpty(result.first().getRequest().getDate())); + assertEquals("requestId", result.first().getRequest().getId()); + assertNull(result.first().getRequest().getResponsible()); + + // Add non existing request responsible user id + request.setResponsible(new ClinicalResponsible().setId("unknown")); + thrown.expect(CatalogException.class); + thrown.expectMessage("not found"); + catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setRequest(request), INCLUDE_RESULT, sessionIdUser); + } + + @Test + public void updateClinicalAnalysisResponsible() throws CatalogException { + ClinicalAnalysis case1 = createDummyEnvironment(true, true).first(); + assertEquals("user", case1.getResponsible().getId()); + + catalogManager.getUserManager().create(new User().setId("u1").setName("u1").setEmail("mail@mail.com").setAccount(new Account()), + TestParamConstants.PASSWORD, opencgaToken); + + ClinicalResponsible responsible = new ClinicalResponsible().setId("u1"); + + // Change responsible + OpenCGAResult result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setResponsible(responsible), INCLUDE_RESULT, sessionIdUser); + assertNotNull(result.first().getResponsible()); + assertEquals("u1", result.first().getResponsible().getId()); + assertEquals("u1", result.first().getResponsible().getName()); + assertEquals("mail@mail.com", result.first().getResponsible().getEmail()); + + // Change to non existing request responsible user id + responsible.setId("unknown"); + thrown.expect(CatalogException.class); + thrown.expectMessage("not found"); + catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setResponsible(responsible), INCLUDE_RESULT, sessionIdUser); + } + + @Test + public void updateClinicalAnalysisReport() throws CatalogException { + ClinicalAnalysis case1 = createDummyEnvironment(true, true).first(); + assertNull(case1.getReport()); + + ClinicalReport report = new ClinicalReport() + .setTitle("my report") + .setComments(Arrays.asList(new ClinicalComment("author", "msg", null, null), new ClinicalComment("author2", "msg", null, null))); + + // Change report + OpenCGAResult result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setReport(report), INCLUDE_RESULT, sessionIdUser); + assertNotNull(result.first().getReport()); + assertEquals(report.getTitle(), result.first().getReport().getTitle()); + assertEquals(2, result.first().getReport().getComments().size()); + for (ClinicalComment comment : result.first().getReport().getComments()) { + assertEquals("user", comment.getAuthor()); + assertTrue(StringUtils.isNotEmpty(comment.getDate())); + } + + // Add files + catalogManager.getFileManager().create(STUDY, + new FileCreateParams() + .setContent(RandomStringUtils.randomAlphanumeric(1000)) + .setPath("/data/file1.txt") + .setType(File.Type.FILE), + true, sessionIdUser); + catalogManager.getFileManager().create(STUDY, + new FileCreateParams() + .setContent(RandomStringUtils.randomAlphanumeric(1000)) + .setPath("/data/file2.txt") + .setType(File.Type.FILE), + true, sessionIdUser); + + List fileList = Arrays.asList(new File().setId("data:file1.txt"), new File().setId("data:file2.txt")); + report.setSupportingEvidences(fileList); + result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setReport(report), INCLUDE_RESULT, sessionIdUser); + assertNotNull(result.first().getReport()); + assertEquals(report.getTitle(), result.first().getReport().getTitle()); + assertEquals(2, result.first().getReport().getComments().size()); + for (ClinicalComment comment : result.first().getReport().getComments()) { + assertEquals("user", comment.getAuthor()); + assertTrue(StringUtils.isNotEmpty(comment.getDate())); + } + assertEquals(2, result.first().getReport().getSupportingEvidences().size()); + assertEquals("data/file1.txt", result.first().getReport().getSupportingEvidences().get(0).getPath()); + assertEquals("data/file2.txt", result.first().getReport().getSupportingEvidences().get(1).getPath()); + assertNull(result.first().getReport().getFiles()); + + report.setFiles(fileList); + result = catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setReport(report), INCLUDE_RESULT, sessionIdUser); + assertNotNull(result.first().getReport()); + assertEquals(report.getTitle(), result.first().getReport().getTitle()); + assertEquals(2, result.first().getReport().getComments().size()); + for (ClinicalComment comment : result.first().getReport().getComments()) { + assertEquals("user", comment.getAuthor()); + assertTrue(StringUtils.isNotEmpty(comment.getDate())); + } + assertEquals(2, result.first().getReport().getSupportingEvidences().size()); + assertEquals("data/file1.txt", result.first().getReport().getSupportingEvidences().get(0).getPath()); + assertEquals("data/file2.txt", result.first().getReport().getSupportingEvidences().get(1).getPath()); + assertEquals(2, result.first().getReport().getFiles().size()); + assertEquals("data/file1.txt", result.first().getReport().getFiles().get(0).getPath()); + assertEquals("data/file2.txt", result.first().getReport().getFiles().get(1).getPath()); + + // Provide non existing file + report.setFiles(Collections.singletonList(new File().setId("nonexisting.txt"))); + thrown.expect(CatalogException.class); + thrown.expectMessage("not found"); + catalogManager.getClinicalAnalysisManager().update(STUDY, case1.getId(), + new ClinicalAnalysisUpdateParams().setReport(report), INCLUDE_RESULT, sessionIdUser); + } + @Test public void createAndUpdateClinicalAnalysisWithQualityControl() throws CatalogException, InterruptedException { Individual individual = new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2"))); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java b/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java index 4cccaaae80b..36fce194f36 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/api/FieldConstants.java @@ -187,8 +187,10 @@ public class FieldConstants { public static final String CLINICAL_ANALYSIS_INTERPRETATION = "Interpretation of the clinical analysis."; public static final String CLINICAL_ANALYSIS_SECONDARY_INTERPRETATION = "List of Interpretations containing the second and consecutive."; public static final String CLINICAL_ANALYSIS_CONSENT = "Object contains consent annotations of clinical analysis."; - public static final String CLINICAL_ANALYSIS_ANALYST = "The analyst of the clinical analysis."; + public static final String CLINICAL_ANALYSIS_ANALYST = "The analysts of the clinical analysis."; public static final String CLINICAL_ANALYSIS_REPORT = "Report of the clinical analysis."; + public static final String CLINICAL_ANALYSIS_REQUEST = "Request of the clinical analysis."; + public static final String CLINICAL_ANALYSIS_RESPONSIBLE = "Responsible of the clinical analysis."; public static final String CLINICAL_ANALYSIS_PRIORITY = "Priority of the clinical analysis."; public static final String CLINICAL_ANALYSIS_FLAGS = "List of flags for the clinical analysis."; public static final String CLINICAL_ANALYSIS_DUE_DATE_DESCRIPTION = "Due date of the clinical analysis."; @@ -212,6 +214,9 @@ public class FieldConstants { public static final String CLINICAL_REPORT_SIGNED_BY = "Indicates who has signed the report."; public static final String CLINICAL_REPORT_SIGNATURE = "Report signature."; public static final String CLINICAL_REPORT_DATE = "Report date."; + public static final String CLINICAL_REPORT_COMMENTS = "Report comments."; + public static final String CLINICAL_REPORT_SUPPORTING_EVIDENCES = "Report supporting evidences."; + public static final String CLINICAL_REPORT_FILES = "Report files."; //ClinicalPriorityAnnotation public static final String CLINICAL_PRIORITY_ANNOTATION_RANK_DESCRIPTION = "ClinicalPriorityAnnotation rank."; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java index 55ffc934572..1c9ffd04027 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysis.java @@ -117,14 +117,22 @@ public class ClinicalAnalysis extends Annotable { description = FieldConstants.CLINICAL_ANALYSIS_CONSENT) private ClinicalConsentAnnotation consent; - @DataField(id = "analyst", indexed = true, + @DataField(id = "analysts", indexed = true, description = FieldConstants.CLINICAL_ANALYSIS_ANALYST) - private ClinicalAnalyst analyst; + private List analysts; @DataField(id = "report", indexed = true, description = FieldConstants.CLINICAL_ANALYSIS_REPORT) private ClinicalReport report; + @DataField(id = "request", since = "2.12.0", + description = FieldConstants.CLINICAL_ANALYSIS_REPORT) + private ClinicalRequest request; + + @DataField(id = "responsible", since = "2.12.0", + description = FieldConstants.CLINICAL_ANALYSIS_RESPONSIBLE) + private ClinicalResponsible responsible; + @DataField(id = "priority", indexed = true, description = FieldConstants.CLINICAL_ANALYSIS_PRIORITY) private ClinicalPriorityAnnotation priority; @@ -209,11 +217,12 @@ public ClinicalAnalysis() { public ClinicalAnalysis(String id, String description, Type type, Disorder disorder, List files, Individual proband, Family family, List panels, boolean panelLock, boolean locked, Interpretation interpretation, - List secondaryInterpretations, ClinicalConsentAnnotation consent, ClinicalAnalyst analyst, - ClinicalReport report, ClinicalPriorityAnnotation priority, List flags, String creationDate, - String modificationDate, String dueDate, int release, List comments, - ClinicalAnalysisQualityControl qualityControl, List audit, ClinicalAnalysisInternal internal, - List annotationSets, Map attributes, Status status) { + List secondaryInterpretations, ClinicalConsentAnnotation consent, + List analysts, ClinicalReport report, ClinicalRequest request, ClinicalResponsible responsible, + ClinicalPriorityAnnotation priority, List flags, String creationDate, String modificationDate, + String dueDate, int release, List comments, ClinicalAnalysisQualityControl qualityControl, + List audit, ClinicalAnalysisInternal internal, List annotationSets, + Map attributes, Status status) { this.id = id; this.description = description; this.type = type; @@ -227,8 +236,10 @@ public ClinicalAnalysis(String id, String description, Type type, Disorder disor this.interpretation = interpretation; this.secondaryInterpretations = secondaryInterpretations; this.consent = consent; - this.analyst = analyst; + this.analysts = analysts; this.report = report; + this.request = request; + this.responsible = responsible; this.priority = priority; this.flags = flags; this.creationDate = creationDate; @@ -261,8 +272,10 @@ public String toString() { sb.append(", interpretation=").append(interpretation); sb.append(", secondaryInterpretations=").append(secondaryInterpretations); sb.append(", consent=").append(consent); - sb.append(", analyst=").append(analyst); + sb.append(", analysts=").append(analysts); sb.append(", report=").append(report); + sb.append(", request=").append(request); + sb.append(", responsible=").append(responsible); sb.append(", priority=").append(priority); sb.append(", flags=").append(flags); sb.append(", creationDate='").append(creationDate).append('\''); @@ -273,7 +286,6 @@ public String toString() { sb.append(", comments=").append(comments); sb.append(", audit=").append(audit); sb.append(", internal=").append(internal); - sb.append(", annotationSets=").append(annotationSets); sb.append(", attributes=").append(attributes); sb.append(", status=").append(status); sb.append('}'); @@ -409,12 +421,12 @@ public ClinicalAnalysis setConsent(ClinicalConsentAnnotation consent) { return this; } - public ClinicalAnalyst getAnalyst() { - return analyst; + public List getAnalysts() { + return analysts; } - public ClinicalAnalysis setAnalyst(ClinicalAnalyst analyst) { - this.analyst = analyst; + public ClinicalAnalysis setAnalysts(List analysts) { + this.analysts = analysts; return this; } @@ -427,6 +439,24 @@ public ClinicalAnalysis setReport(ClinicalReport report) { return this; } + public ClinicalRequest getRequest() { + return request; + } + + public ClinicalAnalysis setRequest(ClinicalRequest request) { + this.request = request; + return this; + } + + public ClinicalResponsible getResponsible() { + return responsible; + } + + public ClinicalAnalysis setResponsible(ClinicalResponsible responsible) { + this.responsible = responsible; + return this; + } + public ClinicalPriorityAnnotation getPriority() { return priority; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java index 9d91754d5be..301db1b3b54 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java @@ -48,8 +48,10 @@ public class ClinicalAnalysisCreateParams { private List panels; private Boolean panelLock; - private ClinicalAnalystParam analyst; + private List analysts; private ClinicalReport report; + private ClinicalRequest request; + private ClinicalResponsible responsible; private InterpretationCreateParams interpretation; private ClinicalAnalysisQualityControlUpdateParam qualityControl; @@ -71,10 +73,10 @@ public ClinicalAnalysisCreateParams() { public ClinicalAnalysisCreateParams(String id, String description, ClinicalAnalysis.Type type, DisorderReferenceParam disorder, List files, ProbandParam proband, FamilyParam family, - List panels, Boolean panelLock, ClinicalAnalystParam analyst, - ClinicalReport report, InterpretationCreateParams interpretation, - ClinicalConsentAnnotationParam consent, String creationDate, String modificationDate, - String dueDate, List comments, + List panels, Boolean panelLock, List analysts, + ClinicalReport report, ClinicalRequest request, ClinicalResponsible responsible, + InterpretationCreateParams interpretation, ClinicalConsentAnnotationParam consent, + String creationDate, String modificationDate, String dueDate, List comments, ClinicalAnalysisQualityControlUpdateParam qualityControl, PriorityParam priority, List flags, List annotationSets, Map attributes, StatusParam status) { @@ -88,7 +90,9 @@ public ClinicalAnalysisCreateParams(String id, String description, ClinicalAnaly this.panels = panels; this.panelLock = panelLock; this.report = report; - this.analyst = analyst; + this.request = request; + this.responsible = responsible; + this.analysts = analysts; this.interpretation = interpretation; this.consent = consent; this.creationDate = creationDate; @@ -115,8 +119,10 @@ public static ClinicalAnalysisCreateParams of(ClinicalAnalysis clinicalAnalysis) ? clinicalAnalysis.getPanels().stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList()) : null, clinicalAnalysis.isPanelLock(), - clinicalAnalysis.getAnalyst() != null ? ClinicalAnalystParam.of(clinicalAnalysis.getAnalyst()) : null, - clinicalAnalysis.getReport(), + clinicalAnalysis.getAnalysts() != null + ? clinicalAnalysis.getAnalysts().stream().map(ClinicalAnalystParam::of).collect(Collectors.toList()) + : null, + clinicalAnalysis.getReport(), clinicalAnalysis.getRequest(), clinicalAnalysis.getResponsible(), clinicalAnalysis.getInterpretation() != null ? InterpretationCreateParams.of(clinicalAnalysis.getInterpretation()) : null, @@ -148,8 +154,10 @@ public String toString() { sb.append(", family=").append(family); sb.append(", panels=").append(panels); sb.append(", panelLock=").append(panelLock); - sb.append(", analyst=").append(analyst); + sb.append(", analysts=").append(analysts); sb.append(", report=").append(report); + sb.append(", request=").append(request); + sb.append(", responsible=").append(responsible); sb.append(", interpretation=").append(interpretation); sb.append(", qualityControl=").append(qualityControl); sb.append(", consent=").append(consent); @@ -198,7 +206,13 @@ public ClinicalAnalysis toClinicalAnalysis() { Interpretation primaryInterpretation = interpretation != null ? interpretation.toClinicalInterpretation() : null; - String assignee = analyst != null ? analyst.getId() : ""; + List clinicalAnalystList = null; + if (analysts != null) { + clinicalAnalystList = new ArrayList<>(analysts.size()); + for (ClinicalAnalystParam analyst : analysts) { + clinicalAnalystList.add(new ClinicalAnalyst(analyst.getId(), analyst.getId(), "", "", TimeUtils.getTime())); + } + } List caFiles = new LinkedList<>(); if (files != null) { @@ -217,11 +231,11 @@ public ClinicalAnalysis toClinicalAnalysis() { return new ClinicalAnalysis(id, description, type, disorder != null ? disorder.toDisorder() : null, caFiles, individual, f, diseasePanelList, panelLock != null ? panelLock : false, false, primaryInterpretation, new LinkedList<>(), consent != null ? consent.toClinicalConsentAnnotation() : null, - new ClinicalAnalyst(assignee, assignee, "", "", TimeUtils.getTime()), report, - priority != null ? priority.toClinicalPriorityAnnotation() : null, + clinicalAnalystList, report, request, responsible, priority != null ? priority.toClinicalPriorityAnnotation() : null, flags != null ? flags.stream().map(FlagValueParam::toFlagAnnotation).collect(Collectors.toList()) : null, creationDate, modificationDate, dueDate, 1, - comments != null ? comments.stream().map(ClinicalCommentParam::toClinicalComment).collect(Collectors.toList()) : null, qualityControl != null ? qualityControl.toClinicalQualityControl() : null, new LinkedList<>(), null, + comments != null ? comments.stream().map(ClinicalCommentParam::toClinicalComment).collect(Collectors.toList()) : null, + qualityControl != null ? qualityControl.toClinicalQualityControl() : null, new LinkedList<>(), null, annotationSets, attributes, status != null ? status.toStatus() : null); } @@ -306,12 +320,12 @@ public ClinicalAnalysisCreateParams setPanelLock(Boolean panelLock) { return this; } - public ClinicalAnalystParam getAnalyst() { - return analyst; + public List getAnalysts() { + return analysts; } - public ClinicalAnalysisCreateParams setAnalyst(ClinicalAnalystParam analyst) { - this.analyst = analyst; + public ClinicalAnalysisCreateParams setAnalysts(List analysts) { + this.analysts = analysts; return this; } @@ -324,6 +338,24 @@ public ClinicalAnalysisCreateParams setReport(ClinicalReport report) { return this; } + public ClinicalRequest getRequest() { + return request; + } + + public ClinicalAnalysisCreateParams setRequest(ClinicalRequest request) { + this.request = request; + return this; + } + + public ClinicalResponsible getResponsible() { + return responsible; + } + + public ClinicalAnalysisCreateParams setResponsible(ClinicalResponsible responsible) { + this.responsible = responsible; + return this; + } + public InterpretationCreateParams getInterpretation() { return interpretation; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisQualityControlUpdateParam.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisQualityControlUpdateParam.java index d2634228641..98e957bc234 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisQualityControlUpdateParam.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisQualityControlUpdateParam.java @@ -49,6 +49,7 @@ public String toString() { final StringBuilder sb = new StringBuilder("ClinicalAnalysisQualityControlUpdateParam{"); sb.append("summary=").append(summary); sb.append(", comments=").append(comments); + sb.append(", files=").append(files); sb.append('}'); return sb.toString(); } @@ -61,4 +62,22 @@ public ClinicalAnalysisQualityControlUpdateParam setSummary(ClinicalAnalysisQual this.summary = summary; return this; } + + public List getComments() { + return comments; + } + + public ClinicalAnalysisQualityControlUpdateParam setComments(List comments) { + this.comments = comments; + return this; + } + + public List getFiles() { + return files; + } + + public ClinicalAnalysisQualityControlUpdateParam setFiles(List files) { + this.files = files; + return this; + } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java index 1cec037fb1c..b32711af25b 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisUpdateParams.java @@ -48,9 +48,10 @@ public class ClinicalAnalysisUpdateParams { private FamilyParam family; private Boolean locked; - private ClinicalAnalystParam analyst; + private List analysts; private ClinicalReport report; - + private ClinicalRequest request; + private ClinicalResponsible responsible; private ClinicalAnalysisQualityControlUpdateParam qualityControl; @@ -72,8 +73,9 @@ public ClinicalAnalysisUpdateParams() { public ClinicalAnalysisUpdateParams(String id, String description, ClinicalAnalysis.Type type, DisorderReferenceParam disorder, List files, ProbandParam proband, FamilyParam family, - List panels, Boolean panelLock, Boolean locked, ClinicalAnalystParam analyst, - ClinicalReport report, ClinicalAnalysisQualityControlUpdateParam qualityControl, + List panels, Boolean panelLock, Boolean locked, + List analysts, ClinicalReport report, ClinicalRequest request, + ClinicalResponsible responsible, ClinicalAnalysisQualityControlUpdateParam qualityControl, ClinicalConsentAnnotationParam consent, String creationDate, String modificationDate, String dueDate, List comments, PriorityParam priority, List flags, List annotationSets, Map attributes, @@ -88,8 +90,10 @@ public ClinicalAnalysisUpdateParams(String id, String description, ClinicalAnaly this.panels = panels; this.panelLock = panelLock; this.locked = locked; - this.analyst = analyst; + this.analysts = analysts; this.report = report; + this.request = request; + this.responsible = responsible; this.qualityControl = qualityControl; this.consent = consent; this.creationDate = creationDate; @@ -119,7 +123,10 @@ public ClinicalAnalysis toClinicalAnalysis() { locked != null && locked, null, null, consent != null ? consent.toClinicalConsentAnnotation() : null, - analyst != null ? analyst.toClinicalAnalyst() : null, report, + analysts != null + ? analysts.stream().map(ClinicalAnalystParam::toClinicalAnalyst).collect(Collectors.toList()) + : null, + report, request, responsible, priority != null ? priority.toClinicalPriorityAnnotation() : null, flags != null ? flags.stream().map(FlagValueParam::toFlagAnnotation).collect(Collectors.toList()) : null, creationDate, modificationDate, dueDate, 1, @@ -141,8 +148,10 @@ public String toString() { sb.append(", proband=").append(proband); sb.append(", family=").append(family); sb.append(", locked=").append(locked); - sb.append(", analyst=").append(analyst); + sb.append(", analysts=").append(analysts); sb.append(", report=").append(report); + sb.append(", request=").append(request); + sb.append(", responsible=").append(responsible); sb.append(", qualityControl=").append(qualityControl); sb.append(", consent=").append(consent); sb.append(", creationDate='").append(creationDate).append('\''); @@ -248,12 +257,12 @@ public ClinicalAnalysisUpdateParams setLocked(Boolean locked) { return this; } - public ClinicalAnalystParam getAnalyst() { - return analyst; + public List getAnalysts() { + return analysts; } - public ClinicalAnalysisUpdateParams setAnalyst(ClinicalAnalystParam analyst) { - this.analyst = analyst; + public ClinicalAnalysisUpdateParams setAnalysts(List analysts) { + this.analysts = analysts; return this; } @@ -365,4 +374,21 @@ public ClinicalAnalysisUpdateParams setReport(ClinicalReport report) { return this; } + public ClinicalRequest getRequest() { + return request; + } + + public ClinicalAnalysisUpdateParams setRequest(ClinicalRequest request) { + this.request = request; + return this; + } + + public ClinicalResponsible getResponsible() { + return responsible; + } + + public ClinicalAnalysisUpdateParams setResponsible(ClinicalResponsible responsible) { + this.responsible = responsible; + return this; + } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalReport.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalReport.java index 8303fdc7a1b..fca6fd5c418 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalReport.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalReport.java @@ -1,8 +1,12 @@ package org.opencb.opencga.core.models.clinical; +import org.opencb.biodata.models.clinical.ClinicalComment; import org.opencb.biodata.models.clinical.ClinicalDiscussion; import org.opencb.commons.annotations.DataField; import org.opencb.opencga.core.api.FieldConstants; +import org.opencb.opencga.core.models.file.File; + +import java.util.List; public class ClinicalReport { @@ -34,11 +38,20 @@ public class ClinicalReport { description = FieldConstants.CLINICAL_REPORT_DATE) private String date; + @DataField(id = "comments", description = FieldConstants.CLINICAL_REPORT_COMMENTS, since = "2.12.0") + private List comments; + + @DataField(id = "supportingEvidences", description = FieldConstants.CLINICAL_REPORT_SUPPORTING_EVIDENCES, since = "2.12.0") + private List supportingEvidences; + + @DataField(id = "files", description = FieldConstants.CLINICAL_REPORT_FILES, since = "2.12.0") + private List files; + public ClinicalReport() { } - public ClinicalReport(String title, String overview, ClinicalDiscussion discussion, String logo, String signedBy, - String signature, String date) { + public ClinicalReport(String title, String overview, ClinicalDiscussion discussion, String logo, String signedBy, String signature, + String date, List comments, List supportingEvidences, List files) { this.title = title; this.overview = overview; this.discussion = discussion; @@ -46,6 +59,9 @@ public ClinicalReport(String title, String overview, ClinicalDiscussion discussi this.signedBy = signedBy; this.signature = signature; this.date = date; + this.comments = comments; + this.supportingEvidences = supportingEvidences; + this.files = files; } @Override @@ -53,11 +69,14 @@ public String toString() { final StringBuilder sb = new StringBuilder("ClinicalReport{"); sb.append("title='").append(title).append('\''); sb.append(", overview='").append(overview).append('\''); - sb.append(", discussion='").append(discussion).append('\''); + sb.append(", discussion=").append(discussion); sb.append(", logo='").append(logo).append('\''); sb.append(", signedBy='").append(signedBy).append('\''); sb.append(", signature='").append(signature).append('\''); sb.append(", date='").append(date).append('\''); + sb.append(", comments=").append(comments); + sb.append(", supportingEvidences=").append(supportingEvidences); + sb.append(", files=").append(files); sb.append('}'); return sb.toString(); } @@ -124,4 +143,31 @@ public ClinicalReport setDate(String date) { this.date = date; return this; } + + public List getComments() { + return comments; + } + + public ClinicalReport setComments(List comments) { + this.comments = comments; + return this; + } + + public List getSupportingEvidences() { + return supportingEvidences; + } + + public ClinicalReport setSupportingEvidences(List supportingEvidences) { + this.supportingEvidences = supportingEvidences; + return this; + } + + public List getFiles() { + return files; + } + + public ClinicalReport setFiles(List files) { + this.files = files; + return this; + } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalRequest.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalRequest.java new file mode 100644 index 00000000000..38998b4bb0d --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalRequest.java @@ -0,0 +1,80 @@ +package org.opencb.opencga.core.models.clinical; + +import java.util.Map; + +public class ClinicalRequest { + + private String id; + private String justification; + private String date; + private ClinicalResponsible responsible; + private Map attributes; + + public ClinicalRequest() { + } + + public ClinicalRequest(String id, String justification, String date, ClinicalResponsible responsible, Map attributes) { + this.id = id; + this.justification = justification; + this.date = date; + this.responsible = responsible; + this.attributes = attributes; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ClinicalRequest{"); + sb.append("id='").append(id).append('\''); + sb.append(", justification='").append(justification).append('\''); + sb.append(", date='").append(date).append('\''); + sb.append(", responsible=").append(responsible); + sb.append(", attributes=").append(attributes); + sb.append('}'); + return sb.toString(); + } + + public String getId() { + return id; + } + + public ClinicalRequest setId(String id) { + this.id = id; + return this; + } + + public String getJustification() { + return justification; + } + + public ClinicalRequest setJustification(String justification) { + this.justification = justification; + return this; + } + + public String getDate() { + return date; + } + + public ClinicalRequest setDate(String date) { + this.date = date; + return this; + } + + public ClinicalResponsible getResponsible() { + return responsible; + } + + public ClinicalRequest setResponsible(ClinicalResponsible responsible) { + this.responsible = responsible; + return this; + } + + public Map getAttributes() { + return attributes; + } + + public ClinicalRequest setAttributes(Map attributes) { + this.attributes = attributes; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalResponsible.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalResponsible.java new file mode 100644 index 00000000000..3e8967b552a --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalResponsible.java @@ -0,0 +1,115 @@ +package org.opencb.opencga.core.models.clinical; + +public class ClinicalResponsible { + + private String id; + private String name; + private String email; + private String organization; + private String department; + private String address; + private String city; + private String postcode; + + public ClinicalResponsible() { + } + + public ClinicalResponsible(String id, String name, String email, String organization, String department, String address, String city, + String postcode) { + this.id = id; + this.name = name; + this.email = email; + this.organization = organization; + this.department = department; + this.address = address; + this.city = city; + this.postcode = postcode; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ClinicalResponsible{"); + sb.append("id='").append(id).append('\''); + sb.append(", name='").append(name).append('\''); + sb.append(", email='").append(email).append('\''); + sb.append(", organization='").append(organization).append('\''); + sb.append(", department='").append(department).append('\''); + sb.append(", address='").append(address).append('\''); + sb.append(", city='").append(city).append('\''); + sb.append(", postcode='").append(postcode).append('\''); + sb.append('}'); + return sb.toString(); + } + + public String getId() { + return id; + } + + public ClinicalResponsible setId(String id) { + this.id = id; + return this; + } + + public String getName() { + return name; + } + + public ClinicalResponsible setName(String name) { + this.name = name; + return this; + } + + public String getEmail() { + return email; + } + + public ClinicalResponsible setEmail(String email) { + this.email = email; + return this; + } + + public String getOrganization() { + return organization; + } + + public ClinicalResponsible setOrganization(String organization) { + this.organization = organization; + return this; + } + + public String getDepartment() { + return department; + } + + public ClinicalResponsible setDepartment(String department) { + this.department = department; + return this; + } + + public String getAddress() { + return address; + } + + public ClinicalResponsible setAddress(String address) { + this.address = address; + return this; + } + + public String getCity() { + return city; + } + + public ClinicalResponsible setCity(String city) { + this.city = city; + return this; + } + + public String getPostcode() { + return postcode; + } + + public ClinicalResponsible setPostcode(String postcode) { + this.postcode = postcode; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/file/File.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/file/File.java index 28a2a05980f..581cc6d6dd1 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/file/File.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/file/File.java @@ -562,6 +562,7 @@ public enum Format { TAB_SEPARATED_VALUES, COMMA_SEPARATED_VALUES, XML, PROTOCOL_BUFFER, JSON, AVRO, PARQUET, //Serialization formats + PDF, IMAGE, PLAIN, BINARY, diff --git a/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java b/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java index 5c33dd532b2..fdaa1e84449 100644 --- a/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java +++ b/opencga-server/src/main/java/org/opencb/opencga/server/rest/analysis/ClinicalWebService.java @@ -211,6 +211,8 @@ public Response update( @QueryParam("commentsAction") ParamUtils.AddRemoveReplaceAction commentsAction, @ApiParam(value = "Action to be performed if the array of flags is being updated.", allowableValues = "ADD,SET,REMOVE", defaultValue = "ADD") @QueryParam("flagsAction") ParamUtils.BasicUpdateAction flagsAction, + @ApiParam(value = "Action to be performed if the array of analysts is being updated.", allowableValues = "ADD,SET,REMOVE", defaultValue = "ADD") + @QueryParam("analystsAction") ParamUtils.BasicUpdateAction analystsAction, @ApiParam(value = "Action to be performed if the array of files is being updated.", allowableValues = "ADD,SET,REMOVE", defaultValue = "ADD") @QueryParam("filesAction") ParamUtils.BasicUpdateAction filesAction, @ApiParam(value = "Action to be performed if the array of panels is being updated.", allowableValues = "ADD,SET,REMOVE", defaultValue = "ADD") @@ -235,6 +237,9 @@ public Response update( if (panelsAction == null) { panelsAction = ParamUtils.BasicUpdateAction.ADD; } + if (analystsAction == null) { + analystsAction = ParamUtils.BasicUpdateAction.ADD; + } Map actionMap = new HashMap<>(); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.ANNOTATION_SETS.key(), annotationSetsAction); @@ -242,6 +247,7 @@ public Response update( actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.FLAGS.key(), flagsAction); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), filesAction); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.PANELS.key(), panelsAction); + actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), analystsAction); queryOptions.put(Constants.ACTIONS, actionMap); return createOkResponse(clinicalManager.update(studyStr, getIdList(clinicalAnalysisStr), params, true, queryOptions, token)); From afe43bbf2dd548c60c7bd1176ccb3917b8d125fe Mon Sep 17 00:00:00 2001 From: pfurio Date: Wed, 29 Nov 2023 10:44:10 +0100 Subject: [PATCH 5/7] app: add data model migration, #TASK-5198 --- ...pleteClinicalReportDataModelMigration.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java index b4fa490c90a..f7e6123b223 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v2_12_0/catalog/CompleteClinicalReportDataModelMigration.java @@ -2,6 +2,9 @@ import com.mongodb.client.model.Filters; import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.bson.Document; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor; import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptorFactory; import org.opencb.opencga.catalog.migration.Migration; import org.opencb.opencga.catalog.migration.MigrationTool; @@ -9,6 +12,8 @@ import java.util.Arrays; import java.util.Collections; +import static com.mongodb.client.model.Filters.eq; + @Migration(id = "complete_clinical_report_data_model" , description = "Complete Clinical Report data model #TASK-5198", version = "2.12.0", @@ -23,10 +28,35 @@ protected void run() throws Exception { migrateCollection( Arrays.asList(MongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, MongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION), Filters.exists("analyst"), - Projections.include(Collections.singletonList("analyst")), + Projections.include(Arrays.asList("analyst", "report")), (document, bulk) -> { + Document analyst = document.get("analyst", Document.class); + analyst.remove("assignedBy"); + analyst.remove("date"); + + Document report = document.get("report", Document.class); + if (report != null) { + report.put("comments", Collections.emptyList()); + report.put("supportingEvidences", Collections.emptyList()); + report.put("files", Collections.emptyList()); + } + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + updateDocument.getSet().put("report", report); + updateDocument.getSet().put("request", new Document()); + updateDocument.getSet().put("responsible", new Document() + .append("id", analyst.get("id")) + .append("name", analyst.get("name")) + .append("email", analyst.get("email")) + ); + updateDocument.getSet().put("analysts", Collections.singletonList(analyst)); + updateDocument.getUnset().add("analyst"); + + bulk.add(new UpdateOneModel<>( + eq("_id", document.get("_id")), + updateDocument.toFinalUpdateDocument() + ) + ); }); } - } From e46d9ba2c44b871746bb6b6cde7c6cf892671913 Mon Sep 17 00:00:00 2001 From: pfurio Date: Wed, 29 Nov 2023 12:40:14 +0100 Subject: [PATCH 6/7] catalog: fix biodata changes, #TASK-5198 --- .../analysis/clinical/ClinicalInterpretationManager.java | 2 +- .../opencga/catalog/managers/ClinicalAnalysisManager.java | 4 ++-- .../opencga/catalog/managers/InterpretationManager.java | 6 +++--- .../catalog/managers/ClinicalAnalysisManagerTest.java | 4 ++-- .../core/models/clinical/ClinicalAnalysisCreateParams.java | 3 +-- .../opencga/core/models/clinical/ClinicalAnalystParam.java | 5 +++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalInterpretationManager.java b/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalInterpretationManager.java index 50e6d32da75..3ca18fe0eb9 100644 --- a/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalInterpretationManager.java +++ b/opencga-analysis/src/main/java/org/opencb/opencga/analysis/clinical/ClinicalInterpretationManager.java @@ -824,7 +824,7 @@ public ClinicalAnalyst getAnalyst(String token) throws ToolException { OpenCGAResult userQueryResult = catalogManager.getUserManager().get(userId, new QueryOptions(QueryOptions.INCLUDE, Arrays.asList(UserDBAdaptor.QueryParams.EMAIL.key(), UserDBAdaptor.QueryParams.ORGANIZATION.key())), token); User user = userQueryResult.first(); - return new ClinicalAnalyst(userId, user.getName(), user.getEmail(), "", ""); + return new ClinicalAnalyst(userId, user.getName(), user.getEmail(), "", Collections.emptyMap()); } catch (CatalogException e) { throw new ToolException(e); } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java index 069a8e25d4e..13be28039cc 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManager.java @@ -337,7 +337,7 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis } List clinicalAnalystList = new ArrayList<>(userList.size()); for (User user : userList) { - clinicalAnalystList.add(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, TimeUtils.getTime())); + clinicalAnalystList.add(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, Collections.emptyMap())); } clinicalAnalysis.setAnalysts(clinicalAnalystList); @@ -1484,7 +1484,7 @@ private OpenCGAResult update(Study study, ClinicalAnalysis cli } for (User user : userResult.getResults()) { clinicalAnalystList.add(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, - TimeUtils.getTime())); + Collections.emptyMap())); } } parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.ANALYSTS.key(), clinicalAnalystList); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/InterpretationManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/InterpretationManager.java index 4294998ca19..0ab582184d0 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/InterpretationManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/InterpretationManager.java @@ -388,7 +388,7 @@ void validateNewInterpretation(Study study, Interpretation interpretation, Clini } user = result.first(); } - interpretation.setAnalyst(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, TimeUtils.getTime())); + interpretation.setAnalyst(new ClinicalAnalyst(user.getId(), user.getName(), user.getEmail(), userId, Collections.emptyMap())); } public OpenCGAResult clear(String studyStr, String clinicalAnalysisId, List interpretationList, String token) @@ -984,11 +984,11 @@ private OpenCGAResult update(Study study, Interpretation interpretation, Interpr throw new CatalogException("User '" + updateParams.getAnalyst().getId() + "' not found"); } parameters.put(InterpretationDBAdaptor.QueryParams.ANALYST.key(), new ClinicalAnalyst(userResult.first().getId(), - userResult.first().getName(), userResult.first().getEmail(), userId, TimeUtils.getTime())); + userResult.first().getName(), userResult.first().getEmail(), userId, Collections.emptyMap())); } else { // Remove assignee parameters.put(InterpretationDBAdaptor.QueryParams.ANALYST.key(), new ClinicalAnalyst("", "", "", userId, - TimeUtils.getTime())); + Collections.emptyMap())); } } diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java index 400c85e23af..e07d53338b9 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/ClinicalAnalysisManagerTest.java @@ -305,8 +305,8 @@ public void updateClinicalAnalystsTest() throws CatalogException { for (ClinicalAnalyst analyst : result.first().getAnalysts()) { assertNotNull(analyst.getId()); assertNotNull(analyst.getName()); - assertNotNull(analyst.getDate()); - assertEquals("user", analyst.getAssignedBy()); + assertNotNull(analyst.getRole()); + assertNotNull(analyst.getAttributes()); } // Remove analysts diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java index 301db1b3b54..ee4ab6d703b 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisCreateParams.java @@ -17,7 +17,6 @@ package org.opencb.opencga.core.models.clinical; import org.opencb.biodata.models.clinical.ClinicalAnalyst; -import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.models.common.AnnotationSet; import org.opencb.opencga.core.models.common.StatusParam; import org.opencb.opencga.core.models.family.Family; @@ -210,7 +209,7 @@ public ClinicalAnalysis toClinicalAnalysis() { if (analysts != null) { clinicalAnalystList = new ArrayList<>(analysts.size()); for (ClinicalAnalystParam analyst : analysts) { - clinicalAnalystList.add(new ClinicalAnalyst(analyst.getId(), analyst.getId(), "", "", TimeUtils.getTime())); + clinicalAnalystList.add(new ClinicalAnalyst(analyst.getId(), analyst.getId(), "", "", Collections.emptyMap())); } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalystParam.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalystParam.java index 91861b29d0b..ad3a3cd13f7 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalystParam.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalystParam.java @@ -1,7 +1,8 @@ package org.opencb.opencga.core.models.clinical; import org.opencb.biodata.models.clinical.ClinicalAnalyst; -import org.opencb.opencga.core.common.TimeUtils; + +import java.util.Collections; public class ClinicalAnalystParam { @@ -23,7 +24,7 @@ public static ClinicalAnalystParam of(ClinicalAnalyst clinicalAnalyst) { } public ClinicalAnalyst toClinicalAnalyst() { - return new ClinicalAnalyst(id != null ? id : "", "", "", "", TimeUtils.getTime()); + return new ClinicalAnalyst(id != null ? id : "", "", "", "", Collections.emptyMap()); } @Override From 0c6871351f9aaec3e51c1886b32bdcfe97d5a685 Mon Sep 17 00:00:00 2001 From: pfurio Date: Wed, 29 Nov 2023 13:01:41 +0100 Subject: [PATCH 7/7] storage: ignore test --- .../variant/annotation/annotators/VariantAnnotatorTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/opencga-storage/opencga-storage-core/src/test/java/org/opencb/opencga/storage/core/variant/annotation/annotators/VariantAnnotatorTest.java b/opencga-storage/opencga-storage-core/src/test/java/org/opencb/opencga/storage/core/variant/annotation/annotators/VariantAnnotatorTest.java index 02b84fc38a9..ecc48098006 100644 --- a/opencga-storage/opencga-storage-core/src/test/java/org/opencb/opencga/storage/core/variant/annotation/annotators/VariantAnnotatorTest.java +++ b/opencga-storage/opencga-storage-core/src/test/java/org/opencb/opencga/storage/core/variant/annotation/annotators/VariantAnnotatorTest.java @@ -1,20 +1,19 @@ package org.opencb.opencga.storage.core.variant.annotation.annotators; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.rules.ExpectedException; import org.opencb.biodata.models.variant.Variant; -import org.opencb.biodata.models.variant.avro.EvidenceEntry; import org.opencb.biodata.models.variant.avro.VariantAnnotation; import org.opencb.cellbase.core.result.CellBaseDataResult; import org.opencb.commons.datastore.core.ObjectMap; +import org.opencb.opencga.core.config.storage.StorageConfiguration; import org.opencb.opencga.core.testclassification.duration.ShortTests; import org.opencb.opencga.storage.core.StorageEngine; -import org.opencb.opencga.core.config.storage.StorageConfiguration; import org.opencb.opencga.storage.core.metadata.models.ProjectMetadata; import org.opencb.opencga.storage.core.variant.VariantStorageOptions; import org.opencb.opencga.storage.core.variant.annotation.VariantAnnotatorException; @@ -111,6 +110,7 @@ public void testErrorVariant() throws VariantAnnotatorException { testAnnotator.annotate(Arrays.asList(new Variant("10:999:A:C"), new Variant("10:1000:A:C"), new Variant("10:1001:A:C"))); } + @Ignore @Test public void useCellBaseApiKeys() throws VariantAnnotatorException { storageConfiguration.getCellbase().setUrl("https://uk.ws.zettagenomics.com/cellbase/");