diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/AnalysisClinicalCommandExecutor.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/AnalysisClinicalCommandExecutor.java index c6596f06134..07dbf9230f9 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/AnalysisClinicalCommandExecutor.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/executors/AnalysisClinicalCommandExecutor.java @@ -347,7 +347,7 @@ private RestResponse create() throws Exception { putNestedIfNotEmpty(beanParams, "disorder.id", commandOptions.disorderId, true); putNestedIfNotEmpty(beanParams, "proband.id", commandOptions.probandId, true); putNestedIfNotEmpty(beanParams, "family.id", commandOptions.familyId, true); - putNestedIfNotNull(beanParams, "panelLock", commandOptions.panelLock, true); + putNestedIfNotNull(beanParams, "panelLocked", commandOptions.panelLocked, true); putNestedIfNotEmpty(beanParams, "analyst.id", commandOptions.analystId, true); putNestedIfNotEmpty(beanParams, "report.title", commandOptions.reportTitle, true); putNestedIfNotEmpty(beanParams, "report.overview", commandOptions.reportOverview, true); @@ -367,6 +367,7 @@ private RestResponse create() throws Exception { putNestedIfNotEmpty(beanParams, "responsible.address", commandOptions.responsibleAddress, true); putNestedIfNotEmpty(beanParams, "responsible.city", commandOptions.responsibleCity, true); putNestedIfNotEmpty(beanParams, "responsible.postcode", commandOptions.responsiblePostcode, true); + putNestedIfNotEmpty(beanParams, "interpretation.name", commandOptions.interpretationName, true); putNestedIfNotEmpty(beanParams, "interpretation.description", commandOptions.interpretationDescription, true); putNestedIfNotEmpty(beanParams, "interpretation.clinicalAnalysisId", commandOptions.interpretationClinicalAnalysisId, true); putNestedIfNotEmpty(beanParams, "interpretation.creationDate", commandOptions.interpretationCreationDate, true); @@ -419,6 +420,7 @@ private RestResponse distinct() throws Exception { queryParams.putIfNotEmpty("dueDate", commandOptions.dueDate); queryParams.putIfNotEmpty("qualityControlSummary", commandOptions.qualityControlSummary); queryParams.putIfNotEmpty("release", commandOptions.release); + queryParams.putIfNotNull("snapshot", commandOptions.snapshot); queryParams.putIfNotEmpty("status", commandOptions.status); queryParams.putIfNotEmpty("internalStatus", commandOptions.internalStatus); queryParams.putIfNotEmpty("annotation", commandOptions.annotation); @@ -439,6 +441,7 @@ private RestResponse distinctInterpretation() throws Exception { queryParams.putIfNotEmpty("study", commandOptions.study); queryParams.putIfNotEmpty("id", commandOptions.id); queryParams.putIfNotEmpty("uuid", commandOptions.uuid); + queryParams.putIfNotEmpty("name", commandOptions.name); queryParams.putIfNotEmpty("clinicalAnalysisId", commandOptions.clinicalAnalysisId); queryParams.putIfNotEmpty("analystId", commandOptions.analystId); queryParams.putIfNotEmpty("methodName", commandOptions.methodName); @@ -471,6 +474,7 @@ private RestResponse searchInterpretation() throws Exception { queryParams.putIfNotEmpty("study", commandOptions.study); queryParams.putIfNotEmpty("id", commandOptions.id); queryParams.putIfNotEmpty("uuid", commandOptions.uuid); + queryParams.putIfNotEmpty("name", commandOptions.name); queryParams.putIfNotEmpty("clinicalAnalysisId", commandOptions.clinicalAnalysisId); queryParams.putIfNotEmpty("analystId", commandOptions.analystId); queryParams.putIfNotEmpty("methodName", commandOptions.methodName); @@ -1145,6 +1149,7 @@ private RestResponse search() throws Exception { queryParams.putIfNotEmpty("dueDate", commandOptions.dueDate); queryParams.putIfNotEmpty("qualityControlSummary", commandOptions.qualityControlSummary); queryParams.putIfNotEmpty("release", commandOptions.release); + queryParams.putIfNotNull("snapshot", commandOptions.snapshot); queryParams.putIfNotEmpty("status", commandOptions.status); queryParams.putIfNotEmpty("internalStatus", commandOptions.internalStatus); queryParams.putIfNotEmpty("annotation", commandOptions.annotation); @@ -1293,7 +1298,7 @@ private RestResponse update() throws Exception { putNestedIfNotEmpty(beanParams, "description", commandOptions.description, true); putNestedIfNotNull(beanParams, "type", commandOptions.type, true); putNestedIfNotEmpty(beanParams, "disorder.id", commandOptions.disorderId, true); - putNestedIfNotNull(beanParams, "panelLock", commandOptions.panelLock, true); + putNestedIfNotNull(beanParams, "panelLocked", commandOptions.panelLocked, true); putNestedIfNotEmpty(beanParams, "proband.id", commandOptions.probandId, true); putNestedIfNotEmpty(beanParams, "family.id", commandOptions.familyId, true); putNestedIfNotNull(beanParams, "locked", commandOptions.locked, true); @@ -1325,6 +1330,7 @@ private RestResponse update() throws Exception { putNestedIfNotEmpty(beanParams, "priority.id", commandOptions.priorityId, true); putNestedMapIfNotEmpty(beanParams, "attributes", commandOptions.attributes, true); putNestedIfNotEmpty(beanParams, "status.id", commandOptions.statusId, true); + putNestedIfNotNull(beanParams, "panelLock", commandOptions.panelLock, true); clinicalAnalysisUpdateParams = JacksonUtils.getDefaultObjectMapper().copy() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true) @@ -1369,6 +1375,7 @@ private RestResponse info() throws Exception { queryParams.putIfNotEmpty("exclude", commandOptions.exclude); queryParams.putIfNotNull("flattenAnnotations", commandOptions.flattenAnnotations); queryParams.putIfNotEmpty("study", commandOptions.study); + queryParams.putIfNotEmpty("version", commandOptions.version); queryParams.putIfNotNull("deleted", commandOptions.deleted); if (queryParams.get("study") == null && OpencgaMain.isShellMode()) { queryParams.putIfNotEmpty("study", sessionManager.getSession().getCurrentStudy()); @@ -1404,6 +1411,7 @@ private RestResponse createInterpretation() throws Exception { .readValue(new java.io.File(commandOptions.jsonFile), InterpretationCreateParams.class); } else { ObjectMap beanParams = new ObjectMap(); + putNestedIfNotEmpty(beanParams, "name", commandOptions.name, true); putNestedIfNotEmpty(beanParams, "description", commandOptions.description, true); putNestedIfNotEmpty(beanParams, "clinicalAnalysisId", commandOptions.clinicalAnalysisId, true); putNestedIfNotEmpty(beanParams, "creationDate", commandOptions.creationDate, true); @@ -1493,6 +1501,7 @@ private RestResponse updateInterpretation() throws Exception { .readValue(new java.io.File(commandOptions.jsonFile), InterpretationUpdateParams.class); } else { ObjectMap beanParams = new ObjectMap(); + putNestedIfNotEmpty(beanParams, "name", commandOptions.name, true); putNestedIfNotEmpty(beanParams, "description", commandOptions.description, true); putNestedIfNotEmpty(beanParams, "analyst.id", commandOptions.analystId, true); putNestedIfNotEmpty(beanParams, "method.name", commandOptions.methodName, true); diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/AnalysisClinicalCommandOptions.java b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/AnalysisClinicalCommandOptions.java index 36f822087db..b9dc5e1956a 100644 --- a/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/AnalysisClinicalCommandOptions.java +++ b/opencga-app/src/main/java/org/opencb/opencga/app/cli/main/options/AnalysisClinicalCommandOptions.java @@ -241,8 +241,8 @@ public class CreateCommandOptions { @Parameter(names = {"--family-id"}, description = "The body web service id parameter", required = false, arity = 1) public String familyId; - @Parameter(names = {"--panel-lock"}, description = "The body web service panelLock parameter", required = false, arity = 1) - public Boolean panelLock; + @Parameter(names = {"--panel-locked"}, description = "The body web service panelLocked parameter", required = false, arity = 1) + public Boolean panelLocked; @Parameter(names = {"--analyst-id"}, description = "The body web service id parameter", required = false, arity = 1) public String analystId; @@ -301,6 +301,9 @@ public class CreateCommandOptions { @Parameter(names = {"--responsible-postcode"}, description = "The body web service postcode parameter", required = false, arity = 1) public String responsiblePostcode; + @Parameter(names = {"--interpretation-name"}, description = "The body web service name parameter", required = false, arity = 1) + public String interpretationName; + @Parameter(names = {"--interpretation-description"}, description = "The body web service description parameter", required = false, arity = 1) public String interpretationDescription; @@ -423,6 +426,9 @@ public class DistinctCommandOptions { @Parameter(names = {"--release"}, description = "Release when it was created", required = false, arity = 1) public String release; + @Parameter(names = {"--snapshot"}, description = "Snapshot value (Latest version of the entry in the specified release)", required = false, arity = 1) + public Integer snapshot; + @Parameter(names = {"--status"}, description = "Filter by status", required = false, arity = 1) public String status; @@ -455,6 +461,9 @@ public class DistinctInterpretationCommandOptions { @Parameter(names = {"--uuid"}, description = "Comma separated list of Interpretation UUIDs up to a maximum of 100", required = false, arity = 1) public String uuid; + @Parameter(names = {"--name", "-n"}, description = "Comma separated list of Interpretation names up to a maximum of 100", required = false, arity = 1) + public String name; + @Parameter(names = {"--clinical-analysis-id"}, description = "Clinical Analysis id", required = false, arity = 1) public String clinicalAnalysisId; @@ -523,6 +532,9 @@ public class SearchInterpretationCommandOptions { @Parameter(names = {"--uuid"}, description = "Comma separated list of Interpretation UUIDs up to a maximum of 100", required = false, arity = 1) public String uuid; + @Parameter(names = {"--name", "-n"}, description = "Comma separated list of Interpretation names up to a maximum of 100", required = false, arity = 1) + public String name; + @Parameter(names = {"--clinical-analysis-id"}, description = "Clinical Analysis id", required = false, arity = 1) public String clinicalAnalysisId; @@ -1740,6 +1752,9 @@ public class SearchCommandOptions { @Parameter(names = {"--release"}, description = "Release when it was created", required = false, arity = 1) public String release; + @Parameter(names = {"--snapshot"}, description = "Snapshot value (Latest version of the entry in the specified release)", required = false, arity = 1) + public Integer snapshot; + @Parameter(names = {"--status"}, description = "Filter by status", required = false, arity = 1) public String status; @@ -2027,8 +2042,8 @@ public class UpdateCommandOptions { @Parameter(names = {"--disorder-id"}, description = "The body web service id parameter", required = false, arity = 1) public String disorderId; - @Parameter(names = {"--panel-lock"}, description = "The body web service panelLock parameter", required = false, arity = 1) - public Boolean panelLock; + @Parameter(names = {"--panel-locked"}, description = "The body web service panelLocked parameter", required = false, arity = 1) + public Boolean panelLocked; @Parameter(names = {"--proband-id"}, description = "The body web service id parameter", required = false, arity = 1) public String probandId; @@ -2123,6 +2138,9 @@ public class UpdateCommandOptions { @Parameter(names = {"--status-id"}, description = "The body web service id parameter", required = false, arity = 1) public String statusId; + @Parameter(names = {"--panel-lock"}, description = "The body web service panelLock parameter", required = false, arity = 1) + public Boolean panelLock; + } @Parameters(commandNames = {"annotation-sets-annotations-update"}, commandDescription ="Update annotations from an annotationSet") @@ -2172,6 +2190,9 @@ public class InfoCommandOptions { @Parameter(names = {"--study", "-s"}, description = "Study [[organization@]project:]study where study and project can be either the ID or UUID", required = false, arity = 1) public String study; + @Parameter(names = {"--version"}, description = "Comma separated list of clinical versions. 'all' to get all the clinical versions. Not supported if multiple clinical ids are provided", required = false, arity = 1) + public String version; + @Parameter(names = {"--deleted"}, description = "Boolean to retrieve deleted entries", required = false, help = true, arity = 0) public boolean deleted = false; @@ -2207,6 +2228,9 @@ public class CreateInterpretationCommandOptions { @Parameter(names = {"--include-result"}, description = "Flag indicating to include the created or updated document result in the response", required = false, help = true, arity = 0) public boolean includeResult = false; + @Parameter(names = {"--name", "-n"}, description = "The body web service name parameter", required = false, arity = 1) + public String name; + @Parameter(names = {"--description"}, description = "The body web service description parameter", required = false, arity = 1) public String description; @@ -2344,6 +2368,9 @@ public class UpdateInterpretationCommandOptions { @Parameter(names = {"--include-result"}, description = "Flag indicating to include the created or updated document result in the response", required = false, help = true, arity = 0) public boolean includeResult = false; + @Parameter(names = {"--name", "-n"}, description = "The body web service name parameter", required = false, arity = 1) + public String name; + @Parameter(names = {"--description"}, description = "The body web service description parameter", required = false, arity = 1) public String description; diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddInterpretationName.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddInterpretationName.java new file mode 100644 index 00000000000..372130c0a5e --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddInterpretationName.java @@ -0,0 +1,35 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_0.TASK_5964; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Arrays; + +@Migration(id = "add_interpretation_name", description = "Add Interpretation name #TASK-5964", version = "3.2.0", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240610) +public class AddInterpretationName extends MigrationTool { + + @Override + protected void run() throws Exception { + // Add new Interpretation name field + Bson nameDoesNotExistQuery = Filters.exists("name", false); + Bson projection = Projections.include("id"); + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.INTERPRETATION_COLLECTION, + OrganizationMongoDBAdaptorFactory.INTERPRETATION_ARCHIVE_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_INTERPRETATION_COLLECTION)) { + migrateCollection(collection, nameDoesNotExistQuery, projection, + (document, bulk) -> { + Document updateDocument = new Document() + .append("name", document.get("id")); + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), new Document("$set", updateDocument))); + }); + } + } + +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddNewClinicalStatusValues.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddNewClinicalStatusValues.java new file mode 100644 index 00000000000..775cf2c64d7 --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddNewClinicalStatusValues.java @@ -0,0 +1,112 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_0.TASK_5964; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.apache.commons.lang3.StringUtils; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; +import org.opencb.opencga.core.common.GitRepositoryState; +import org.opencb.opencga.core.common.TimeUtils; +import org.opencb.opencga.core.models.clinical.ClinicalStatus; +import org.opencb.opencga.core.models.clinical.ClinicalStatusValue; +import org.opencb.opencga.core.models.study.configuration.ClinicalAnalysisStudyConfiguration; + +import java.util.Arrays; +import java.util.List; + +@Migration(id = "add_new_clinical_status", + description = "Add new ClinicalStatus to ClinicalAnalysis and Interpretation, #TASK-5964", + version = "3.2.0", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240611) +public class AddNewClinicalStatusValues extends MigrationTool { + + @Override + protected void run() throws Exception { + ClinicalAnalysisStudyConfiguration defaultConfiguration = ClinicalAnalysisStudyConfiguration.defaultConfiguration(); + + Bson query = Filters.exists("status.author", false); + Bson projection = Projections.include("status", "id"); + + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, + OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_ARCHIVE_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION)) { + migrateCollection(collection, query, projection, + (document, bulk) -> { + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + String clinicalId = document.getString("id"); + Document status = document.get("status", Document.class); + + Document newStatus = fillStatusValues("Clinical Analysis", clinicalId, status, defaultConfiguration.getStatus()); + updateDocument.getSet().put("status", newStatus); + + Document effectiveUpdate = updateDocument.toFinalUpdateDocument(); + + logger.debug("Updating clinical analysis '{}': {}", document.get("id"), effectiveUpdate.toBsonDocument()); + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), effectiveUpdate)); + }); + } + + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.INTERPRETATION_COLLECTION, + OrganizationMongoDBAdaptorFactory.INTERPRETATION_ARCHIVE_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_INTERPRETATION_COLLECTION)) { + migrateCollection(collection, query, projection, + (document, bulk) -> { + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + String interpretationId = document.getString("id"); + Document status = document.get("status", Document.class); + + Document newStatus = fillStatusValues("Interpretation", interpretationId, status, + defaultConfiguration.getInterpretation().getStatus()); + updateDocument.getSet().put("status", newStatus); + + Document effectiveUpdate = updateDocument.toFinalUpdateDocument(); + + logger.debug("Updating interpretation '{}': {}", document.get("id"), effectiveUpdate.toBsonDocument()); + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), effectiveUpdate)); + }); + } + } + + private Document fillStatusValues(String entity, String id, Document status, List statusValueList) { + ClinicalStatus clinicalStatus = new ClinicalStatus(); + String clinicalStatusId = status != null ? status.getString("id") : null; + if (status == null || StringUtils.isEmpty(clinicalStatusId)) { + logger.warn("Status is empty or does not contain 'id' field. Setting default status value for {} '{}'", entity, id); + for (ClinicalStatusValue clinicalStatusValue : statusValueList) { + if (clinicalStatusValue.getType().equals(ClinicalStatusValue.ClinicalStatusType.NOT_STARTED)) { + clinicalStatus.setId(clinicalStatusValue.getId()); + clinicalStatus.setDescription(clinicalStatusValue.getDescription()); + clinicalStatus.setType(clinicalStatusValue.getType()); + } + } + } else { + for (ClinicalStatusValue clinicalStatusValue : statusValueList) { + if (clinicalStatusValue.getId().equals(clinicalStatusId)) { + clinicalStatus.setId(clinicalStatusValue.getId()); + clinicalStatus.setDescription(clinicalStatusValue.getDescription()); + clinicalStatus.setType(clinicalStatusValue.getType()); + break; + } + } + if (clinicalStatus.getType() == null) { + logger.warn("Status '{}' not found in the list of available status values. Keeping original status for {} '{}'", + clinicalStatusId, entity, id); + clinicalStatus.setId(clinicalStatusId); + clinicalStatus.setDescription(status.getString("description")); + } + } + clinicalStatus.setDate(TimeUtils.getTime()); + clinicalStatus.setVersion(GitRepositoryState.getInstance().getBuildVersion()); + clinicalStatus.setCommit(GitRepositoryState.getInstance().getCommitId()); + clinicalStatus.setAuthor("opencga"); + + Document document = convertToDocument(clinicalStatus); + return document; + } + +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddVersionToClinicalAnalysisMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddVersionToClinicalAnalysisMigration.java new file mode 100644 index 00000000000..302637cf968 --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/AddVersionToClinicalAnalysisMigration.java @@ -0,0 +1,62 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_0.TASK_5964; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.apache.commons.collections4.CollectionUtils; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Collections; +import java.util.List; + +@Migration(id = "add_version_to_clinicalAnalysis", description = "Add version to Clinical Analysis #TASK-5964", version = "3.2.0", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240527) +public class AddVersionToClinicalAnalysisMigration extends MigrationTool { + + @Override + protected void run() throws Exception { + // Add missing mandatory "versioning" fields to Clinical Analysis + logger.info("Adding missing 'versioning' fields to Clinical Analysis..."); + Bson versionDoesNotExistQuery = Filters.exists("version", false); + Bson projection = Projections.include("release", "interpretation", "secondaryInterpretations"); + migrateCollection(OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, versionDoesNotExistQuery, projection, + (document, bulk) -> { + int version = 1; + Document interpretation = document.get("interpretation", Document.class); + if (interpretation != null) { + int interpretationVersion = interpretation.get("version", Number.class).intValue(); + version = Math.max(version, interpretationVersion + 1); + } + List secondaryInterpretations = document.getList("secondaryInterpretations", Document.class); + if (CollectionUtils.isNotEmpty(secondaryInterpretations)) { + for (Document secondaryInterpretation : secondaryInterpretations) { + int secondaryInterpretationVersion = secondaryInterpretation.get("version", Number.class).intValue(); + version = Math.max(version, secondaryInterpretationVersion + 1); + } + } + int release = document.get("release", Number.class).intValue(); + Document updateDocument = new Document() + .append("version", version) + .append("_releaseFromVersion", Collections.singletonList(release)) + .append("_lastOfVersion", true) + .append("_lastOfRelease", true); + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), new Document("$set", updateDocument))); + }); + + // Recalculate indexes + logger.info("Installing new indexes..."); + catalogManager.installIndexes(organizationId, token); + + // Copy all Clinical Analyses to the archive collection + logger.info("Copying all the data from the main collection to the archive one..."); + copyData(new Document(), OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, + OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_ARCHIVE_COLLECTION); + + + } + +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/RemoveStatusNameMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/RemoveStatusNameMigration.java new file mode 100644 index 00000000000..80692ae910c --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/RemoveStatusNameMigration.java @@ -0,0 +1,114 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_0.TASK_5964; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.exceptions.CatalogDBException; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Migration(id = "remove_status_name", description = "Remove status name #TASK-5964", version = "3.2.0", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240612) +public class RemoveStatusNameMigration extends MigrationTool { + + @Override + protected void run() throws Exception { + // Remove from user + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.USER_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_USER_COLLECTION)) { + removeStatusField(collection, Collections.singletonList("internal.status.name")); + } + + // Remove from project + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.PROJECT_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_PROJECT_COLLECTION)) { + removeStatusField(collection, Collections.singletonList("internal.status.name")); + } + + // Remove from study + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.STUDY_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_STUDY_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from sample + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.SAMPLE_COLLECTION, + OrganizationMongoDBAdaptorFactory.SAMPLE_ARCHIVE_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_SAMPLE_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name", "internal.variant.index.status.name", + "internal.variant.sampleGenotypeIndex.status.name", "internal.variant.sampleGenotypeIndex.familyStatus.name", + "internal.variant.secondarySampleIndex.status.name", "internal.variant.secondarySampleIndex.familyStatus.name", + "internal.variant.annotationIndex.status.name", "internal.variant.secondaryAnnotationIndex.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from file + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.FILE_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_FILE_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name", "internal.variant.index.status.name", + "internal.variant.annotationIndex.status.name", "internal.variant.secondaryAnnotationIndex.status.name", + "internal.alignment.index.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from individual + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.INDIVIDUAL_COLLECTION, + OrganizationMongoDBAdaptorFactory.INDIVIDUAL_ARCHIVE_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_INDIVIDUAL_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from family + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.FAMILY_COLLECTION, + OrganizationMongoDBAdaptorFactory.FAMILY_ARCHIVE_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_FAMILY_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from cohort + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.COHORT_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_COHORT_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from panel + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.PANEL_COLLECTION, + OrganizationMongoDBAdaptorFactory.PANEL_ARCHIVE_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_PANEL_COLLECTION)) { + List statusList = Arrays.asList("status.name", "internal.status.name"); + removeStatusField(collection, statusList); + } + + // Remove from job + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.JOB_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_JOB_COLLECTION)) { + removeStatusField(collection, Collections.singletonList("internal.status.name")); + } + + // Remove from clinical + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, + OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_ARCHIVE_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION)) { + removeStatusField(collection, Collections.singletonList("internal.status.name")); + } + + // Remove from interpretation + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.INTERPRETATION_COLLECTION, + OrganizationMongoDBAdaptorFactory.INTERPRETATION_ARCHIVE_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_INTERPRETATION_COLLECTION)) { + removeStatusField(collection, Collections.singletonList("internal.status.name")); + } + } + + private void removeStatusField(String collection, List statusList) throws CatalogDBException { + logger.info("Removing status.name fields from collection {}...", collection); + List exists = statusList.stream().map(Filters::exists).collect(Collectors.toList()); + List unsetList = statusList.stream().map(Updates::unset).collect(Collectors.toList()); + getMongoCollection(collection).updateMany(Filters.or(exists), Updates.combine(unsetList)); + } + +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/RenamePanelLockMigration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/RenamePanelLockMigration.java new file mode 100644 index 00000000000..32c10c3fab7 --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/RenamePanelLockMigration.java @@ -0,0 +1,26 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_0.TASK_5964; + +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationTool; + +import java.util.Arrays; + +@Migration(id = "rename_panel_lock_from_clinical__task_5964", description = "Rename 'panelLock' to 'panelLocked' #TASK-5964", + version = "3.2.0", language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240710) +public class RenamePanelLockMigration extends MigrationTool { + + @Override + protected void run() throws Exception { + Bson query = new Document(); + + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION, + OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_ARCHIVE_COLLECTION, + OrganizationMongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION)) { + getMongoCollection(collection).updateMany(query, new Document("$rename", new Document("panelLock", "panelLocked"))); + } + } + +} diff --git a/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/UpdateClinicalStudyConfiguration.java b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/UpdateClinicalStudyConfiguration.java new file mode 100644 index 00000000000..35960978d4c --- /dev/null +++ b/opencga-app/src/main/java/org/opencb/opencga/app/migrations/v3/v3_2_0/TASK_5964/UpdateClinicalStudyConfiguration.java @@ -0,0 +1,68 @@ +package org.opencb.opencga.app.migrations.v3.v3_2_0.TASK_5964; + +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Projections; +import com.mongodb.client.model.UpdateOneModel; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.opencb.opencga.catalog.db.mongodb.MongoDBAdaptor; +import org.opencb.opencga.catalog.db.mongodb.OrganizationMongoDBAdaptorFactory; +import org.opencb.opencga.catalog.migration.Migration; +import org.opencb.opencga.catalog.migration.MigrationRuntimeException; +import org.opencb.opencga.catalog.migration.MigrationTool; +import org.opencb.opencga.core.models.study.configuration.ClinicalAnalysisStudyConfiguration; + +import java.util.Arrays; +import java.util.List; + +@Migration(id = "update_clinical_study_configuration", + description = "Setting new default Clinical Study Configuration status values, #TASK-5964", + version = "3.2.0", + language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20240610) +public class UpdateClinicalStudyConfiguration extends MigrationTool { + + @Override + protected void run() throws Exception { + ClinicalAnalysisStudyConfiguration clinicalAnalysisStudyConfiguration = ClinicalAnalysisStudyConfiguration.defaultConfiguration(); + Document clinicalConfigurationDocument = convertToDocument(clinicalAnalysisStudyConfiguration); + + Bson query = new Document(); + Bson projection = Projections.include("internal.configuration.clinical", "fqn"); + + for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.STUDY_COLLECTION, OrganizationMongoDBAdaptorFactory.DELETED_STUDY_COLLECTION)) { + migrateCollection(collection, query, projection, + (document, bulk) -> { + Document internal = document.get("internal", Document.class); + if (internal == null) { + throw new MigrationRuntimeException("'internal' field not found in study '" + document.get("fqn") + "'"); + } + Document configuration = internal.get("configuration", Document.class); + if (configuration == null) { + throw new MigrationRuntimeException("'internal.configuration' field not found in study '" + document.get("fqn") + "'"); + } + Document clinicalDocument = configuration.get("clinical", Document.class); + + MongoDBAdaptor.UpdateDocument updateDocument = new MongoDBAdaptor.UpdateDocument(); + if (clinicalDocument == null) { + logger.warn("Found empty 'internal.configuration.clinical' field in study '{}'. Creating a new one...", document.get("fqn")); + updateDocument.getSet().put("internal.configuration.clinical", clinicalConfigurationDocument); + } else { + Object statusObject = clinicalDocument.get("status"); + if (statusObject instanceof List) { + // The study seems to be already migrated. Skipping... + logger.warn("Study '{}' seems to be already migrated. Skipping...", document.get("fqn")); + return; + } + // Study needs to be migrated + logger.info("Migrating study '{}'", document.get("fqn")); + updateDocument.getSet().put("internal.configuration.clinical.status", clinicalConfigurationDocument.get("status")); + updateDocument.getSet().put("internal.configuration.clinical.flags", clinicalConfigurationDocument.get("flags")); + updateDocument.getSet().put("internal.configuration.clinical.interpretation.status", clinicalConfigurationDocument.get("interpretation", Document.class).get("status")); + } + logger.debug("Updating study '{}': {}", document.get("fqn"), updateDocument.toFinalUpdateDocument()); + bulk.add(new UpdateOneModel<>(Filters.eq("_id", document.get("_id")), updateDocument.toFinalUpdateDocument())); + }); + } + } + +} 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 4fd3c2f9a3b..3935f24836d 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 @@ -78,8 +78,10 @@ enum QueryParams implements QueryParam { RESPONSIBLE("responsible", OBJECT, ""), FLAGS("flags", OBJECT, ""), FLAGS_ID("flags.id", TEXT, ""), + VERSION("version", INTEGER, ""), RELEASE("release", INTEGER, ""), - PANEL_LOCK("panelLock", BOOLEAN, ""), + SNAPSHOT("snapshot", INTEGER, ""), + PANEL_LOCKED("panelLocked", BOOLEAN, ""), LOCKED("locked", BOOLEAN, ""), SAMPLE("sample", TEXT_ARRAY, ""), // Alias to search for samples within proband.samples or family.members.samples diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java index 519e25fa3eb..a49e7fd6262 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/api/InterpretationDBAdaptor.java @@ -42,6 +42,7 @@ enum QueryParams implements QueryParam { ID("id", TEXT, ""), UID("uid", INTEGER, ""), UUID("uuid", TEXT, ""), + NAME("name", TEXT, ""), CLINICAL_ANALYSIS_ID("clinicalAnalysisId", TEXT, ""), DESCRIPTION("description", TEXT, ""), INTERNAL_STATUS("internal.status", TEXT, ""), 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 08216439ba5..7a359e5a7eb 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 @@ -83,16 +83,23 @@ public class ClinicalAnalysisMongoDBAdaptor extends AnnotationMongoDBAdaptor result = updateAnnotationSets(clientSession, clinical.getStudyUid(), clinicalAnalysisUid, parameters, variableSetList, - queryOptions, false); + Query tmpQuery = new Query() + .append(STUDY_UID.key(), clinical.getStudyUid()) + .append(QueryParams.UID.key(), clinicalAnalysisUid); + Bson bsonQuery = parseQuery(tmpQuery); + return versionedMongoDBAdaptor.update(clientSession, bsonQuery, (entryList) -> { + DataResult result = updateAnnotationSets(clientSession, clinical.getStudyUid(), clinicalAnalysisUid, parameters, + variableSetList, queryOptions, false); - // Perform the update - Query query = new Query(QueryParams.UID.key(), clinicalAnalysisUid); - UpdateDocument updateDocument = parseAndValidateUpdateParams(parameters, clinicalAuditList, query, queryOptions); + // Perform the update + UpdateDocument updateDocument = parseAndValidateUpdateParams(parameters, clinicalAuditList, tmpQuery, queryOptions); - Document updateOperation = updateDocument.toFinalUpdateDocument(); - List events = new ArrayList<>(); - if (!updateOperation.isEmpty() || !updateDocument.getNestedUpdateList().isEmpty()) { - DataResult update; + Document updateOperation = updateDocument.toFinalUpdateDocument(); + List events = new ArrayList<>(); + if (!updateOperation.isEmpty() || !updateDocument.getNestedUpdateList().isEmpty()) { + DataResult update; - if (!updateOperation.isEmpty()) { - Bson bsonQuery = Filters.eq(PRIVATE_UID, clinicalAnalysisUid); + if (!updateOperation.isEmpty()) { + logger.debug("Update clinical analysis. Query: {}, Update: {}", bsonQuery.toBsonDocument(), updateDocument); + update = clinicalCollection.update(clientSession, bsonQuery, updateOperation, null); - logger.debug("Update clinical analysis. Query: {}, Update: {}", bsonQuery.toBsonDocument(), updateDocument); - update = clinicalCollection.update(clientSession, bsonQuery, updateOperation, null); + if (update.getNumMatches() == 0) { + throw CatalogDBException.uidNotFound("Clinical Analysis", clinicalAnalysisUid); + } + if (update.getNumUpdated() == 0) { + events.add(new Event(Event.Type.WARNING, clinicalAnalysisId, "Clinical Analysis was already updated")); + } - if (update.getNumMatches() == 0) { - throw CatalogDBException.uidNotFound("Clinical Analysis", clinicalAnalysisUid); - } - if (update.getNumUpdated() == 0) { - events.add(new Event(Event.Type.WARNING, clinicalAnalysisId, "Clinical Analysis was already updated")); - } + if (parameters.getBoolean(LOCKED.key())) { + // Propagate locked value to Interpretations + logger.debug("Propagating case lock to all the Interpretations"); + dbAdaptorFactory.getInterpretationDBAdaptor().propagateLockedFromClinicalAnalysis(clientSession, clinical, + parameters.getBoolean(LOCKED.key())); + } - if (parameters.getBoolean(LOCKED.key())) { - // Propagate locked value to Interpretations - logger.debug("Propagating case lock to all the Interpretations"); - dbAdaptorFactory.getInterpretationDBAdaptor().propagateLockedFromClinicalAnalysis(clientSession, clinical, - parameters.getBoolean(LOCKED.key())); + logger.debug("Clinical Analysis {} successfully updated", clinicalAnalysisId); } - logger.debug("Clinical Analysis {} successfully updated", clinicalAnalysisId); - } - - if (!updateDocument.getNestedUpdateList().isEmpty()) { - for (NestedArrayUpdateDocument nestedDocument : updateDocument.getNestedUpdateList()) { + if (!updateDocument.getNestedUpdateList().isEmpty()) { + // Nested documents are used to update reports + for (NestedArrayUpdateDocument nestedDocument : updateDocument.getNestedUpdateList()) { + Bson tmpBsonQuery = parseQuery(nestedDocument.getQuery().append(QueryParams.UID.key(), clinicalAnalysisUid)); + logger.debug("Update nested element from Clinical Analysis. Query: {}, Update: {}", + tmpBsonQuery.toBsonDocument(), nestedDocument.getSet()); + update = clinicalCollection.update(clientSession, tmpBsonQuery, nestedDocument.getSet(), null); - Bson bsonQuery = parseQuery(nestedDocument.getQuery().append(QueryParams.UID.key(), clinicalAnalysisUid)); - logger.debug("Update nested element from Clinical Analysis. Query: {}, Update: {}", - bsonQuery.toBsonDocument(), nestedDocument.getSet()); - - update = clinicalCollection.update(clientSession, bsonQuery, nestedDocument.getSet(), null); - - if (update.getNumMatches() == 0) { - throw CatalogDBException.uidNotFound("Clinical Analysis", clinicalAnalysisUid); + if (update.getNumMatches() == 0) { + throw CatalogDBException.uidNotFound("Clinical Analysis", clinicalAnalysisUid); + } } } - } - } else if (result.getNumUpdated() == 0) { - throw new CatalogDBException("Nothing to update"); - } + } else if (result.getNumUpdated() == 0) { + throw new CatalogDBException("Nothing to update"); + } - return endWrite(tmpStartTime, 1, 1, events); + return endWrite(tmpStartTime, 1, 1, events); + }, null, null); } @Override @@ -359,22 +368,24 @@ OpenCGAResult transactionalUpdate(ClientSession clientSession, Document updateOperation = updateDocument.toFinalUpdateDocument(); if (!updateOperation.isEmpty()) { - logger.debug("Update clinical analysis. Query: {}, Update: {}", query.toBsonDocument(), updateDocument); - DataResult update = clinicalCollection.update(clientSession, query, updateOperation, null); - - if (updateDocument.getSet().getBoolean(LOCKED.key(), false)) { - // Propagate locked value to Interpretations - logger.debug("Propagating case lock to all the Interpretations"); - MongoDBIterator iterator = clinicalCollection.iterator(clientSession, query, null, clinicalConverter, - ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS); - while (iterator.hasNext()) { - ClinicalAnalysis clinical = iterator.next(); - dbAdaptorFactory.getInterpretationDBAdaptor().propagateLockedFromClinicalAnalysis(clientSession, clinical, true); + return versionedMongoDBAdaptor.update(clientSession, query, entryList -> { + logger.debug("Update clinical analysis. Query: {}, Update: {}", query.toBsonDocument(), updateDocument); + DataResult update = clinicalCollection.update(clientSession, query, updateOperation, null); + + if (updateDocument.getSet().getBoolean(LOCKED.key(), false)) { + // Propagate locked value to Interpretations + logger.debug("Propagating case lock to all the Interpretations"); + MongoDBIterator iterator = clinicalCollection.iterator(clientSession, query, null, clinicalConverter, + ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS); + while (iterator.hasNext()) { + ClinicalAnalysis clinical = iterator.next(); + dbAdaptorFactory.getInterpretationDBAdaptor().propagateLockedFromClinicalAnalysis(clientSession, clinical, true); + } } - } - logger.debug("{} clinical analyses successfully updated", update.getNumUpdated()); - return endWrite(tmpStartTime, update.getNumMatches(), update.getNumUpdated(), Collections.emptyList()); + logger.debug("{} clinical analyses successfully updated", update.getNumUpdated()); + return endWrite(tmpStartTime, update.getNumMatches(), update.getNumUpdated(), Collections.emptyList()); + }, null, null); } else { throw new CatalogDBException("Nothing to update"); } @@ -412,7 +423,7 @@ UpdateDocument parseAndValidateUpdateParams(ObjectMap parameters, List privateDelete(ClientSession clientSession, ClinicalAnalysis cli } } + // Add Audit to ClinicalAnalysis + transactionalUpdate(clientSession, clinicalAnalysis, new ObjectMap(), Collections.emptyList(), clinicalAuditList, + QueryOptions.empty()); + + // And delete ClinicalAnalysis Query query = new Query() - .append(STUDY_UID.key(), clinicalAnalysis.getStudyUid()) + .append(QueryParams.STUDY_UID.key(), clinicalAnalysis.getStudyUid()) .append(UID.key(), clinicalAnalysis.getUid()); - OpenCGAResult result = nativeGet(clientSession, query, QueryOptions.empty()); - if (result.getNumResults() == 0) { - throw new CatalogDBException("Internal error: Clinical Analysis '" + clinicalAnalysis.getId() + "' not found."); - } - - String clinicalId = result.first().getString(QueryParams.ID.key()); - long clinicalUid = result.first().getLong(PRIVATE_UID); - long studyUid = result.first().getLong(PRIVATE_STUDY_UID); - - logger.debug("Deleting Clinical Analysis {} ({})", clinicalId, clinicalUid); - - // Delete any documents that might have been already deleted with that id - Bson bsonQuery = new Document() - .append(QueryParams.ID.key(), clinicalId) - .append(PRIVATE_STUDY_UID, studyUid); - deletedClinicalCollection.remove(clientSession, bsonQuery, new QueryOptions(MongoDBCollection.MULTI, true)); - - // Set status to DELETED - nestedPut(QueryParams.INTERNAL_STATUS.key(), getMongoDBDocument(new InternalStatus(InternalStatus.DELETED), "status"), - result.first()); - - // Add audit - List auditList = result.first().getList(AUDIT.key(), Document.class); - for (ClinicalAudit clinicalAudit : clinicalAuditList) { - auditList.add(getMongoDBDocument(clinicalAudit, "ClinicalAudit")); - } - result.first().put(AUDIT.key(), auditList); - - // Insert the document in the DELETE collection - deletedClinicalCollection.insert(clientSession, replaceDotsInKeys(result.first()), null); - logger.debug("Inserted Clinical Analysis uid '{}' in DELETE collection", clinicalUid); - - // Remove the document from the main Clinical collection - bsonQuery = parseQuery(new Query(QueryParams.UID.key(), clinicalUid)); - DataResult remove = clinicalCollection.remove(clientSession, bsonQuery, null); - if (remove.getNumMatches() == 0) { - throw new CatalogDBException("Clinical Analysis " + clinicalId + " not found"); - } - if (remove.getNumDeleted() == 0) { - throw new CatalogDBException("Clinical Analysis " + clinicalId + " could not be deleted"); - } + Bson bsonQuery = parseQuery(query); + versionedMongoDBAdaptor.delete(clientSession, bsonQuery); - logger.debug("Clinical Analysis {}({}) deleted", clinicalId, clinicalUid); + logger.debug("Clinical Analysis {}({}) deleted", clinicalAnalysis.getId(), clinicalAnalysis.getUid()); return endWrite(tmpStartTime, 1, 0, 0, 1, Collections.emptyList()); } @@ -968,12 +945,8 @@ private MongoDBIterator getMongoCursor(ClientSession clientSession, Qu qOptions = removeInnerProjections(qOptions, QueryParams.SECONDARY_INTERPRETATIONS.key()); logger.debug("Clinical analysis query : {}", bson.toBsonDocument()); - - if (!query.getBoolean(QueryParams.DELETED.key())) { - return clinicalCollection.iterator(clientSession, bson, null, null, qOptions); - } else { - return deletedClinicalCollection.iterator(clientSession, bson, null, null, qOptions); - } + MongoDBCollection collection = getQueryCollection(query, clinicalCollection, archiveClinicalCollection, deletedClinicalCollection); + return collection.iterator(clientSession, bson, null, null, qOptions); } @Override @@ -1105,7 +1078,7 @@ ClinicalAnalysis insert(ClientSession clientSession, long studyId, ClinicalAnaly clinicalDocument.put(PRIVATE_DUE_DATE, TimeUtils.toDate(clinicalAnalysis.getDueDate())); logger.debug("Inserting ClinicalAnalysis '{}' ({})...", clinicalAnalysis.getId(), clinicalAnalysis.getUid()); - clinicalCollection.insert(clientSession, clinicalDocument, null); + versionedMongoDBAdaptor.insert(clientSession, clinicalDocument); logger.debug("ClinicalAnalysis '{}' successfully inserted", clinicalAnalysis.getId()); return clinicalAnalysis; @@ -1251,7 +1224,7 @@ void updateClinicalAnalysisPanelReferences(ClientSession clientSession, Panel pa Query query = new Query() .append(STUDY_UID.key(), panel.getStudyUid()) .append(PANELS_UID.key(), panel.getUid()) - .append(PANEL_LOCK.key(), false) + .append(PANEL_LOCKED.key(), false) .append(LOCKED.key(), false); QueryOptions include = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( PANELS_UID.key(), @@ -1333,12 +1306,18 @@ private Bson parseQuery(Query query, Document extraQuery, String user) queryCopy.remove(ParamConstants.ACL_PARAM); } + if ("all".equalsIgnoreCase(queryCopy.getString(QueryParams.VERSION.key()))) { + queryCopy.put(Constants.ALL_VERSIONS, true); + queryCopy.remove(QueryParams.VERSION.key()); + } + boolean uidVersionQueryFlag = versionedMongoDBAdaptor.generateUidVersionQuery(queryCopy, andBsonList); + for (Map.Entry entry : queryCopy.entrySet()) { String key = entry.getKey().split("\\.")[0]; 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())) { + if (Constants.ALL_VERSIONS.equals(entry.getKey()) || Constants.PRIVATE_ANNOTATION_PARAM_TYPES.equals(entry.getKey())) { continue; } throw new CatalogDBException("Unexpected parameter " + entry.getKey() + ". The parameter does not exist or cannot be " @@ -1384,7 +1363,7 @@ private Bson parseQuery(Query query, Document extraQuery, String user) case INTERNAL_STATUS: case INTERNAL_STATUS_ID: // Convert the status to a positive status - queryCopy.put(queryParam.key(), InternalStatus.getPositiveStatus(ClinicalAnalysisStatus.STATUS_LIST, + queryCopy.put(queryParam.key(), InternalStatus.getPositiveStatus(InternalStatus.STATUS_LIST, queryCopy.getString(queryParam.key()))); addAutoOrQuery(INTERNAL_STATUS_ID.key(), queryParam.key(), queryCopy, INTERNAL_STATUS_ID.type(), andBsonList); break; @@ -1394,11 +1373,14 @@ private Bson parseQuery(Query query, Document extraQuery, String user) queryCopy.get(Constants.PRIVATE_ANNOTATION_PARAM_TYPES, ObjectMap.class)); } break; + case SNAPSHOT: + addAutoOrQuery(RELEASE_FROM_VERSION, queryParam.key(), queryCopy, queryParam.type(), andBsonList); + break; // Other parameter that can be queried. case ID: case UUID: case TYPE: - case PANEL_LOCK: + case PANEL_LOCKED: case LOCKED: case FILES_UID: case PROBAND_UID: @@ -1411,6 +1393,7 @@ private Bson parseQuery(Query query, Document extraQuery, String user) case PRIORITY_ID: case FLAGS_ID: case QUALITY_CONTROL_SUMMARY: + case VERSION: case RELEASE: case COMMENTS_DATE: addAutoOrQuery(queryParam.key(), queryParam.key(), queryCopy, queryParam.type(), andBsonList); @@ -1424,6 +1407,17 @@ private Bson parseQuery(Query query, Document extraQuery, String user) } } + // If the user doesn't look for a concrete version... + if (!uidVersionQueryFlag && !queryCopy.getBoolean(Constants.ALL_VERSIONS) && !queryCopy.containsKey(QueryParams.VERSION.key())) { + if (queryCopy.containsKey(QueryParams.SNAPSHOT.key())) { + // If the user looks for anything from some release, we will try to find the latest from the release (snapshot) + andBsonList.add(Filters.eq(LAST_OF_RELEASE, true)); + } else { + // Otherwise, we will always look for the latest version + andBsonList.add(Filters.eq(LAST_OF_VERSION, true)); + } + } + if (annotationDocument != null && !annotationDocument.isEmpty()) { andBsonList.add(annotationDocument); } 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 f15a2ac5739..0c833de52ed 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 @@ -433,7 +433,7 @@ private UpdateDocument parseAndValidateUpdateParams(ClientSession clientSession, String[] booleanParams = {LOCKED.key()}; filterBooleanParams(parameters, document.getSet(), booleanParams); - String[] acceptedParams = {QueryParams.DESCRIPTION.key()}; + String[] acceptedParams = {QueryParams.NAME.key(), QueryParams.DESCRIPTION.key()}; filterStringParams(parameters, document.getSet(), acceptedParams); if (StringUtils.isNotEmpty(parameters.getString(QueryParams.CREATION_DATE.key()))) { @@ -1136,6 +1136,7 @@ protected Bson parseQuery(Query query) throws CatalogDBException { break; // Other parameter that can be queried. case ID: + case NAME: case UUID: case PANELS_UID: case RELEASE: diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java index 10e84541343..32c10c362f7 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/MongoDBAdaptor.java @@ -60,6 +60,7 @@ public abstract class MongoDBAdaptor extends AbstractDBAdaptor { static final String PRIVATE_PROJECT_UUID = PRIVATE_PROJECT + '.' + PRIVATE_UUID; public static final String PRIVATE_STUDY_UID = "studyUid"; public static final String VERSION = "version"; + public static final String RELEASE = "release"; static final String FILTER_ROUTE_STUDIES = "projects.studies."; static final String FILTER_ROUTE_COHORTS = "projects.studies.cohorts."; diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java index fbc54430a22..9884bbccc6c 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/OrganizationMongoDBAdaptorFactory.java @@ -48,6 +48,7 @@ public class OrganizationMongoDBAdaptorFactory { public static final String INDIVIDUAL_ARCHIVE_COLLECTION = "individual_archive"; public static final String FAMILY_ARCHIVE_COLLECTION = "family_archive"; public static final String PANEL_ARCHIVE_COLLECTION = "panel_archive"; + public static final String CLINICAL_ANALYSIS_ARCHIVE_COLLECTION = "clinical_archive"; public static final String INTERPRETATION_ARCHIVE_COLLECTION = "interpretation_archive"; public static final String DELETED_NOTE_COLLECTION = "note_deleted"; @@ -89,6 +90,7 @@ public class OrganizationMongoDBAdaptorFactory { INDIVIDUAL_ARCHIVE_COLLECTION, FAMILY_ARCHIVE_COLLECTION, PANEL_ARCHIVE_COLLECTION, + CLINICAL_ANALYSIS_ARCHIVE_COLLECTION, INTERPRETATION_ARCHIVE_COLLECTION, DELETED_NOTE_COLLECTION, @@ -176,6 +178,7 @@ public OrganizationMongoDBAdaptorFactory(String organizationId, MongoDataStoreMa MongoDBCollection individualArchivedCollection = mongoDataStore.getCollection(INDIVIDUAL_ARCHIVE_COLLECTION); MongoDBCollection familyArchivedCollection = mongoDataStore.getCollection(FAMILY_ARCHIVE_COLLECTION); MongoDBCollection panelArchivedCollection = mongoDataStore.getCollection(PANEL_ARCHIVE_COLLECTION); + MongoDBCollection clinicalArchivedCollection = mongoDataStore.getCollection(CLINICAL_ANALYSIS_ARCHIVE_COLLECTION); MongoDBCollection interpretationArchivedCollection = mongoDataStore.getCollection(INTERPRETATION_ARCHIVE_COLLECTION); MongoDBCollection deletedNotesCollection = mongoDataStore.getCollection(DELETED_NOTE_COLLECTION); @@ -211,7 +214,8 @@ public OrganizationMongoDBAdaptorFactory(String organizationId, MongoDataStoreMa userDBAdaptor = new UserMongoDBAdaptor(userCollection, deletedUserCollection, configuration, this); cohortDBAdaptor = new CohortMongoDBAdaptor(cohortCollection, deletedCohortCollection, configuration, this); panelDBAdaptor = new PanelMongoDBAdaptor(panelCollection, panelArchivedCollection, deletedPanelCollection, configuration, this); - clinicalDBAdaptor = new ClinicalAnalysisMongoDBAdaptor(clinicalCollection, deletedClinicalCollection, configuration, this); + clinicalDBAdaptor = new ClinicalAnalysisMongoDBAdaptor(clinicalCollection, clinicalArchivedCollection, deletedClinicalCollection, + configuration, this); interpretationDBAdaptor = new InterpretationMongoDBAdaptor(interpretationCollection, interpretationArchivedCollection, deletedInterpretationCollection, configuration, this); // metaDBAdaptor = new MetaMongoDBAdaptor(metaCollection, configuration, this); diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SnapshotVersionedMongoDBAdaptor.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SnapshotVersionedMongoDBAdaptor.java index a86ebb9cc36..c54c80df169 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SnapshotVersionedMongoDBAdaptor.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/db/mongodb/SnapshotVersionedMongoDBAdaptor.java @@ -137,6 +137,12 @@ DBIterator iterator(ClientSession session, Query query, QueryOptions options) } protected void insert(ClientSession session, Document document) { + // Versioning private parameters + document.put(VERSION, 1); + document.put(RELEASE_FROM_VERSION, Arrays.asList(document.getInteger(RELEASE))); + document.put(LAST_OF_VERSION, true); + document.put(LAST_OF_RELEASE, true); + String uuid = getClientSessionUuid(session); document.put(PRIVATE_TRANSACTION_ID, uuid); collection.insert(session, document, QueryOptions.empty()); @@ -348,12 +354,17 @@ protected Document revertToVersion(ClientSession clientSession, long uid, int ve return document; } - protected void delete(ClientSession session, Bson query) { + protected void delete(ClientSession session, Bson query) throws CatalogDBException { // Remove any old documents from the "delete" collection matching the criteria deletedCollection.remove(session, query, QueryOptions.empty()); // Remove document from main collection - collection.remove(session, query, QueryOptions.empty()); + DataResult remove = collection.remove(session, query, QueryOptions.empty()); + if (remove.getNumDeleted() == 0) { + logger.error("Delete operation for '{}' could not be performed. Num matches: {}", query.toBsonDocument(), + remove.getNumMatches()); + throw new CatalogDBException("Delete operation could not be performed"); + } // Add versioned documents to "delete" collection InternalStatus internalStatus = new InternalStatus(InternalStatus.DELETED); 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 452748329d7..20b228aeed8 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 @@ -25,7 +25,6 @@ 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; import org.opencb.commons.datastore.core.Query; @@ -43,6 +42,7 @@ import org.opencb.opencga.catalog.models.InternalGetDataResult; import org.opencb.opencga.catalog.utils.*; import org.opencb.opencga.core.api.ParamConstants; +import org.opencb.opencga.core.common.GitRepositoryState; import org.opencb.opencga.core.common.JacksonUtils; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.Configuration; @@ -51,10 +51,7 @@ import org.opencb.opencga.core.models.JwtPayload; 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; +import org.opencb.opencga.core.models.common.*; import org.opencb.opencga.core.models.family.Family; import org.opencb.opencga.core.models.family.FamilyCreateParams; import org.opencb.opencga.core.models.file.File; @@ -277,7 +274,7 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis List events = new LinkedList<>(); - clinicalAnalysis.setStatus(ParamUtils.defaultObject(clinicalAnalysis.getStatus(), Status::new)); + clinicalAnalysis.setStatus(ParamUtils.defaultObject(clinicalAnalysis.getStatus(), ClinicalStatus::new)); clinicalAnalysis.setInternal(ClinicalAnalysisInternal.init()); clinicalAnalysis.setDisorder(ParamUtils.defaultObject(clinicalAnalysis.getDisorder(), new Disorder("", "", "", Collections.emptyMap(), "", Collections.emptyList()))); @@ -591,10 +588,10 @@ public OpenCGAResult create(String studyStr, ClinicalAnalysis validateCustomPriorityParameters(clinicalAnalysis, clinicalConfiguration); validateCustomFlagParameters(clinicalAnalysis, clinicalConfiguration); validateCustomConsentParameters(clinicalAnalysis, clinicalConfiguration); - validateStatusParameter(clinicalAnalysis, clinicalConfiguration); + validateStatusParameter(clinicalAnalysis, clinicalConfiguration, userId, true); if (StringUtils.isNotEmpty(clinicalAnalysis.getStatus().getId())) { - List clinicalStatusValues = clinicalConfiguration.getStatus().get(clinicalAnalysis.getType()); + List clinicalStatusValues = clinicalConfiguration.getStatus(); for (ClinicalStatusValue clinicalStatusValue : clinicalStatusValues) { if (clinicalAnalysis.getStatus().getId().equals(clinicalStatusValue.getId())) { if (clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { @@ -802,17 +799,15 @@ private void fillResponsible(String organizationId, ClinicalResponsible responsi responsible.setEmail(ParamUtils.defaultString(responsible.getEmail(), result.first().getEmail())); } - private void validateStatusParameter(ClinicalAnalysis clinicalAnalysis, ClinicalAnalysisStudyConfiguration clinicalConfiguration) - throws CatalogException { + private void validateStatusParameter(ClinicalAnalysis clinicalAnalysis, ClinicalAnalysisStudyConfiguration clinicalConfiguration, + String userId, boolean initIfUndefined) throws CatalogException { // Status - if (clinicalConfiguration.getStatus() == null - || CollectionUtils.isEmpty(clinicalConfiguration.getStatus().get(clinicalAnalysis.getType()))) { - throw new CatalogException("Missing status configuration in study for type '" + clinicalAnalysis.getType() - + "'. Please add a proper set of valid statuses."); + if (CollectionUtils.isEmpty(clinicalConfiguration.getStatus())) { + throw new CatalogException("Missing status configuration in study. Please add a proper set of valid statuses."); } if (StringUtils.isNotEmpty(clinicalAnalysis.getStatus().getId())) { Map statusMap = new HashMap<>(); - for (ClinicalStatusValue status : clinicalConfiguration.getStatus().get(clinicalAnalysis.getType())) { + for (ClinicalStatusValue status : clinicalConfiguration.getStatus()) { statusMap.put(status.getId(), status); } if (!statusMap.containsKey(clinicalAnalysis.getStatus().getId())) { @@ -821,10 +816,26 @@ private void validateStatusParameter(ClinicalAnalysis clinicalAnalysis, Clinical } ClinicalStatusValue clinicalStatusValue = statusMap.get(clinicalAnalysis.getStatus().getId()); clinicalAnalysis.getStatus().setDescription(clinicalStatusValue.getDescription()); - clinicalAnalysis.getStatus().setDate(TimeUtils.getTime()); + clinicalAnalysis.getStatus().setType(clinicalStatusValue.getType()); } else if (clinicalAnalysis.getStatus().getId() == null) { - clinicalAnalysis.getStatus().setId(""); + if (initIfUndefined) { + // Look for first status of type NOT_STARTED + for (ClinicalStatusValue status : clinicalConfiguration.getStatus()) { + if (status.getType() == ClinicalStatusValue.ClinicalStatusType.NOT_STARTED) { + clinicalAnalysis.getStatus().setId(status.getId()); + clinicalAnalysis.getStatus().setDescription(status.getDescription()); + clinicalAnalysis.getStatus().setType(status.getType()); + break; + } + } + } else { + throw new CatalogException("Missing status id in clinical analysis"); + } } + clinicalAnalysis.getStatus().setDate(TimeUtils.getTime()); + clinicalAnalysis.getStatus().setVersion(GitRepositoryState.getInstance().getBuildVersion()); + clinicalAnalysis.getStatus().setCommit(GitRepositoryState.getInstance().getCommitId()); + clinicalAnalysis.getStatus().setAuthor(userId); } private void validateCustomConsentParameters(ClinicalAnalysis clinicalAnalysis, @@ -879,12 +890,11 @@ private void validateCustomFlagParameters(ClinicalAnalysis clinicalAnalysis, Cli throws CatalogException { // Flag definition if (CollectionUtils.isNotEmpty(clinicalAnalysis.getFlags())) { - if (CollectionUtils.isEmpty(clinicalConfiguration.getFlags().get(clinicalAnalysis.getType()))) { - throw new CatalogException("Missing flags configuration in study for type '" + clinicalAnalysis.getType() - + "'. Please add a proper set of valid priorities."); + if (CollectionUtils.isEmpty(clinicalConfiguration.getFlags())) { + throw new CatalogException("Missing flags configuration. Please add a proper set of valid flags."); } Map supportedFlags = new HashMap<>(); - for (FlagValue flagValue : clinicalConfiguration.getFlags().get(clinicalAnalysis.getType())) { + for (FlagValue flagValue : clinicalConfiguration.getFlags()) { supportedFlags.put(flagValue.getId(), flagValue); } @@ -898,8 +908,8 @@ private void validateCustomFlagParameters(ClinicalAnalysis clinicalAnalysis, Cli flag.setDescription(supportedFlags.get(flag.getId()).getDescription()); flag.setDate(TimeUtils.getTime()); } else { - throw new CatalogException("Flag '" + flag.getId() + "' not supported. Supported flags for Clinical Analyses of " - + "type '" + clinicalAnalysis.getType() + "' are: '" + String.join(", ", supportedFlags.keySet()) + "'."); + throw new CatalogException("Flag '" + flag.getId() + "' not supported. Supported flags for Clinical Analyses are: '" + + String.join(", ", supportedFlags.keySet()) + "'."); } } clinicalAnalysis.setFlags(new ArrayList<>(flagMap.values())); @@ -1393,15 +1403,65 @@ private OpenCGAResult update(String organizationId, Study stud } ClinicalAnalysisStudyConfiguration clinicalConfiguration = study.getInternal().getConfiguration().getClinical(); + // Get the clinical status that are CLOSED and DONE + Set closedStatus = new HashSet<>(); + Set doneStatus = new HashSet<>(); + for (ClinicalStatusValue clinicalStatusValue : clinicalConfiguration.getStatus()) { + if (clinicalStatusValue.getType().equals(ClinicalStatusValue.ClinicalStatusType.CLOSED)) { + closedStatus.add(clinicalStatusValue.getId()); + } else if (clinicalStatusValue.getType().equals(ClinicalStatusValue.ClinicalStatusType.DONE)) { + doneStatus.add(clinicalStatusValue.getId()); + } + } + + // If the current clinical analysis: + // - is locked or panelLocked + // - the user wants to update the locked or panelLocked status + // - the user wants to update the status to/from a done|closed status + boolean adminPermissionsChecked = false; + if (clinicalAnalysis.isLocked() || clinicalAnalysis.isPanelLocked() + || clinicalAnalysis.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED + || clinicalAnalysis.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.DONE + || updateParamsClone.getLocked() != null + || updateParams.getPanelLocked() != null + || (updateParams.getStatus() != null && (closedStatus.contains(updateParams.getStatus().getId()) + || doneStatus.contains(updateParams.getStatus().getId())))) { + authorizationManager.checkClinicalAnalysisPermission(organizationId, study.getUid(), clinicalAnalysis.getUid(), userId, + ClinicalAnalysisPermissions.ADMIN); + + // Current status is of type CLOSED + if (clinicalAnalysis.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { + // The only allowed action is to remove the CLOSED status + if (updateParams.getStatus() == null || StringUtils.isEmpty(updateParams.getStatus().getId())) { + throw new CatalogException("Cannot update a ClinicalAnalysis with a " + ClinicalStatusValue.ClinicalStatusType.CLOSED + + " status. You need to remove the " + ClinicalStatusValue.ClinicalStatusType.CLOSED + " status to be able " + + "to perform further updates on the ClinicalAnalysis."); + } else if (closedStatus.contains(updateParams.getStatus().getId())) { + // Users should be able to change from one CLOSED status to a different one but we should still control that no further + // modifications are made + if (parameters.size() > 1) { + throw new CatalogException("Cannot update a ClinicalAnalysis with a " + + ClinicalStatusValue.ClinicalStatusType.CLOSED + " status. You need to remove the " + + ClinicalStatusValue.ClinicalStatusType.CLOSED + " status to be able to perform further updates on " + + "the ClinicalAnalysis."); + } else if (clinicalAnalysis.getStatus().getId().equals(updateParams.getStatus().getId())) { + throw new CatalogException("ClinicalAnalysis already have the status '" + clinicalAnalysis.getStatus().getId() + + "' of type " + ClinicalStatusValue.ClinicalStatusType.CLOSED); + } + } + } + + adminPermissionsChecked = true; + } // Check permissions... // Only check write annotation permissions if the user wants to update the annotation sets - if (updateParamsClone.getAnnotationSets() != null) { + if (!adminPermissionsChecked && updateParamsClone.getAnnotationSets() != null) { authorizationManager.checkClinicalAnalysisPermission(organizationId, 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) { + if (!adminPermissionsChecked && ((parameters.size() == 1 + && !parameters.containsKey(SampleDBAdaptor.QueryParams.ANNOTATION_SETS.key())) || parameters.size() > 1)) { authorizationManager.checkClinicalAnalysisPermission(organizationId, study.getUid(), clinicalAnalysis.getUid(), userId, ClinicalAnalysisPermissions.WRITE); } @@ -1533,13 +1593,14 @@ private OpenCGAResult update(String organizationId, Study stud parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.FILES.key(), clinicalAnalysis.getFiles()); } - 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(updateParamsClone.getPanels()) && updateParamsClone.getPanelLocked() != null + && updateParamsClone.getPanelLocked()) { + throw new CatalogException("Updating the list of panels and setting '" + + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key() + "' to true at the same time is not allowed."); } if (CollectionUtils.isNotEmpty(updateParamsClone.getPanels())) { - if (clinicalAnalysis.isPanelLock() && (updateParamsClone.getPanelLock() == null || updateParamsClone.getPanelLock())) { + if (clinicalAnalysis.isPanelLocked() && (updateParamsClone.getPanelLocked() == null || updateParamsClone.getPanelLocked())) { throw new CatalogException("Cannot update panels from ClinicalAnalysis '" + clinicalAnalysis.getId() + "'. " + "'panelLocked' field from ClinicalAnalysis is set to true."); } @@ -1556,15 +1617,17 @@ private OpenCGAResult update(String organizationId, Study stud parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.PANELS.key(), panelResult.getResults()); } - if (updateParamsClone.getPanelLock() != null && updateParamsClone.getPanelLock() && !clinicalAnalysis.isPanelLock()) { + if (updateParamsClone.getPanelLocked() != null && updateParamsClone.getPanelLocked() && !clinicalAnalysis.isPanelLocked()) { // 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. Set panelIds = clinicalAnalysis.getPanels().stream().map(Panel::getId).collect(Collectors.toSet()); String exceptionMsgPrefix = "The interpretation '"; - String exceptionMsgSuffix = "' does not contain any of the case panels. 'panelLock' can only be set to true if all" + String exceptionMsgSuffix = "' does not contain any of the case panels. '" + + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key() + "' can only be set to true if all" + " all Interpretations contains a non-empty subset of the panels used by the case."; - String alternativeExceptionMsgSuffix = "' is using a panel not defined by the case. 'panelLock' can only be set to true if all" + String alternativeExceptionMsgSuffix = "' is using a panel not defined by the case. '" + + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key() + "' can only be set to true if all" + " all Interpretations contains a non-empty subset of the panels used by the case."; if (clinicalAnalysis.getInterpretation() != null) { if (CollectionUtils.isEmpty(clinicalAnalysis.getInterpretation().getPanels())) { @@ -1614,8 +1677,8 @@ private OpenCGAResult update(String organizationId, Study stud if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_STATUS.key())) { Map status = (Map) parameters.get(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_STATUS.key()); - if (!(status instanceof Map) || StringUtils.isEmpty(String.valueOf(status.get("name"))) - || !ClinicalAnalysisStatus.isValid(String.valueOf(status.get("name")))) { + if (!(status instanceof Map) || StringUtils.isEmpty(String.valueOf(status.get("id"))) + || !InternalStatus.isValid(String.valueOf(status.get("id")))) { throw new CatalogException("Missing or invalid status"); } } @@ -1659,12 +1722,12 @@ private OpenCGAResult update(String organizationId, Study stud parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.CONSENT.key(), clinicalAnalysis.getConsent()); } if (parameters.containsKey(ClinicalAnalysisDBAdaptor.QueryParams.STATUS.key())) { - clinicalAnalysis.setStatus(updateParamsClone.getStatus().toStatus()); - validateStatusParameter(clinicalAnalysis, clinicalConfiguration); + clinicalAnalysis.setStatus(updateParamsClone.getStatus().toClinicalStatus()); + validateStatusParameter(clinicalAnalysis, clinicalConfiguration, userId, false); parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.STATUS.key(), clinicalAnalysis.getStatus()); if (StringUtils.isNotEmpty(updateParamsClone.getStatus().getId())) { - List clinicalStatusValues = clinicalConfiguration.getStatus().get(clinicalAnalysis.getType()); + List clinicalStatusValues = clinicalConfiguration.getStatus(); for (ClinicalStatusValue clinicalStatusValue : clinicalStatusValues) { if (updateParamsClone.getStatus().getId().equals(clinicalStatusValue.getId())) { if (clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { @@ -2636,23 +2699,29 @@ public OpenCGAResult configureStudy(String studyStr, ClinicalAnalysisStudyConfig } } - private void validateClinicalStatus(Map> status, String field) + private void validateClinicalStatus(List status, String field) throws CatalogException { - if (status == null) { + if (CollectionUtils.isEmpty(status)) { throw CatalogParameterException.isNull(field); } - for (ClinicalAnalysis.Type value : ClinicalAnalysis.Type.values()) { - if (!status.containsKey(value)) { - throw new CatalogParameterException(field + ": Missing status values for ClinicalAnalysis type '" + value + "'"); + // Ensure there's at least one status id per status type + Map presentMap = new HashMap<>(); + for (ClinicalStatusValue.ClinicalStatusType value : ClinicalStatusValue.ClinicalStatusType.values()) { + // Init map + presentMap.put(value, false); + } + for (ClinicalStatusValue clinicalStatusValue : status) { + if (StringUtils.isEmpty(clinicalStatusValue.getId())) { + throw CatalogParameterException.isNull(field + ".id"); } - List statuses = status.get(value); - for (ClinicalStatusValue clinicalStatusValue : statuses) { - if (StringUtils.isEmpty(clinicalStatusValue.getId())) { - throw CatalogParameterException.isNull(field + ".{" + value + "}.id"); - } - if (clinicalStatusValue.getType() == null) { - throw CatalogParameterException.isNull(field + ".{" + value + "}.type"); - } + if (clinicalStatusValue.getType() == null) { + throw CatalogParameterException.isNull(field + ".type"); + } + presentMap.put(clinicalStatusValue.getType(), true); + } + for (Map.Entry entry : presentMap.entrySet()) { + if (!entry.getValue()) { + throw new CatalogException("Missing status values for ClinicalStatus type '" + entry.getKey() + "'"); } } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileManager.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileManager.java index 37be3aeeba2..386eb98cafa 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileManager.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/managers/FileManager.java @@ -3258,7 +3258,6 @@ private void checkCanDeleteFile(String organizationId, Study study, String fileI // We need to remove the reference to the transformed files and change their status from TRANSFORMED to NONE next.getInternal().getVariant().getIndex().setTransform(null); next.getInternal().getVariant().getIndex().getStatus().setId(VariantIndexStatus.NONE); - next.getInternal().getVariant().getIndex().getStatus().setName(VariantIndexStatus.NONE); break; case VariantIndexStatus.NONE: case VariantIndexStatus.DELETED: 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 95ae214a1d7..417978cef13 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 @@ -27,7 +27,6 @@ import org.opencb.biodata.models.clinical.interpretation.DiseasePanel; import org.opencb.biodata.models.clinical.interpretation.InterpretationMethod; import org.opencb.biodata.models.clinical.interpretation.InterpretationStats; -import org.opencb.biodata.models.common.Status; import org.opencb.commons.datastore.core.Event; import org.opencb.commons.datastore.core.ObjectMap; import org.opencb.commons.datastore.core.Query; @@ -45,6 +44,7 @@ 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.GitRepositoryState; import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.config.Configuration; import org.opencb.opencga.core.models.JwtPayload; @@ -69,18 +69,16 @@ public class InterpretationManager extends ResourceManager { public static final QueryOptions INCLUDE_CLINICAL_ANALYSIS = keepFieldsInQueryOptions(ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, - Arrays.asList(ClinicalAnalysisDBAdaptor.QueryParams.LOCKED.key(), ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCK.key())); + Arrays.asList(ClinicalAnalysisDBAdaptor.QueryParams.LOCKED.key(), ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key(), + ClinicalAnalysisDBAdaptor.QueryParams.STATUS.key())); public static final QueryOptions INCLUDE_INTERPRETATION_IDS = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( InterpretationDBAdaptor.QueryParams.ID.key(), InterpretationDBAdaptor.QueryParams.UID.key(), InterpretationDBAdaptor.QueryParams.UUID.key(), InterpretationDBAdaptor.QueryParams.CLINICAL_ANALYSIS_ID.key(), - InterpretationDBAdaptor.QueryParams.LOCKED.key(), + InterpretationDBAdaptor.QueryParams.LOCKED.key(), InterpretationDBAdaptor.QueryParams.STATUS.key(), InterpretationDBAdaptor.QueryParams.VERSION.key(), InterpretationDBAdaptor.QueryParams.STUDY_UID.key())); - public static final QueryOptions INCLUDE_INTERPRETATION_FINDING_IDS = new QueryOptions(QueryOptions.INCLUDE, Arrays.asList( - InterpretationDBAdaptor.QueryParams.ID.key(), InterpretationDBAdaptor.QueryParams.UID.key(), - InterpretationDBAdaptor.QueryParams.UUID.key(), InterpretationDBAdaptor.QueryParams.CLINICAL_ANALYSIS_ID.key(), - InterpretationDBAdaptor.QueryParams.VERSION.key(), InterpretationDBAdaptor.QueryParams.STUDY_UID.key(), - InterpretationDBAdaptor.QueryParams.LOCKED.key(), InterpretationDBAdaptor.QueryParams.PRIMARY_FINDINGS_ID.key(), - InterpretationDBAdaptor.QueryParams.SECONDARY_FINDINGS_ID.key())); + public static final QueryOptions INCLUDE_INTERPRETATION_FINDING_IDS = keepFieldsInQueryOptions(INCLUDE_INTERPRETATION_IDS, + Arrays.asList(InterpretationDBAdaptor.QueryParams.PRIMARY_FINDINGS_ID.key(), + InterpretationDBAdaptor.QueryParams.SECONDARY_FINDINGS_ID.key())); protected static Logger logger = LoggerFactory.getLogger(InterpretationManager.class); private UserManager userManager; private StudyManager studyManager; @@ -219,7 +217,7 @@ public OpenCGAResult create(String studyStr, String clinicalAnal try { QueryOptions clinicalOptions = keepFieldsInQueryOptions(ClinicalAnalysisManager.INCLUDE_CLINICAL_IDS, Arrays.asList(ClinicalAnalysisDBAdaptor.QueryParams.PANELS.key(), - ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCK.key(), + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key(), ClinicalAnalysisDBAdaptor.QueryParams.AUDIT.key(), ClinicalAnalysisDBAdaptor.QueryParams.INTERPRETATION_ID.key(), ClinicalAnalysisDBAdaptor.QueryParams.SECONDARY_INTERPRETATIONS_ID.key())); @@ -277,6 +275,7 @@ void validateNewInterpretation(String organizationId, Study study, Interpretatio } interpretation.setId(clinicalAnalysis.getId() + "." + count); + interpretation.setName(ParamUtils.defaultString(interpretation.getName(), interpretation.getId())); interpretation.setClinicalAnalysisId(clinicalAnalysis.getId()); @@ -290,7 +289,7 @@ void validateNewInterpretation(String organizationId, Study study, Interpretatio interpretation.setPrimaryFindings(ParamUtils.defaultObject(interpretation.getPrimaryFindings(), Collections.emptyList())); interpretation.setSecondaryFindings(ParamUtils.defaultObject(interpretation.getSecondaryFindings(), Collections.emptyList())); interpretation.setComments(ParamUtils.defaultObject(interpretation.getComments(), Collections.emptyList())); - interpretation.setStatus(ParamUtils.defaultObject(interpretation.getStatus(), Status::new)); + interpretation.setStatus(ParamUtils.defaultObject(interpretation.getStatus(), ClinicalStatus::new)); interpretation.setRelease(studyManager.getCurrentRelease(study)); interpretation.setVersion(1); interpretation.setAttributes(ParamUtils.defaultObject(interpretation.getAttributes(), Collections.emptyMap())); @@ -300,7 +299,7 @@ void validateNewInterpretation(String organizationId, Study study, Interpretatio if (CollectionUtils.isEmpty(interpretation.getPanels())) { interpretation.setPanels(clinicalAnalysis.getPanels()); } else { - if (clinicalAnalysis.isPanelLock()) { + if (clinicalAnalysis.isPanelLocked()) { // Check the panels are the same provided in the Clinical Analysis Map clinicalPanelIds = clinicalAnalysis.getPanels().stream() .collect(Collectors.toMap(DiseasePanel::getId, panel -> panel)); @@ -308,7 +307,8 @@ void validateNewInterpretation(String organizationId, Study study, Interpretatio List panelList = new ArrayList<>(clinicalPanelIds.size()); for (Panel panel : interpretation.getPanels()) { if (!clinicalPanelIds.containsKey(panel.getId())) { - throw new CatalogException("'panelLock' from ClinicalAnalysis is set to True. Please, leave list of panels empty" + throw new CatalogException("'" + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key() + + "' from ClinicalAnalysis is set to True. Please, leave list of panels empty" + " so they can be inherited or pass at least a subset of the panels defined in the Clinical Analysis."); } panelList.add(clinicalPanelIds.get(panel.getId())); @@ -331,9 +331,9 @@ void validateNewInterpretation(String organizationId, Study study, Interpretatio } // Validate status - validateStatusParameter(interpretation, clinicalAnalysis.getType(), interpretationConfiguration); + validateStatusParameter(interpretation, interpretationConfiguration, userId, true); if (StringUtils.isNotEmpty(interpretation.getStatus().getId())) { - List clinicalStatusValues = interpretationConfiguration.getStatus().get(clinicalAnalysis.getType()); + List clinicalStatusValues = interpretationConfiguration.getStatus(); for (ClinicalStatusValue clinicalStatusValue : clinicalStatusValues) { if (interpretation.getStatus().getId().equals(clinicalStatusValue.getId()) && clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { @@ -413,6 +413,16 @@ public OpenCGAResult clear(String studyStr, String clinicalAnaly String operationId = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); auditManager.initAuditBatch(operationId); + InterpretationStudyConfiguration interpretationConfiguration = + study.getInternal().getConfiguration().getClinical().getInterpretation(); + ClinicalStatusValue initStatus = null; + for (ClinicalStatusValue status : interpretationConfiguration.getStatus()) { + if (status.getType().equals(ClinicalStatusValue.ClinicalStatusType.NOT_STARTED)) { + initStatus = status; + break; + } + } + OpenCGAResult result = OpenCGAResult.empty(); for (String interpretationStr : interpretationList) { String interpretationId = interpretationStr; @@ -457,13 +467,13 @@ public OpenCGAResult clear(String studyStr, String clinicalAnaly actionMap.put(InterpretationDBAdaptor.QueryParams.PANELS.key(), ParamUtils.BasicUpdateAction.SET); QueryOptions options = new QueryOptions(Constants.ACTIONS, actionMap); - InterpretationUpdateParams params = new InterpretationUpdateParams("", new ClinicalAnalystParam(), + InterpretationUpdateParams params = new InterpretationUpdateParams("", "", new ClinicalAnalystParam(), InterpretationMethod.init(), null, null, Collections.emptyList(), Collections.emptyList(), clinicalAnalysis.getPanels() != null ? clinicalAnalysis.getPanels().stream() .map(p -> new PanelReferenceParam().setId(p.getId())).collect(Collectors.toList()) : null, - Collections.emptyList(), new StatusParam(), false, new ObjectMap()); + Collections.emptyList(), new StatusParam(initStatus.getId()), false, new ObjectMap()); ClinicalAudit clinicalAudit = new ClinicalAudit(userId, ClinicalAudit.Action.CLEAR_INTERPRETATION, "Clear interpretation '" + interpretationId + "'", TimeUtils.getTime()); @@ -629,89 +639,89 @@ public OpenCGAResult clear(String studyStr, String clinicalAnaly // } // } - public OpenCGAResult update(String studyStr, Query query, InterpretationUpdateParams updateParams, - ParamUtils.SaveInterpretationAs as, QueryOptions options, String token) - throws CatalogException { - return update(studyStr, query, updateParams, as, false, options, token); - } - - public OpenCGAResult update(String studyStr, Query query, InterpretationUpdateParams updateParams, - ParamUtils.SaveInterpretationAs as, boolean ignoreException, QueryOptions options, - String token) throws CatalogException { - options = ParamUtils.defaultObject(options, QueryOptions::new); - - JwtPayload tokenPayload = catalogManager.getUserManager().validateToken(token); - CatalogFqn studyFqn = CatalogFqn.extractFqnFromStudy(studyStr, tokenPayload); - String organizationId = studyFqn.getOrganizationId(); - String userId = tokenPayload.getUserId(organizationId); - Study study = studyManager.resolveId(studyStr, StudyManager.INCLUDE_CONFIGURATION, userId, organizationId); - - String operationId = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); - - ObjectMap updateMap; - try { - updateMap = updateParams != null ? updateParams.getUpdateMap() : null; - } catch (JsonProcessingException e) { - throw new CatalogException("Could not parse InterpretationUpdateParams object: " + e.getMessage(), e); - } - - ObjectMap auditParams = new ObjectMap() - .append("study", studyStr) - .append("query", query) - .append("updateParams", updateMap) - .append("as", as) - .append("ignoreException", ignoreException) - .append("options", options) - .append("token", token); - - Query finalQuery = new Query(ParamUtils.defaultObject(query, Query::new)); - fixQueryObject(organizationId, study, finalQuery, userId); - - DBIterator iterator; - try { - finalQuery.append(InterpretationDBAdaptor.QueryParams.STUDY_UID.key(), study.getUid()); - iterator = getInterpretationDBAdaptor(organizationId).iterator(study.getUid(), finalQuery, INCLUDE_INTERPRETATION_FINDING_IDS, - userId); - } catch (CatalogException e) { - auditManager.auditUpdate(organizationId, operationId, userId, Enums.Resource.INTERPRETATION, "", "", study.getId(), - study.getUuid(), auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); - throw e; - } - - auditManager.initAuditBatch(operationId); - OpenCGAResult result = OpenCGAResult.empty(); - while (iterator.hasNext()) { - Interpretation interpretation = iterator.next(); - try { - List clinicalAuditList = new ArrayList<>(); - clinicalAuditList.add(new ClinicalAudit(userId, ClinicalAudit.Action.UPDATE_INTERPRETATION, - "Update interpretation '" + interpretation.getId() + "'", TimeUtils.getTime())); - if (as != null) { - clinicalAuditList.add(new ClinicalAudit(userId, ClinicalAudit.Action.SWAP_INTERPRETATION, - "Swap interpretation '" + interpretation.getId() + "' to " + as, TimeUtils.getTime())); - } - OpenCGAResult writeResult = update(organizationId, study, interpretation, updateParams, clinicalAuditList, as, options, - userId); - auditManager.auditUpdate(organizationId, operationId, userId, Enums.Resource.INTERPRETATION, interpretation.getId(), - interpretation.getUuid(), study.getId(), study.getUuid(), auditParams, - new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); - - result.append(writeResult); - } catch (CatalogException e) { - Event event = new Event(Event.Type.ERROR, interpretation.getId(), e.getMessage()); - result.getEvents().add(event); - result.setNumErrors(result.getNumErrors() + 1); - - logger.error("Cannot update interpretation {}: {}", interpretation.getId(), e.getMessage(), e); - auditManager.auditUpdate(organizationId, operationId, userId, Enums.Resource.INTERPRETATION, interpretation.getId(), - interpretation.getUuid(), study.getId(), study.getUuid(), auditParams, - new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); - } - } - auditManager.finishAuditBatch(organizationId, operationId); - - return endResult(result, ignoreException); - } +// public OpenCGAResult update(String studyStr, Query query, InterpretationUpdateParams updateParams, +// ParamUtils.SaveInterpretationAs as, QueryOptions options, String token) +// throws CatalogException { +// return update(studyStr, query, updateParams, as, false, options, token); +// } +// +// public OpenCGAResult update(String studyStr, Query query, InterpretationUpdateParams updateParams, +// ParamUtils.SaveInterpretationAs as, boolean ignoreException, QueryOptions options, +// String token) throws CatalogException { +// options = ParamUtils.defaultObject(options, QueryOptions::new); +// +// JwtPayload tokenPayload = catalogManager.getUserManager().validateToken(token); +// CatalogFqn studyFqn = CatalogFqn.extractFqnFromStudy(studyStr, tokenPayload); +// String organizationId = studyFqn.getOrganizationId(); +// String userId = tokenPayload.getUserId(organizationId); +// Study study = studyManager.resolveId(studyStr, StudyManager.INCLUDE_CONFIGURATION, userId, organizationId); +// +// String operationId = UuidUtils.generateOpenCgaUuid(UuidUtils.Entity.AUDIT); +// +// ObjectMap updateMap; +// try { +// updateMap = updateParams != null ? updateParams.getUpdateMap() : null; +// } catch (JsonProcessingException e) { +// throw new CatalogException("Could not parse InterpretationUpdateParams object: " + e.getMessage(), e); +// } +// +// ObjectMap auditParams = new ObjectMap() +// .append("study", studyStr) +// .append("query", query) +// .append("updateParams", updateMap) +// .append("as", as) +// .append("ignoreException", ignoreException) +// .append("options", options) +// .append("token", token); +// +// Query finalQuery = new Query(ParamUtils.defaultObject(query, Query::new)); +// fixQueryObject(organizationId, study, finalQuery, userId); +// +// DBIterator iterator; +// try { +// finalQuery.append(InterpretationDBAdaptor.QueryParams.STUDY_UID.key(), study.getUid()); +// iterator = getInterpretationDBAdaptor(organizationId).iterator(study.getUid(), finalQuery, INCLUDE_INTERPRETATION_FINDING_IDS, +// userId); +// } catch (CatalogException e) { +// auditManager.auditUpdate(organizationId, operationId, userId, Enums.Resource.INTERPRETATION, "", "", study.getId(), +// study.getUuid(), auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); +// throw e; +// } +// +// auditManager.initAuditBatch(operationId); +// OpenCGAResult result = OpenCGAResult.empty(); +// while (iterator.hasNext()) { +// Interpretation interpretation = iterator.next(); +// try { +// List clinicalAuditList = new ArrayList<>(); +// clinicalAuditList.add(new ClinicalAudit(userId, ClinicalAudit.Action.UPDATE_INTERPRETATION, +// "Update interpretation '" + interpretation.getId() + "'", TimeUtils.getTime())); +// if (as != null) { +// clinicalAuditList.add(new ClinicalAudit(userId, ClinicalAudit.Action.SWAP_INTERPRETATION, +// "Swap interpretation '" + interpretation.getId() + "' to " + as, TimeUtils.getTime())); +// } +// OpenCGAResult writeResult = update(organizationId, study, interpretation, updateParams, clinicalAuditList, as, options, +// userId); +// auditManager.auditUpdate(organizationId, operationId, userId, Enums.Resource.INTERPRETATION, interpretation.getId(), +// interpretation.getUuid(), study.getId(), study.getUuid(), auditParams, +// new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS)); +// +// result.append(writeResult); +// } catch (CatalogException e) { +// Event event = new Event(Event.Type.ERROR, interpretation.getId(), e.getMessage()); +// result.getEvents().add(event); +// result.setNumErrors(result.getNumErrors() + 1); +// +// logger.error("Cannot update interpretation {}: {}", interpretation.getId(), e.getMessage(), e); +// auditManager.auditUpdate(organizationId, operationId, userId, Enums.Resource.INTERPRETATION, interpretation.getId(), +// interpretation.getUuid(), study.getId(), study.getUuid(), auditParams, +// new AuditRecord.Status(AuditRecord.Status.Result.ERROR, e.getError())); +// } +// } +// auditManager.finishAuditBatch(organizationId, operationId); +// +// return endResult(result, ignoreException); +// } public OpenCGAResult update(String studyStr, String clinicalAnalysisId, String intepretationId, InterpretationUpdateParams updateParams, ParamUtils.SaveInterpretationAs as, @@ -910,17 +920,89 @@ private OpenCGAResult update(String organizationId, Study study, Interpretation InterpretationStudyConfiguration interpretationConfiguration = study.getInternal().getConfiguration().getClinical().getInterpretation(); + ObjectMap parameters = new ObjectMap(); + if (updateParams != null) { + try { + parameters = updateParams.getUpdateMap(); + } catch (JsonProcessingException e) { + throw new CatalogException("Could not parse InterpretationUpdateParams object: " + e.getMessage(), e); + } + } else { + throw new CatalogException("Missing interpretation update parameters"); + } + Map actionMap = options.getMap(Constants.ACTIONS); // Check if user has permissions to write clinical analysis ClinicalAnalysis clinicalAnalysis = catalogManager.getClinicalAnalysisManager().internalGet(organizationId, study.getUid(), interpretation.getClinicalAnalysisId(), INCLUDE_CLINICAL_ANALYSIS, userId).first(); - authorizationManager.checkClinicalAnalysisPermission(organizationId, study.getUid(), clinicalAnalysis.getUid(), userId, - ClinicalAnalysisPermissions.WRITE); +// if (clinicalAnalysis.isLocked()) { +// throw new CatalogException("Could not update the Interpretation. Case is locked so no further modifications can be made to" +// + " the Interpretation."); +// } + if (clinicalAnalysis.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { + throw new CatalogException("Cannot update the Interpretation. Case status is " + ClinicalStatusValue.ClinicalStatusType.CLOSED); + } + + InterpretationStudyConfiguration interpretationStudyConfiguration = study.getInternal().getConfiguration().getClinical() + .getInterpretation(); + // Get the interpretation status that are CLOSED and DONE + Set closedStatus = new HashSet<>(); + Set doneStatus = new HashSet<>(); + for (ClinicalStatusValue clinicalStatusValue : interpretationStudyConfiguration.getStatus()) { + if (clinicalStatusValue.getType().equals(ClinicalStatusValue.ClinicalStatusType.CLOSED)) { + closedStatus.add(clinicalStatusValue.getId()); + } else if (clinicalStatusValue.getType().equals(ClinicalStatusValue.ClinicalStatusType.DONE)) { + doneStatus.add(clinicalStatusValue.getId()); + } + } + + // If the current interpretation: + // - is locked + // - the user wants to update the locked status + // - the user wants to update the status to/from a done|closed status + boolean adminPermissionsChecked = false; + if (interpretation.isLocked() + || interpretation.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED + || interpretation.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.DONE + || updateParams.getLocked() != null + || (updateParams.getStatus() != null && (closedStatus.contains(updateParams.getStatus().getId()) + || doneStatus.contains(updateParams.getStatus().getId())))) { + authorizationManager.checkClinicalAnalysisPermission(organizationId, study.getUid(), clinicalAnalysis.getUid(), userId, + ClinicalAnalysisPermissions.ADMIN); + + // Current status is of type CLOSED + if (interpretation.getStatus().getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { + // The only allowed action is to remove the CLOSED status + if (updateParams.getStatus() == null || StringUtils.isEmpty(updateParams.getStatus().getId())) { + throw new CatalogException("Cannot update a Interpretation with a " + ClinicalStatusValue.ClinicalStatusType.CLOSED + + " status. You need to remove the " + ClinicalStatusValue.ClinicalStatusType.CLOSED + " status to be able " + + "to perform further updates on the Interpretation."); + } else if (closedStatus.contains(updateParams.getStatus().getId())) { + // Users should be able to change from one CLOSED status to a different one but we should still control that no further + // modifications are made + if (parameters.size() > 1) { + throw new CatalogException("Cannot update a Interpretation with a " + ClinicalStatusValue.ClinicalStatusType.CLOSED + + " status. You need to remove the " + ClinicalStatusValue.ClinicalStatusType.CLOSED + " status to be able " + + "to perform further updates on the Interpretation."); + } else if (interpretation.getStatus().getId().equals(updateParams.getStatus().getId())) { + throw new CatalogException("Interpretation already have the status '" + interpretation.getStatus().getId() + + "' of type " + ClinicalStatusValue.ClinicalStatusType.CLOSED); + } + } + } - if (clinicalAnalysis.isLocked()) { - throw new CatalogException("Could not update the Interpretation. Case is locked so no further modifications can be made to" - + " the Interpretation."); + adminPermissionsChecked = true; + } + + if (!adminPermissionsChecked) { + authorizationManager.checkClinicalAnalysisPermission(organizationId, study.getUid(), clinicalAnalysis.getUid(), userId, + ClinicalAnalysisPermissions.WRITE); + } + + if (clinicalAnalysis.isLocked() && updateParams.getLocked() != null && !updateParams.getLocked()) { + throw new CatalogException("Could not unlock the Interpretation. Case is locked so unlocking the Interpretation is not" + + " allowed."); } List events = new ArrayList<>(); @@ -932,20 +1014,11 @@ private OpenCGAResult update(String organizationId, Study study, Interpretation ParamUtils.checkDateFormat(updateParams.getModificationDate(), InterpretationDBAdaptor.QueryParams.MODIFICATION_DATE.key()); } - ObjectMap parameters = new ObjectMap(); - if (updateParams != null) { - try { - parameters = updateParams.getUpdateMap(); - } catch (JsonProcessingException e) { - throw new CatalogException("Could not parse InterpretationUpdateParams object: " + e.getMessage(), e); - } - } - - if (!parameters.isEmpty() && interpretation.isLocked() - && parameters.getBoolean(InterpretationDBAdaptor.QueryParams.LOCKED.key(), true)) { - throw new CatalogException("Could not update the Interpretation. Interpretation '" + interpretation.getId() - + " is locked. Please, unlock it first."); - } +// if (!parameters.isEmpty() && interpretation.isLocked() +// && parameters.getBoolean(InterpretationDBAdaptor.QueryParams.LOCKED.key(), true)) { +// throw new CatalogException("Could not update the Interpretation. Interpretation '" + interpretation.getId() +// + " is locked. Please, unlock it first."); +// } if (updateParams != null && updateParams.getComments() != null && !updateParams.getComments().isEmpty()) { List comments = new ArrayList<>(updateParams.getComments().size()); @@ -982,15 +1055,15 @@ private OpenCGAResult update(String organizationId, Study study, Interpretation } if (updateParams != null && CollectionUtils.isNotEmpty(updateParams.getPanels())) { - if (clinicalAnalysis.isPanelLock()) { - throw new CatalogException("Updating panels from Interpretation is not allowed. 'panelLock' from ClinicalAnalysis is set " - + "to True."); + if (clinicalAnalysis.isPanelLocked()) { + throw new CatalogException("Updating panels from Interpretation is not allowed. '" + + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key() + "' from ClinicalAnalysis is set to True."); } // Validate and get panels List panelIds = updateParams.getPanels().stream().map(PanelReferenceParam::getId).collect(Collectors.toList()); Query query = new Query(PanelDBAdaptor.QueryParams.ID.key(), panelIds); - OpenCGAResult panelResult = + OpenCGAResult panelResult = getPanelDBAdaptor(organizationId).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"); @@ -1068,12 +1141,12 @@ private OpenCGAResult update(String organizationId, Study study, Interpretation } if (parameters.containsKey(InterpretationDBAdaptor.QueryParams.STATUS.key())) { - interpretation.setStatus(updateParams.getStatus().toStatus()); - validateStatusParameter(interpretation, clinicalAnalysis.getType(), interpretationConfiguration); + interpretation.setStatus(updateParams.getStatus().toClinicalStatus()); + validateStatusParameter(interpretation, interpretationConfiguration, userId, false); parameters.put(InterpretationDBAdaptor.QueryParams.STATUS.key(), interpretation.getStatus()); if (StringUtils.isNotEmpty(interpretation.getStatus().getId())) { - List clinicalStatusValues = interpretationConfiguration.getStatus().get(clinicalAnalysis.getType()); + List clinicalStatusValues = interpretationConfiguration.getStatus(); for (ClinicalStatusValue clinicalStatusValue : clinicalStatusValues) { if (interpretation.getStatus().getId().equals(clinicalStatusValue.getId()) && clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) { @@ -1128,8 +1201,9 @@ public OpenCGAResult revert(String studyStr, String clinicalAnal throw new CatalogException("Could not revert the Interpretation. Case is locked so no further modifications can be made to" + " the Interpretation."); } - if (clinicalAnalysis.isPanelLock()) { - throw new CatalogException("Could not revert the Interpretation. 'panelLock' is set to True, so no further modifications" + if (clinicalAnalysis.isPanelLocked()) { + throw new CatalogException("Could not revert the Interpretation. '" + + ClinicalAnalysisDBAdaptor.QueryParams.PANEL_LOCKED.key() + "' is set to True, so no further modifications" + " can be made to the Interpretation."); } @@ -1515,17 +1589,15 @@ protected void fixQueryObject(String organizationId, Study study, Query query, S } } - private void validateStatusParameter(Interpretation interpretation, ClinicalAnalysis.Type type, - InterpretationStudyConfiguration interpretationConfiguration) throws CatalogException { + private void validateStatusParameter(Interpretation interpretation, InterpretationStudyConfiguration interpretationConfiguration, + String userId, boolean initIfUndefined) throws CatalogException { // Status - if (interpretationConfiguration.getStatus() == null - || CollectionUtils.isEmpty(interpretationConfiguration.getStatus().get(type))) { - throw new CatalogException("Missing status configuration in study for type '" + type - + "'. Please add a proper set of valid statuses."); + if (CollectionUtils.isEmpty(interpretationConfiguration.getStatus())) { + throw new CatalogException("Missing status configuration in study. Please add a proper set of valid statuses."); } if (StringUtils.isNotEmpty(interpretation.getStatus().getId())) { Map statusMap = new HashMap<>(); - for (ClinicalStatusValue status : interpretationConfiguration.getStatus().get(type)) { + for (ClinicalStatusValue status : interpretationConfiguration.getStatus()) { statusMap.put(status.getId(), status); } if (!statusMap.containsKey(interpretation.getStatus().getId())) { @@ -1534,7 +1606,25 @@ private void validateStatusParameter(Interpretation interpretation, ClinicalAnal } ClinicalStatusValue clinicalStatusValue = statusMap.get(interpretation.getStatus().getId()); interpretation.getStatus().setDescription(clinicalStatusValue.getDescription()); - interpretation.getStatus().setDate(TimeUtils.getTime()); + interpretation.getStatus().setType(clinicalStatusValue.getType()); + } else { + if (initIfUndefined) { + // Look for first status of type NOT_STARTED + for (ClinicalStatusValue status : interpretationConfiguration.getStatus()) { + if (status.getType() == ClinicalStatusValue.ClinicalStatusType.NOT_STARTED) { + interpretation.getStatus().setId(status.getId()); + interpretation.getStatus().setDescription(status.getDescription()); + interpretation.getStatus().setType(status.getType()); + break; + } + } + } else { + throw new CatalogException("Missing status id in Interpretation"); + } } + interpretation.getStatus().setDate(TimeUtils.getTime()); + interpretation.getStatus().setVersion(GitRepositoryState.getInstance().getBuildVersion()); + interpretation.getStatus().setCommit(GitRepositoryState.getInstance().getCommitId()); + interpretation.getStatus().setAuthor(userId); } } diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationRuntimeException.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationRuntimeException.java new file mode 100644 index 00000000000..01d1d59d4a2 --- /dev/null +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationRuntimeException.java @@ -0,0 +1,13 @@ +package org.opencb.opencga.catalog.migration; + +public class MigrationRuntimeException extends IllegalArgumentException { + + public MigrationRuntimeException(String message) { + super(message); + } + + public MigrationRuntimeException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationTool.java b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationTool.java index 219e1178652..1a57bb6a239 100644 --- a/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationTool.java +++ b/opencga-catalog/src/main/java/org/opencb/opencga/catalog/migration/MigrationTool.java @@ -3,6 +3,8 @@ import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoCursor; import com.mongodb.client.model.IndexOptions; +import com.mongodb.client.model.InsertOneModel; +import com.mongodb.client.model.Projections; import com.mongodb.client.model.WriteModel; import org.apache.commons.lang3.StringUtils; import org.bson.Document; @@ -174,6 +176,25 @@ protected final void migrateCollection(MongoCollection inputCollection } } + protected void copyData(Bson query, String sourceCol, String targetCol) throws CatalogDBException { + MongoCollection sourceMongoCollection = getMongoCollection(sourceCol); + MongoCollection targetMongoCollection = getMongoCollection(targetCol); + copyData(query, sourceMongoCollection, targetMongoCollection); + } + + protected void copyData(Bson query, MongoCollection sourceCol, MongoCollection targetCol) { + // Move data to the new collection + logger.info("Copying data from {} to {}", sourceCol.getNamespace(), targetCol.getNamespace()); + migrateCollection(sourceCol, targetCol, query, Projections.exclude("_id"), + (document, bulk) -> bulk.add(new InsertOneModel<>(document))); + } + + protected void moveData(Bson query, MongoCollection sourceCol, MongoCollection targetCol) { + copyData(query, sourceCol, targetCol); + // Remove data from the source collection + sourceCol.deleteMany(query); + } + protected final void createIndex(String collection, Document index) throws CatalogDBException { createIndex(getMongoCollection(collection), index, new IndexOptions().background(true)); } diff --git a/opencga-catalog/src/main/resources/catalog-indexes.txt b/opencga-catalog/src/main/resources/catalog-indexes.txt index 557a660716a..fe7f43506d5 100644 --- a/opencga-catalog/src/main/resources/catalog-indexes.txt +++ b/opencga-catalog/src/main/resources/catalog-indexes.txt @@ -207,35 +207,36 @@ {"collections": ["panel", "panel_archive"], "fields": {"studyUid": 1, "release": 1, "_acl": 1}, "options": {}} {"collections": ["panel", "panel_archive"], "fields": {"internal.status.id": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"id": 1, "studyUid": 1}, "options": {"unique": true}} -{"collections": ["clinical"], "fields": {"uuid": 1}, "options": {"unique": true}} -{"collections": ["clinical"], "fields": {"uid": 1}, "options": {"unique": true}} -{"collections": ["clinical"], "fields": {"type": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"files.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"proband.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"proband.samples.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"family.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"family.members.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"family.members.samples.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"panels.uid": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"panelLock": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"locked": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"_dueDate": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"disorder.id": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"disorder.name": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"analyst.id": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"priority.id": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"flags.id": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"qualityControl.summary": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"_creationDate": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"_modificationDate": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"studyUid": 1, "_acl": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"status.id": 1, "studyUid": 1}, "options": {}} -{"collections": ["clinical"], "fields": {"internal.status.id": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"id": 1, "studyUid": 1}, "options": {"unique": true}} +{"collections": ["clinical", "clinical_archive"], "fields": {"uuid": 1}, "options": {"unique": true}} +{"collections": ["clinical", "clinical_archive"], "fields": {"uid": 1}, "options": {"unique": true}} +{"collections": ["clinical", "clinical_archive"], "fields": {"type": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"files.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"proband.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"proband.samples.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"family.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"family.members.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"family.members.samples.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"panels.uid": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"panelLocked": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"locked": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"_dueDate": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"disorder.id": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"disorder.name": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"analyst.id": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"priority.id": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"flags.id": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"qualityControl.summary": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"_creationDate": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"_modificationDate": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"studyUid": 1, "_acl": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"status.id": 1, "studyUid": 1}, "options": {}} +{"collections": ["clinical", "clinical_archive"], "fields": {"internal.status.id": 1, "studyUid": 1}, "options": {}} {"collections": ["interpretation", "interpretation_archive"], "fields": {"uuid": 1, "version": 1}, "options": {"unique": true}} {"collections": ["interpretation", "interpretation_archive"], "fields": {"uid": 1, "version": 1}, "options": {"unique": true}} {"collections": ["interpretation", "interpretation_archive"], "fields": {"id": 1, "version": 1, "studyUid": 1}, "options": {"unique": true}} +{"collections": ["interpretation", "interpretation_archive"], "fields": {"name": 1, "studyUid": 1}, "options": {}} {"collections": ["interpretation", "interpretation_archive"], "fields": {"clinicalAnalysisId": 1, "studyUid": 1}, "options": {}} {"collections": ["interpretation", "interpretation_archive"], "fields": {"analyst.id": 1, "studyUid": 1}, "options": {}} {"collections": ["interpretation", "interpretation_archive"], "fields": {"method.name": 1, "studyUid": 1}, "options": {}} 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 18a20c3667b..6d42dbc6fbd 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 @@ -25,7 +25,6 @@ import org.opencb.biodata.models.clinical.interpretation.ClinicalVariant; import org.opencb.biodata.models.clinical.interpretation.ClinicalVariantEvidence; import org.opencb.biodata.models.clinical.interpretation.InterpretationMethod; -import org.opencb.biodata.models.common.Status; import org.opencb.biodata.models.core.SexOntologyTermAnnotation; import org.opencb.biodata.models.variant.avro.VariantAvro; import org.opencb.biodata.models.variant.avro.VariantType; @@ -36,6 +35,7 @@ import org.opencb.opencga.TestParamConstants; import org.opencb.opencga.catalog.db.api.ClinicalAnalysisDBAdaptor; import org.opencb.opencga.catalog.db.api.InterpretationDBAdaptor; +import org.opencb.opencga.catalog.exceptions.CatalogAuthorizationException; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.models.ClinicalAnalysisLoadResult; import org.opencb.opencga.catalog.utils.Constants; @@ -61,9 +61,7 @@ import org.opencb.opencga.core.models.sample.Sample; 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.*; 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; @@ -159,7 +157,7 @@ private DataResult createDummyFamily() throws CatalogException { private DataResult createDummyEnvironment(boolean createFamily, boolean createDefaultInterpretation) throws CatalogException { ClinicalAnalysis clinicalAnalysis = new ClinicalAnalysis() - .setStatus(new Status().setId(ClinicalAnalysisStatus.READY_FOR_INTERPRETATION)) + .setStatus(new ClinicalStatus().setId("READY_FOR_INTERPRETATION")) .setId("analysis" + RandomStringUtils.randomAlphanumeric(3)) .setDescription("My description").setType(ClinicalAnalysis.Type.FAMILY) .setProband(new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2")))); @@ -205,25 +203,21 @@ public void createAndTestStatusIdIsNotNull() throws CatalogException { OpenCGAResult result = catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, false, INCLUDE_RESULT, ownerToken); - assertEquals("", result.first().getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.NOT_STARTED, result.first().getStatus().getType()); clinicalAnalysis = new ClinicalAnalysis() .setId("analysis" + RandomStringUtils.randomAlphanumeric(3)) - .setStatus(new Status(null, null, null, null)) + .setStatus(new ClinicalStatus()) .setDescription("My description").setType(ClinicalAnalysis.Type.FAMILY) .setProband(new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2")))) .setFamily(new Family().setId("family") .setMembers(Collections.singletonList(new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2")))))); result = catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, false, INCLUDE_RESULT, ownerToken); - assertEquals("", result.first().getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.NOT_STARTED, result.first().getStatus().getType()); - result = catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), - new ClinicalAnalysisUpdateParams().setStatus(new StatusParam(null)), INCLUDE_RESULT, ownerToken); - assertEquals("", result.first().getStatus().getId()); - - result = catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), - new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("")), INCLUDE_RESULT, ownerToken); - assertEquals("", result.first().getStatus().getId()); + String clinicalId = clinicalAnalysis.getId(); + assertThrows(CatalogException.class, () -> catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalId, + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam(null)), INCLUDE_RESULT, ownerToken)); } @Test @@ -592,6 +586,32 @@ public void updateClinicalAnalysisReportWithActions() throws CatalogException { } @Test + public void queryByVersionTest() throws CatalogException { + Individual individual = new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2"))); + catalogManager.getIndividualManager().create(studyFqn, individual, null, ownerToken); + + ClinicalComment comment = new ClinicalComment(orgOwnerUserId, "my comment", new ArrayList<>(), ""); + ClinicalAnalysis clinicalAnalysis = new ClinicalAnalysis() + .setId("analysis" + RandomStringUtils.randomAlphanumeric(3)) + .setDescription("My description").setType(ClinicalAnalysis.Type.SINGLE) + .setQualityControl(new ClinicalAnalysisQualityControl(ClinicalAnalysisQualityControl.QualityControlSummary.LOW, + Collections.singletonList(comment), Collections.emptyList())) + .setProband(individual); + + catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, true, INCLUDE_RESULT, ownerToken).first(); + catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams().setDescription("blabla"), null, ownerToken); + + ClinicalAnalysis case1 = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), null, ownerToken).first(); + assertEquals(2, case1.getVersion()); + assertEquals("blabla", case1.getDescription()); + + Query query = new Query(ParamConstants.CLINICAL_VERSION_PARAM, 1); + case1 = catalogManager.getClinicalAnalysisManager().get(studyFqn, Collections.singletonList(clinicalAnalysis.getId()), query, null, false, ownerToken).first(); + assertEquals(1, case1.getVersion()); + assertEquals(clinicalAnalysis.getDescription(), case1.getDescription()); + } + + @Test public void createAndUpdateClinicalAnalysisWithQualityControl() throws CatalogException, InterruptedException { Individual individual = new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2"))); catalogManager.getIndividualManager().create(studyFqn, individual, null, ownerToken); @@ -644,7 +664,7 @@ public void automaticallyLockCaseTest() throws CatalogException { .setProband(individual); OpenCGAResult clinical = catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken); - assertTrue(StringUtils.isEmpty(clinical.first().getStatus().getId())); + assertEquals(ClinicalStatusValue.ClinicalStatusType.NOT_STARTED, clinical.first().getStatus().getType()); assertFalse(clinical.first().isLocked()); clinical = catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), @@ -655,10 +675,11 @@ public void automaticallyLockCaseTest() throws CatalogException { clinicalAnalysis = new ClinicalAnalysis() .setId("Clinical2") .setType(ClinicalAnalysis.Type.SINGLE) - .setStatus(new ClinicalAnalysisStatus().setId("CLOSED")) + .setStatus(new ClinicalStatus().setId("CLOSED")) .setProband(individual); clinical = catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken); assertEquals("CLOSED", clinical.first().getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.CLOSED, clinical.first().getStatus().getType()); assertTrue(clinical.first().isLocked()); } @@ -932,6 +953,57 @@ public void updateClinicalAnalysis() throws CatalogException { assertEquals(attributes.get("b"), clinical.getAttributes().get("b")); } + @Test + public void versioningTest() throws CatalogException { + Individual individual = new Individual() + .setId("proband") + .setSamples(Collections.singletonList(new Sample().setId("sample"))); + catalogManager.getIndividualManager().create(studyFqn, individual, QueryOptions.empty(), ownerToken); + + List findingList = new ArrayList<>(); + VariantAvro variantAvro = new VariantAvro("id1", null, "chr2", 1, 2, "", "", "+", null, 1, null, null, null); + ClinicalVariantEvidence evidence = new ClinicalVariantEvidence().setInterpretationMethodName("method"); + ClinicalVariant cv1 = new ClinicalVariant(variantAvro, Collections.singletonList(evidence), null, null, new ClinicalDiscussion(), + ClinicalVariant.Status.NOT_REVIEWED, Collections.emptyList(), null); + findingList.add(cv1); + variantAvro = new VariantAvro("id2", null, "chr2", 1, 2, "", "", "+", null, 1, null, null, null); + ClinicalVariant cv2 = new ClinicalVariant(variantAvro, Collections.singletonList(evidence), null, null, new ClinicalDiscussion(), + ClinicalVariant.Status.NOT_REVIEWED, Collections.emptyList(), null); + findingList.add(cv2); + + ClinicalAnalysis clinicalAnalysis = new ClinicalAnalysis() + .setId("Clinical") + .setType(ClinicalAnalysis.Type.SINGLE) + .setProband(individual) + .setInterpretation(new Interpretation() + .setPrimaryFindings(findingList) + ); + ClinicalAnalysis clinical = catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken).first(); + assertEquals(1, clinical.getVersion()); + assertEquals(1, clinical.getInterpretation().getVersion()); + + // Update clinical analysis + clinical = catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() + .setDescription("my new description"), INCLUDE_RESULT, ownerToken).first(); + assertEquals("my new description", clinical.getDescription()); + assertEquals(2, clinical.getVersion()); + assertEquals(1, clinical.getInterpretation().getVersion()); + + // Update interpretation + Interpretation interpretation = catalogManager.getInterpretationManager().update(studyFqn, clinicalAnalysis.getId(), + clinical.getInterpretation().getId(), new InterpretationUpdateParams().setDescription("my new interpretation description"), + null, INCLUDE_RESULT, ownerToken).first(); + assertEquals("my new interpretation description", interpretation.getDescription()); + assertEquals(2, interpretation.getVersion()); + + // Get clinical Analysis + clinical = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); + assertEquals("my new description", clinical.getDescription()); + assertEquals(3, clinical.getVersion()); + assertEquals("my new interpretation description", clinical.getInterpretation().getDescription()); + assertEquals(2, clinical.getInterpretation().getVersion()); + } + @Test public void createRepeatedInterpretationPrimaryFindings() throws CatalogException { Individual individual = new Individual() @@ -1323,6 +1395,41 @@ public void updateSecondaryFindings() throws CatalogException { } } + @Test + public void updateStatusTest() throws CatalogException { + ClinicalAnalysis ca = createDummyEnvironment(true, false).first(); + + Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, ca.getId(), new Interpretation(), + ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); + + // Create 2 allowed statuses of type CLOSED + ClinicalAnalysisStudyConfiguration studyConfiguration = ClinicalAnalysisStudyConfiguration.defaultConfiguration(); + List statusValueList = new ArrayList<>(); + for (ClinicalStatusValue status : studyConfiguration.getStatus()) { + if (!status.getType().equals(ClinicalStatusValue.ClinicalStatusType.CLOSED)) { + statusValueList.add(status); + } + } + // Add two statuses of type CLOSED + statusValueList.add(new ClinicalStatusValue("closed1", "my desc", ClinicalStatusValue.ClinicalStatusType.CLOSED)); + statusValueList.add(new ClinicalStatusValue("closed2", "my desc", ClinicalStatusValue.ClinicalStatusType.CLOSED)); + studyConfiguration.setStatus(statusValueList); + catalogManager.getClinicalAnalysisManager().configureStudy(studyFqn, studyConfiguration, studyAdminToken1); + + // Update status to one of the new statuses + catalogManager.getClinicalAnalysisManager().update(studyFqn, ca.getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("closed1")), QueryOptions.empty(), studyAdminToken1); + ca = catalogManager.getClinicalAnalysisManager().get(studyFqn, ca.getId(), QueryOptions.empty(), studyAdminToken1).first(); + assertEquals("closed1", ca.getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.CLOSED, ca.getStatus().getType()); + + // Update status to the other new CLOSED status + catalogManager.getClinicalAnalysisManager().update(studyFqn, ca.getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("closed2")), QueryOptions.empty(), studyAdminToken1); + assertEquals("closed1", ca.getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.CLOSED, ca.getStatus().getType()); + } + @Test public void updateInterpretationComments() throws CatalogException { Individual individual = new Individual() @@ -1593,6 +1700,79 @@ public void updateClinicalAnalysisTest() throws CatalogException { assertEquals("URGENT", ca.getPriority().getId()); } + @Test + public void adminPermissionTest() throws CatalogException { + // Add ADMIN permissions to the user2 + catalogManager.getStudyManager().updateAcl(studyFqn, normalUserId2, + new StudyAclParams(StudyPermissions.Permissions.ADMIN_CLINICAL_ANALYSIS.name(), null), ParamUtils.AclAction.SET, ownerToken); + + DataResult dummyEnvironment = createDummyEnvironment(true, false); + + // Update ClinicalAnalysis with user1 + ClinicalAnalysis clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setDescription("My description"), INCLUDE_RESULT, normalToken1).first(); + assertEquals("My description", clinicalAnalysis.getDescription()); + + // Update ClinicalAnalysis with user2 + clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setDescription("My description 2"), INCLUDE_RESULT, normalToken2).first(); + assertEquals("My description 2", clinicalAnalysis.getDescription()); + + // Set status to CLOSED with user1 - FAIL + assertThrows(CatalogAuthorizationException.class, () -> + catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("CLOSED")), INCLUDE_RESULT, normalToken1) + ); + + // Set status to CLOSED with user2 - WORKS + clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("CLOSED")), INCLUDE_RESULT, normalToken2).first(); + assertEquals("CLOSED", clinicalAnalysis.getStatus().getId()); + assertTrue(clinicalAnalysis.isLocked()); + + // Unset status from CLOSED to other with user1 - FAIL + assertThrows(CatalogAuthorizationException.class, () -> + catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("READY_FOR_INTERPRETATION")), INCLUDE_RESULT, normalToken1) + ); + + // Edit CLOSED ClinicalAnalysis from user with ADMIN permission + assertThrows(CatalogException.class, () -> + catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setDescription("new description"), INCLUDE_RESULT, normalToken2) + ); + + // Send CLOSED status and edit description from CLOSED ClinicalAnalysis from user with ADMIN permission + assertThrows(CatalogException.class, () -> + catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("CLOSED")).setDescription("new description"), + INCLUDE_RESULT, normalToken2) + ); + + // Remove CLOSED status and edit description from CLOSED ClinicalAnalysis from user with ADMIN permission + clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("READY_FOR_INTERPRETATION")).setDescription("new description"), + INCLUDE_RESULT, normalToken2).first(); + assertEquals("READY_FOR_INTERPRETATION", clinicalAnalysis.getStatus().getId()); + assertEquals("new description", clinicalAnalysis.getDescription()); + + // Set status to CLOSED with study admin - WORKS + clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("CLOSED")), INCLUDE_RESULT, studyAdminToken1).first(); + assertEquals("CLOSED", clinicalAnalysis.getStatus().getId()); + + // Unset status from CLOSED to other with study admin - WORKS + clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("READY_FOR_INTERPRETATION")).setLocked(false), INCLUDE_RESULT, + studyAdminToken1).first(); + assertEquals("READY_FOR_INTERPRETATION", clinicalAnalysis.getStatus().getId()); + + // Update ClinicalAnalysis with user1 - WORKS + clinicalAnalysis = catalogManager.getClinicalAnalysisManager().update(studyFqn, dummyEnvironment.first().getId(), + new ClinicalAnalysisUpdateParams().setDescription("My description 3"), INCLUDE_RESULT, normalToken1).first(); + assertEquals("My description 3", clinicalAnalysis.getDescription()); + } + @Test public void updateCustomStatusTest() throws CatalogException { Study study = catalogManager.getStudyManager().get(studyFqn, QueryOptions.empty(), ownerToken).first(); @@ -1600,7 +1780,7 @@ public void updateCustomStatusTest() throws CatalogException { DataResult dummyEnvironment = createDummyEnvironment(true, false); - ClinicalStatusValue status = configuration.getStatus().get(dummyEnvironment.first().getType()).get(0); + ClinicalStatusValue status = configuration.getStatus().get(0); ClinicalAnalysisUpdateParams updateParams = new ClinicalAnalysisUpdateParams() .setStatus(new StatusParam(status.getId())); @@ -1645,9 +1825,9 @@ public void updateCustomFlagTest() throws CatalogException { DataResult dummyEnvironment = createDummyEnvironment(true, false); - FlagValue flag1 = configuration.getFlags().get(dummyEnvironment.first().getType()).get(1); - FlagValue flag2 = configuration.getFlags().get(dummyEnvironment.first().getType()).get(3); - FlagValue flag3 = configuration.getFlags().get(dummyEnvironment.first().getType()).get(4); + FlagValue flag1 = configuration.getFlags().get(1); + FlagValue flag2 = configuration.getFlags().get(3); + FlagValue flag3 = configuration.getFlags().get(4); ObjectMap actionMap = new ObjectMap(ClinicalAnalysisDBAdaptor.QueryParams.FLAGS.key(), ParamUtils.BasicUpdateAction.ADD); QueryOptions options = new QueryOptions(Constants.ACTIONS, actionMap); @@ -1684,8 +1864,8 @@ public void updateCustomFlagTest() throws CatalogException { } // Set other flags - flag1 = configuration.getFlags().get(dummyEnvironment.first().getType()).get(0); - flag2 = configuration.getFlags().get(dummyEnvironment.first().getType()).get(2); + flag1 = configuration.getFlags().get(0); + flag2 = configuration.getFlags().get(2); actionMap = new ObjectMap(ClinicalAnalysisDBAdaptor.QueryParams.FLAGS.key(), ParamUtils.BasicUpdateAction.SET); options = new QueryOptions(Constants.ACTIONS, actionMap); @@ -1768,7 +1948,7 @@ public void updateInterpretationCustomStatusTest() throws CatalogException { InterpretationStudyConfiguration configuration = study.getInternal().getConfiguration().getClinical().getInterpretation(); DataResult dummyEnvironment = createDummyEnvironment(true, true); - ClinicalStatusValue status = configuration.getStatus().get(dummyEnvironment.first().getType()).get(0); + ClinicalStatusValue status = configuration.getStatus().get(1); InterpretationUpdateParams updateParams = new InterpretationUpdateParams() .setStatus(new StatusParam(status.getId())); @@ -2581,35 +2761,35 @@ public void searchClinicalAnalysisByStatus() throws CatalogException { createDummyEnvironment(false, false); OpenCGAResult search = catalogManager.getClinicalAnalysisManager().search(studyFqn, - new Query(ParamConstants.STATUS_PARAM, ClinicalAnalysisStatus.DONE), + new Query(ParamConstants.STATUS_PARAM, "DONE"), new QueryOptions(QueryOptions.INCLUDE, ClinicalAnalysisDBAdaptor.QueryParams.PROBAND_ID.key()), ownerToken); assertEquals(0, search.getNumResults()); search = catalogManager.getClinicalAnalysisManager().search(studyFqn, - new Query(ParamConstants.STATUS_PARAM, ClinicalAnalysisStatus.READY_FOR_INTERPRETATION), + new Query(ParamConstants.STATUS_PARAM, "READY_FOR_INTERPRETATION"), new QueryOptions(), ownerToken); assertEquals(2, search.getNumResults()); for (ClinicalAnalysis result : search.getResults()) { - assertEquals(ClinicalAnalysisStatus.READY_FOR_INTERPRETATION, result.getStatus().getId()); + assertEquals("READY_FOR_INTERPRETATION", result.getStatus().getId()); } catalogManager.getClinicalAnalysisManager().update(studyFqn, search.first().getId(), - new ClinicalAnalysisUpdateParams().setStatus(new StatusParam(ClinicalAnalysisStatus.REJECTED)), QueryOptions.empty(), + new ClinicalAnalysisUpdateParams().setStatus(new StatusParam("REJECTED")), QueryOptions.empty(), ownerToken); search = catalogManager.getClinicalAnalysisManager().search(studyFqn, - new Query(ParamConstants.STATUS_PARAM, ClinicalAnalysisStatus.READY_FOR_INTERPRETATION), + new Query(ParamConstants.STATUS_PARAM, "READY_FOR_INTERPRETATION"), new QueryOptions(), ownerToken); assertEquals(1, search.getNumResults()); for (ClinicalAnalysis result : search.getResults()) { - assertEquals(ClinicalAnalysisStatus.READY_FOR_INTERPRETATION, result.getStatus().getId()); + assertEquals("READY_FOR_INTERPRETATION", result.getStatus().getId()); } search = catalogManager.getClinicalAnalysisManager().search(studyFqn, - new Query(ParamConstants.STATUS_PARAM, ClinicalAnalysisStatus.REJECTED), + new Query(ParamConstants.STATUS_PARAM, "REJECTED"), new QueryOptions(), ownerToken); assertEquals(1, search.getNumResults()); for (ClinicalAnalysis result : search.getResults()) { - assertEquals(ClinicalAnalysisStatus.REJECTED, result.getStatus().getId()); + assertEquals("REJECTED", result.getStatus().getId()); } } @@ -3131,7 +3311,7 @@ public void createClinicalAnalysisWithPanelsTest() throws CatalogException { assertNotNull(panel.getId()); assertNotNull(panel.getName()); } - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); } @Test @@ -3322,7 +3502,7 @@ public void updatePanelsAndPanelLockFromClinicalAnalysisTest() throws CatalogExc catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, true, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(0, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); Map actionMap = new HashMap<>(); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.PANELS.key(), ParamUtils.BasicUpdateAction.SET); @@ -3331,7 +3511,7 @@ public void updatePanelsAndPanelLockFromClinicalAnalysisTest() throws CatalogExc try { catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() .setPanels(panels.stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList())) - .setPanelLock(true), + .setPanelLocked(true), updateOptions, ownerToken); fail("Updating panels and setting panellock to true in one call should not be accepted"); } catch (CatalogException e) { @@ -3342,24 +3522,24 @@ public void updatePanelsAndPanelLockFromClinicalAnalysisTest() throws CatalogExc .setPanels(panels.stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList())), updateOptions, ownerToken); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), + .setPanelLocked(true), updateOptions, ownerToken); result = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken); assertEquals(1, result.getNumResults()); assertEquals(2, result.first().getPanels().size()); - assertTrue(result.first().isPanelLock()); + assertTrue(result.first().isPanelLocked()); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() .setPanels(Collections.singletonList(new PanelReferenceParam(panels.get(0).getId()))) - .setPanelLock(false), + .setPanelLocked(false), updateOptions, ownerToken); result = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken); assertEquals(1, result.getNumResults()); assertEquals(1, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), + .setPanelLocked(true), updateOptions, ownerToken); thrown.expect(CatalogException.class); thrown.expectMessage("panelLock"); @@ -3386,13 +3566,13 @@ public void updatePanelsAndPanelLockFromClinicalAnalysisWithInterpretationTest() catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, null, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(0, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); thrown.expect(CatalogException.class); thrown.expectMessage("not allowed"); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() .setPanels(panels.stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList())) - .setPanelLock(true), + .setPanelLocked(true), QueryOptions.empty(), ownerToken); } @@ -3414,7 +3594,7 @@ public void setPanelLockWithInterpretationWithNoPanelsTest() throws CatalogExcep catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, null, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(0, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() .setPanels(panels.stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList())), @@ -3426,7 +3606,7 @@ public void setPanelLockWithInterpretationWithNoPanelsTest() throws CatalogExcep thrown.expect(CatalogException.class); thrown.expectMessage("any of the case panels"); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), + .setPanelLocked(true), QueryOptions.empty(), ownerToken); } @@ -3448,7 +3628,7 @@ public void setPanelLockWithInterpretationWithPanelSubsetTest() throws CatalogEx catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, null, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(0, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() .setPanels(panels.stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList())), @@ -3462,15 +3642,15 @@ public void setPanelLockWithInterpretationWithPanelSubsetTest() throws CatalogEx .setPanels(Collections.singletonList(new PanelReferenceParam(panels.get(0).getId()))), null, QueryOptions.empty(), ownerToken); clinicalAnalysis = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); - assertFalse(clinicalAnalysis.isPanelLock()); + assertFalse(clinicalAnalysis.isPanelLocked()); assertEquals(2, clinicalAnalysis.getPanels().size()); assertEquals(1, clinicalAnalysis.getInterpretation().getPanels().size()); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), + .setPanelLocked(true), QueryOptions.empty(), ownerToken); clinicalAnalysis = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); - assertTrue(clinicalAnalysis.isPanelLock()); + assertTrue(clinicalAnalysis.isPanelLocked()); assertEquals(2, clinicalAnalysis.getPanels().size()); assertEquals(1, clinicalAnalysis.getInterpretation().getPanels().size()); } @@ -3493,7 +3673,7 @@ public void setPanelLockWithInterpretationWithDifferentPanelsTest() throws Catal catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, null, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(0, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() .setPanels(Collections.singletonList(new PanelReferenceParam(panels.get(0).getId()))), @@ -3513,7 +3693,7 @@ public void setPanelLockWithInterpretationWithDifferentPanelsTest() throws Catal thrown.expect(CatalogException.class); thrown.expectMessage("not defined by the case"); catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), + .setPanelLocked(true), QueryOptions.empty(), ownerToken); } @@ -3536,7 +3716,7 @@ public void updatePanelsFromClinicalAnalysisWithPanelLockTest() throws CatalogEx catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(2, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, clinicalAnalysis.getId(), new Interpretation(), ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); @@ -3544,9 +3724,9 @@ public void updatePanelsFromClinicalAnalysisWithPanelLockTest() throws CatalogEx // Set panelLock to true catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), QueryOptions.empty(), ownerToken); + .setPanelLocked(true), QueryOptions.empty(), ownerToken); clinicalAnalysis = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); - assertTrue(clinicalAnalysis.isPanelLock()); + assertTrue(clinicalAnalysis.isPanelLocked()); thrown.expect(CatalogException.class); thrown.expectMessage("panelLock"); @@ -3574,7 +3754,7 @@ public void updatePanelLockWithDifferentPanels() throws CatalogException { catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(2, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, clinicalAnalysis.getId(), new Interpretation(), ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); @@ -3582,15 +3762,15 @@ public void updatePanelLockWithDifferentPanels() throws CatalogException { // Set panelLock to true catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), QueryOptions.empty(), ownerToken); + .setPanelLocked(true), QueryOptions.empty(), ownerToken); clinicalAnalysis = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); - assertTrue(clinicalAnalysis.isPanelLock()); + assertTrue(clinicalAnalysis.isPanelLocked()); // Set panelLock to false catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(false), QueryOptions.empty(), ownerToken); + .setPanelLocked(false), QueryOptions.empty(), ownerToken); clinicalAnalysis = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); - assertFalse(clinicalAnalysis.isPanelLock()); + assertFalse(clinicalAnalysis.isPanelLocked()); Map actionMap = new HashMap<>(); actionMap.put(ClinicalAnalysisDBAdaptor.QueryParams.PANELS.key(), ParamUtils.BasicUpdateAction.SET); @@ -3606,9 +3786,9 @@ public void updatePanelLockWithDifferentPanels() throws CatalogException { thrown.expectMessage("panels"); // Set panelLock to true catalogManager.getClinicalAnalysisManager().update(studyFqn, clinicalAnalysis.getId(), new ClinicalAnalysisUpdateParams() - .setPanelLock(true), QueryOptions.empty(), ownerToken); + .setPanelLocked(true), QueryOptions.empty(), ownerToken); clinicalAnalysis = catalogManager.getClinicalAnalysisManager().get(studyFqn, clinicalAnalysis.getId(), QueryOptions.empty(), ownerToken).first(); - assertTrue(clinicalAnalysis.isPanelLock()); + assertTrue(clinicalAnalysis.isPanelLocked()); } @Test @@ -3624,14 +3804,14 @@ public void updatePanelsFromInterpretationWithLockedCATest() throws CatalogExcep .setId("analysis") .setType(ClinicalAnalysis.Type.SINGLE) .setProband(proband) - .setPanelLock(true) + .setPanelLocked(true) .setPanels(panels.subList(0, 2)); OpenCGAResult result = catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(2, result.first().getPanels().size()); - assertTrue(result.first().isPanelLock()); + assertTrue(result.first().isPanelLocked()); Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, clinicalAnalysis.getId(), new Interpretation(), ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); @@ -3663,7 +3843,7 @@ public void updatePanelsFromInterpretationWithUnlockedCATest() throws CatalogExc catalogManager.getClinicalAnalysisManager().create(studyFqn, clinicalAnalysis, INCLUDE_RESULT, ownerToken); assertEquals(1, result.getNumResults()); assertEquals(2, result.first().getPanels().size()); - assertFalse(result.first().isPanelLock()); + assertFalse(result.first().isPanelLocked()); Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, clinicalAnalysis.getId(), new Interpretation(), ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/InterpretationManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/InterpretationManagerTest.java index c31ba8e9301..80b630d34ee 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/InterpretationManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/InterpretationManagerTest.java @@ -1,11 +1,9 @@ package org.opencb.opencga.catalog.managers; import org.apache.commons.lang3.RandomStringUtils; -import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.opencb.biodata.models.common.Status; import org.opencb.commons.datastore.core.DataResult; import org.opencb.commons.datastore.core.QueryOptions; import org.opencb.opencga.catalog.exceptions.CatalogException; @@ -14,15 +12,19 @@ import org.opencb.opencga.core.models.clinical.*; import org.opencb.opencga.core.models.common.StatusParam; import org.opencb.opencga.core.models.family.Family; -import org.opencb.opencga.core.models.file.File; -import org.opencb.opencga.core.models.file.FileLinkParams; import org.opencb.opencga.core.models.individual.Individual; import org.opencb.opencga.core.models.panel.Panel; import org.opencb.opencga.core.models.panel.PanelReferenceParam; import org.opencb.opencga.core.models.sample.Sample; +import org.opencb.opencga.core.models.study.StudyAclParams; +import org.opencb.opencga.core.models.study.StudyPermissions; +import org.opencb.opencga.core.models.study.configuration.ClinicalAnalysisStudyConfiguration; import org.opencb.opencga.core.testclassification.duration.MediumTests; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static org.junit.Assert.*; @@ -45,7 +47,7 @@ private DataResult createDummyFamily() throws CatalogException { private DataResult createDummyEnvironment(boolean createFamily, boolean createDefaultInterpretation) throws CatalogException { ClinicalAnalysis clinicalAnalysis = new ClinicalAnalysis() - .setStatus(new Status().setId(ClinicalAnalysisStatus.READY_FOR_INTERPRETATION)) + .setStatus(new ClinicalStatus().setId("READY_FOR_INTERPRETATION")) .setId("analysis" + RandomStringUtils.randomAlphanumeric(3)) .setDescription("My description").setType(ClinicalAnalysis.Type.FAMILY) .setProband(new Individual().setId("child1").setSamples(Arrays.asList(new Sample().setId("sample2")))); @@ -60,25 +62,6 @@ private DataResult createDummyEnvironment(boolean createFamily INCLUDE_RESULT, ownerToken); } - private List registerDummyFiles() throws CatalogException { - List files = new LinkedList<>(); - - String vcfFile = getClass().getResource("/biofiles/variant-test-file.vcf.gz").getFile(); - files.add(catalogManager.getFileManager().link(studyFqn, new FileLinkParams(vcfFile, "", "", "", null, null, null, null, - null), false, ownerToken).first()); - vcfFile = getClass().getResource("/biofiles/family.vcf").getFile(); - files.add(catalogManager.getFileManager().link(studyFqn, new FileLinkParams(vcfFile, "", "", "", null, null, null, null, - null), false, ownerToken).first()); - String bamFile = getClass().getResource("/biofiles/HG00096.chrom20.small.bam").getFile(); - files.add(catalogManager.getFileManager().link(studyFqn, new FileLinkParams(bamFile, "", "", "", null, null, null, null, - null), false, ownerToken).first()); - bamFile = getClass().getResource("/biofiles/NA19600.chrom20.small.bam").getFile(); - files.add(catalogManager.getFileManager().link(studyFqn, new FileLinkParams(bamFile, "", "", "", null, null, null, null, - null), false, ownerToken).first()); - - return files; - } - @Test public void deleteLockedInterpretationTest() throws CatalogException { ClinicalAnalysis ca = createDummyEnvironment(true, false).first(); @@ -118,7 +101,7 @@ public void automaticallyLockInterpretationTest() throws CatalogException { ClinicalAnalysis ca = createDummyEnvironment(true, false).first(); Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, ca.getId(), new Interpretation(), ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); - assertTrue(StringUtils.isEmpty(interpretation.getStatus().getId())); + assertEquals(ClinicalStatusValue.ClinicalStatusType.NOT_STARTED, interpretation.getStatus().getType()); assertFalse(interpretation.isLocked()); interpretation = catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), interpretation.getId(), @@ -128,7 +111,7 @@ public void automaticallyLockInterpretationTest() throws CatalogException { interpretation = catalogManager.getInterpretationManager().create(studyFqn, ca.getId(), new Interpretation() - .setStatus(new Status("REJECTED", "", "", "")), + .setStatus(new ClinicalStatus("REJECTED", "", null, "", "", "", "")), ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); assertEquals("REJECTED", interpretation.getStatus().getId()); assertTrue(interpretation.isLocked()); @@ -151,15 +134,34 @@ public void interpretationLockedTest() throws CatalogException { assertFalse(secondaryInterpretation.isLocked()); } + // Add ADMIN permissions to the user2 + catalogManager.getStudyManager().updateAcl(studyFqn, normalUserId2, + new StudyAclParams(StudyPermissions.Permissions.ADMIN_CLINICAL_ANALYSIS.name(), null), ParamUtils.AclAction.SET, ownerToken); + // Try to update interpretation 1 try { catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), - new InterpretationUpdateParams().setDescription("blabla"), null, QueryOptions.empty(), ownerToken); + new InterpretationUpdateParams().setDescription("blabla"), null, QueryOptions.empty(), normalToken1); fail("Interpretation is locked so it should not allow this"); } catch (CatalogException e) { - assertTrue(e.getMessage().contains("locked")); + assertTrue(e.getMessage().contains(ClinicalAnalysisPermissions.ADMIN.name())); } + // Try to update interpretation 1 + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), + new InterpretationUpdateParams().setDescription("blabla"), null, QueryOptions.empty(), normalToken2); + Interpretation interpretation = catalogManager.getInterpretationManager().get(studyFqn, ca.getInterpretation().getId(), + QueryOptions.empty(), ownerToken).first(); + assertEquals("blabla", interpretation.getDescription()); + assertTrue(interpretation.isLocked()); + + // Try to update interpretation 1 + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), + new InterpretationUpdateParams().setDescription("blabla2"), null, QueryOptions.empty(), ownerToken); + interpretation = catalogManager.getInterpretationManager().get(studyFqn, ca.getInterpretation().getId(), QueryOptions.empty(), ownerToken).first(); + assertEquals("blabla2", interpretation.getDescription()); + assertTrue(interpretation.isLocked()); + // Update interpretation 2 catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getSecondaryInterpretations().get(0).getId(), new InterpretationUpdateParams().setDescription("blabla"), null, QueryOptions.empty(), ownerToken); @@ -175,15 +177,6 @@ public void interpretationLockedTest() throws CatalogException { assertEquals("bloblo", interpretation2.getDescription()); assertTrue(interpretation2.isLocked()); - // Try to lock again and update interpretation 2 - try { - catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getSecondaryInterpretations().get(0).getId(), - new InterpretationUpdateParams().setDescription("blabla").setLocked(true), null, QueryOptions.empty(), ownerToken); - fail("Interpretation was already locked so it should not allow this"); - } catch (CatalogException e) { - assertTrue(e.getMessage().contains("locked")); - } - // Unlock and update interpretation 2 catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getSecondaryInterpretations().get(0).getId(), new InterpretationUpdateParams().setDescription("blabla").setLocked(false), null, QueryOptions.empty(), ownerToken); @@ -210,6 +203,29 @@ public void interpretationLockedTest() throws CatalogException { assertTrue(secondaryInterpretation.isLocked()); } + // Try to update the interpretation 1 + try { + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), + new InterpretationUpdateParams().setDescription("new description"), null, QueryOptions.empty(), normalToken1); + fail("Case and Interpretation are locked so it should not allow this"); + } catch (CatalogException e) { + assertTrue(e.getMessage().contains(ClinicalAnalysisPermissions.ADMIN.name()) && e.getMessage().toLowerCase().contains("permission denied")); + } + + // Try to update the interpretation 1 (ADMIN permission) + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), + new InterpretationUpdateParams().setDescription("new description"), null, QueryOptions.empty(), normalToken2); + interpretation = catalogManager.getInterpretationManager().get(studyFqn, ca.getInterpretation().getId(), QueryOptions.empty(), ownerToken).first(); + assertEquals("new description", interpretation.getDescription()); + assertTrue(interpretation.isLocked()); + + // Try to update the interpretation 1 (owner user) + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), + new InterpretationUpdateParams().setDescription("new description2"), null, QueryOptions.empty(), ownerToken); + interpretation = catalogManager.getInterpretationManager().get(studyFqn, ca.getInterpretation().getId(), QueryOptions.empty(), ownerToken).first(); + assertEquals("new description2", interpretation.getDescription()); + assertTrue(interpretation.isLocked()); + // Try to unlock interpretation 1 try { catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), ca.getInterpretation().getId(), @@ -230,6 +246,43 @@ public void interpretationLockedTest() throws CatalogException { } } + @Test + public void interpretationStatusTest() throws CatalogException { + ClinicalAnalysis ca = createDummyEnvironment(true, false).first(); + + Interpretation interpretation = catalogManager.getInterpretationManager().create(studyFqn, ca.getId(), new Interpretation(), + ParamUtils.SaveInterpretationAs.PRIMARY, INCLUDE_RESULT, ownerToken).first(); + + // Create 2 allowed statuses of type CLOSED + ClinicalAnalysisStudyConfiguration studyConfiguration = ClinicalAnalysisStudyConfiguration.defaultConfiguration(); + List statusValueList = new ArrayList<>(); + for (ClinicalStatusValue status : studyConfiguration.getInterpretation().getStatus()) { + if (!status.getType().equals(ClinicalStatusValue.ClinicalStatusType.CLOSED)) { + statusValueList.add(status); + } + } + // Add two statuses of type CLOSED + statusValueList.add(new ClinicalStatusValue("closed1", "my desc", ClinicalStatusValue.ClinicalStatusType.CLOSED)); + statusValueList.add(new ClinicalStatusValue("closed2", "my desc", ClinicalStatusValue.ClinicalStatusType.CLOSED)); + studyConfiguration.getInterpretation().setStatus(statusValueList); + catalogManager.getClinicalAnalysisManager().configureStudy(studyFqn, studyConfiguration, studyAdminToken1); + + // Update status to one of the new statuses + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), interpretation.getId(), + new InterpretationUpdateParams().setStatus(new StatusParam("closed1")), null, QueryOptions.empty(), studyAdminToken1); + interpretation = catalogManager.getInterpretationManager().get(studyFqn, interpretation.getId(), QueryOptions.empty(), studyAdminToken1).first(); + assertEquals("closed1", interpretation.getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.CLOSED, interpretation.getStatus().getType()); + assertTrue(interpretation.isLocked()); + + // Update status to the other new CLOSED status + catalogManager.getInterpretationManager().update(studyFqn, ca.getId(), interpretation.getId(), + new InterpretationUpdateParams().setStatus(new StatusParam("closed2")), null, QueryOptions.empty(), studyAdminToken1); + assertEquals("closed1", interpretation.getStatus().getId()); + assertEquals(ClinicalStatusValue.ClinicalStatusType.CLOSED, interpretation.getStatus().getType()); + assertTrue(interpretation.isLocked()); + } + @Test public void createInterpretationWithSubsetOfPanels() throws CatalogException { ClinicalAnalysis ca = createDummyEnvironment(true, false).first(); @@ -247,7 +300,7 @@ public void createInterpretationWithSubsetOfPanels() throws CatalogException { catalogManager.getClinicalAnalysisManager().update(studyFqn, ca.getId(), updateParams, QueryOptions.empty(), ownerToken); updateParams = new ClinicalAnalysisUpdateParams() - .setPanelLock(true); + .setPanelLocked(true); catalogManager.getClinicalAnalysisManager().update(studyFqn, ca.getId(), updateParams, QueryOptions.empty(), ownerToken); // Create interpretation with just panel1 diff --git a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/PanelManagerTest.java b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/PanelManagerTest.java index 10b54926e6c..43191dc6838 100644 --- a/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/PanelManagerTest.java +++ b/opencga-catalog/src/test/java/org/opencb/opencga/catalog/managers/PanelManagerTest.java @@ -244,7 +244,7 @@ public void panelIncrementVersionWithCasesAndInterpretations() throws CatalogExc ParamUtils.SaveInterpretationAs.SECONDARY, QueryOptions.empty(), ownerToken); catalogManager.getInterpretationManager().create(studyFqn, case2.getId(), interpretation5, ParamUtils.SaveInterpretationAs.SECONDARY, QueryOptions.empty(), ownerToken); - catalogManager.getClinicalAnalysisManager().update(studyFqn, case2.getId(), new ClinicalAnalysisUpdateParams().setPanelLock(true), + catalogManager.getClinicalAnalysisManager().update(studyFqn, case2.getId(), new ClinicalAnalysisUpdateParams().setPanelLocked(true), QueryOptions.empty(), ownerToken); // case 3 diff --git a/opencga-client/src/main/R/R/Clinical-methods.R b/opencga-client/src/main/R/R/Clinical-methods.R index e0ca2cc5c44..a45c200d12e 100644 --- a/opencga-client/src/main/R/R/Clinical-methods.R +++ b/opencga-client/src/main/R/R/Clinical-methods.R @@ -23,9 +23,9 @@ #' | loadAnnotationSets | /{apiVersion}/analysis/clinical/annotationSets/load | study, variableSetId[*], path[*], parents, annotationSetId, body | #' | updateClinicalConfiguration | /{apiVersion}/analysis/clinical/clinical/configuration/update | study, body | #' | create | /{apiVersion}/analysis/clinical/create | include, exclude, study, skipCreateDefaultInterpretation, includeResult, body[*] | -#' | distinct | /{apiVersion}/analysis/clinical/distinct | study, id, uuid, type, disorder, files, sample, individual, proband, probandSamples, family, familyMembers, familyMemberSamples, panels, locked, analystId, priority, flags, creationDate, modificationDate, dueDate, qualityControlSummary, release, status, internalStatus, annotation, deleted, field[*] | -#' | distinctInterpretation | /{apiVersion}/analysis/clinical/interpretation/distinct | study, id, uuid, clinicalAnalysisId, analystId, methodName, panels, primaryFindings, secondaryFindings, creationDate, modificationDate, status, internalStatus, release, field[*] | -#' | searchInterpretation | /{apiVersion}/analysis/clinical/interpretation/search | include, exclude, limit, skip, sort, study, id, uuid, clinicalAnalysisId, analystId, methodName, panels, primaryFindings, secondaryFindings, creationDate, modificationDate, status, internalStatus, release | +#' | distinct | /{apiVersion}/analysis/clinical/distinct | study, id, uuid, type, disorder, files, sample, individual, proband, probandSamples, family, familyMembers, familyMemberSamples, panels, locked, analystId, priority, flags, creationDate, modificationDate, dueDate, qualityControlSummary, release, snapshot, status, internalStatus, annotation, deleted, field[*] | +#' | distinctInterpretation | /{apiVersion}/analysis/clinical/interpretation/distinct | study, id, uuid, name, clinicalAnalysisId, analystId, methodName, panels, primaryFindings, secondaryFindings, creationDate, modificationDate, status, internalStatus, release, field[*] | +#' | searchInterpretation | /{apiVersion}/analysis/clinical/interpretation/search | include, exclude, limit, skip, sort, study, id, uuid, name, clinicalAnalysisId, analystId, methodName, panels, primaryFindings, secondaryFindings, creationDate, modificationDate, status, internalStatus, release | #' | infoInterpretation | /{apiVersion}/analysis/clinical/interpretation/{interpretations}/info | include, exclude, interpretations[*], study, version, deleted | #' | runInterpreterCancerTiering | /{apiVersion}/analysis/clinical/interpreter/cancerTiering/run | study, jobId, jobDescription, jobDependsOn, jobTags, jobScheduledStartTime, jobPriority, jobDryRun, body[*] | #' | runInterpreterExomiser | /{apiVersion}/analysis/clinical/interpreter/exomiser/run | study, jobId, jobDescription, jobDependsOn, jobTags, jobScheduledStartTime, jobPriority, jobDryRun, body[*] | @@ -41,13 +41,13 @@ #' | summaryRgaIndividual | /{apiVersion}/analysis/clinical/rga/individual/summary | limit, skip, count, sampleId, individualId, sex, phenotypes, disorders, numParents, geneId, geneName, chromosome, start, end, transcriptId, variants, dbSnps, knockoutType, filter, type, clinicalSignificance, populationFrequency, consequenceType, study | #' | queryRgaVariant | /{apiVersion}/analysis/clinical/rga/variant/query | include, exclude, limit, skip, count, includeIndividual, skipIndividual, limitIndividual, sampleId, individualId, sex, phenotypes, disorders, numParents, geneId, geneName, chromosome, start, end, transcriptId, variants, dbSnps, knockoutType, filter, type, clinicalSignificance, populationFrequency, consequenceType, study | #' | summaryRgaVariant | /{apiVersion}/analysis/clinical/rga/variant/summary | limit, skip, count, sampleId, individualId, sex, phenotypes, disorders, numParents, geneId, geneName, chromosome, start, end, transcriptId, variants, dbSnps, knockoutType, filter, type, clinicalSignificance, populationFrequency, consequenceType, study | -#' | search | /{apiVersion}/analysis/clinical/search | include, exclude, limit, skip, count, flattenAnnotations, study, id, uuid, type, disorder, files, sample, individual, proband, probandSamples, family, familyMembers, familyMemberSamples, panels, locked, analystId, priority, flags, creationDate, modificationDate, dueDate, qualityControlSummary, release, status, internalStatus, annotation, deleted | +#' | search | /{apiVersion}/analysis/clinical/search | include, exclude, limit, skip, count, flattenAnnotations, study, id, uuid, type, disorder, files, sample, individual, proband, probandSamples, family, familyMembers, familyMemberSamples, panels, locked, analystId, priority, flags, creationDate, modificationDate, dueDate, qualityControlSummary, release, snapshot, status, internalStatus, annotation, deleted | #' | queryVariant | /{apiVersion}/analysis/clinical/variant/query | include, exclude, limit, skip, count, approximateCount, approximateCountSamplingSize, savedFilter, includeInterpretation, id, region, type, study, file, filter, qual, fileData, sample, sampleData, sampleAnnotation, cohort, cohortStatsRef, cohortStatsAlt, cohortStatsMaf, cohortStatsMgf, cohortStatsPass, missingAlleles, missingGenotypes, score, family, familyDisorder, familySegregation, familyMembers, familyProband, gene, ct, xref, biotype, proteinSubstitution, conservation, populationFrequencyAlt, populationFrequencyRef, populationFrequencyMaf, transcriptFlag, geneTraitId, go, expression, proteinKeyword, drug, functionalScore, clinical, clinicalSignificance, clinicalConfirmedStatus, customAnnotation, panel, panelModeOfInheritance, panelConfidence, panelRoleInCancer, panelFeatureType, panelIntersection, trait | #' | acl | /{apiVersion}/analysis/clinical/{clinicalAnalyses}/acl | clinicalAnalyses[*], study, member, silent | #' | delete | /{apiVersion}/analysis/clinical/{clinicalAnalyses}/delete | study, force, clinicalAnalyses[*] | #' | update | /{apiVersion}/analysis/clinical/{clinicalAnalyses}/update | include, exclude, clinicalAnalyses[*], study, commentsAction, flagsAction, analystsAction, filesAction, panelsAction, annotationSetsAction, includeResult, body[*] | #' | updateAnnotationSetsAnnotations | /{apiVersion}/analysis/clinical/{clinicalAnalysis}/annotationSets/{annotationSet}/annotations/update | clinicalAnalysis[*], study, annotationSet[*], action, body | -#' | info | /{apiVersion}/analysis/clinical/{clinicalAnalysis}/info | include, exclude, flattenAnnotations, clinicalAnalysis[*], study, deleted | +#' | info | /{apiVersion}/analysis/clinical/{clinicalAnalysis}/info | include, exclude, flattenAnnotations, clinicalAnalysis[*], study, version, deleted | #' | createInterpretation | /{apiVersion}/analysis/clinical/{clinicalAnalysis}/interpretation/create | include, exclude, clinicalAnalysis[*], study, setAs, includeResult, body[*] | #' | clearInterpretation | /{apiVersion}/analysis/clinical/{clinicalAnalysis}/interpretation/{interpretations}/clear | study, interpretations[*], clinicalAnalysis[*] | #' | deleteInterpretation | /{apiVersion}/analysis/clinical/{clinicalAnalysis}/interpretation/{interpretations}/delete | study, clinicalAnalysis[*], interpretations[*], setAsPrimary | @@ -131,6 +131,7 @@ setMethod("clinicalClient", "OpencgaR", function(OpencgaR, annotationSet, clinic #' @param dueDate Clinical Analysis due date. Format: yyyyMMddHHmmss. Examples: >2018, 2017-2018, <201805. #' @param qualityControlSummary Clinical Analysis quality control summary. #' @param release Release when it was created. + #' @param snapshot Snapshot value (Latest version of the entry in the specified release). #' @param status Filter by status. #' @param internalStatus Filter by internal status. #' @param annotation Annotation filters. Example: age>30;gender=FEMALE. For more information, please visit http://docs.opencb.org/display/opencga/AnnotationSets+1.4.0. @@ -144,6 +145,7 @@ setMethod("clinicalClient", "OpencgaR", function(OpencgaR, annotationSet, clinic #' @param study Study [[organization@]project:]study where study and project can be either the ID or UUID. #' @param id Comma separated list of Interpretation IDs up to a maximum of 100. Also admits basic regular expressions using the operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. #' @param uuid Comma separated list of Interpretation UUIDs up to a maximum of 100. + #' @param name Comma separated list of Interpretation names up to a maximum of 100. #' @param clinicalAnalysisId Clinical Analysis id. #' @param analystId Analyst ID. #' @param methodName Interpretation method name. Also admits basic regular expressions using the operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. @@ -170,6 +172,7 @@ setMethod("clinicalClient", "OpencgaR", function(OpencgaR, annotationSet, clinic #' @param study Study [[organization@]project:]study where study and project can be either the ID or UUID. #' @param id Comma separated list of Interpretation IDs up to a maximum of 100. Also admits basic regular expressions using the operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. #' @param uuid Comma separated list of Interpretation UUIDs up to a maximum of 100. + #' @param name Comma separated list of Interpretation names up to a maximum of 100. #' @param clinicalAnalysisId Clinical Analysis id. #' @param analystId Analyst ID. #' @param methodName Interpretation method name. Also admits basic regular expressions using the operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. @@ -555,6 +558,7 @@ setMethod("clinicalClient", "OpencgaR", function(OpencgaR, annotationSet, clinic #' @param dueDate Clinical Analysis due date. Format: yyyyMMddHHmmss. Examples: >2018, 2017-2018, <201805. #' @param qualityControlSummary Clinical Analysis quality control summary. #' @param release Release when it was created. + #' @param snapshot Snapshot value (Latest version of the entry in the specified release). #' @param status Filter by status. #' @param internalStatus Filter by internal status. #' @param annotation Annotation filters. Example: age>30;gender=FEMALE. For more information, please visit http://docs.opencb.org/display/opencga/AnnotationSets+1.4.0. @@ -683,6 +687,7 @@ setMethod("clinicalClient", "OpencgaR", function(OpencgaR, annotationSet, clinic #' @param flattenAnnotations Flatten the annotations?. #' @param clinicalAnalysis Comma separated list of clinical analysis IDs or names up to a maximum of 100. #' @param study Study [[organization@]project:]study where study and project can be either the ID or UUID. + #' @param version Comma separated list of clinical versions. 'all' to get all the clinical versions. Not supported if multiple clinical ids are provided. #' @param deleted Boolean to retrieve deleted entries. info=fetchOpenCGA(object=OpencgaR, category="analysis", categoryId=NULL, subcategory="clinical", subcategoryId=clinicalAnalysis, action="info", params=params, httpMethod="GET", as.queryParam=NULL, diff --git a/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/ClinicalAnalysisClient.java b/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/ClinicalAnalysisClient.java index 6590b6d5d4f..7e94ff82723 100644 --- a/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/ClinicalAnalysisClient.java +++ b/opencga-client/src/main/java/org/opencb/opencga/client/rest/clients/ClinicalAnalysisClient.java @@ -175,6 +175,7 @@ public RestResponse create(ClinicalAnalysisCreateParams data, * dueDate: Clinical Analysis due date. Format: yyyyMMddHHmmss. Examples: >2018, 2017-2018, <201805. * qualityControlSummary: Clinical Analysis quality control summary. * release: Release when it was created. + * snapshot: Snapshot value (Latest version of the entry in the specified release). * status: Filter by status. * internalStatus: Filter by internal status. * annotation: Annotation filters. Example: age>30;gender=FEMALE. For more information, please visit @@ -197,6 +198,7 @@ public RestResponse distinct(String field, ObjectMap params) throws C * id: Comma separated list of Interpretation IDs up to a maximum of 100. Also admits basic regular expressions using the * operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. * uuid: Comma separated list of Interpretation UUIDs up to a maximum of 100. + * name: Comma separated list of Interpretation names up to a maximum of 100. * clinicalAnalysisId: Clinical Analysis id. * analystId: Analyst ID. * methodName: Interpretation method name. Also admits basic regular expressions using the operator '~', i.e. '~{perl-regex}' @@ -230,6 +232,7 @@ public RestResponse distinctInterpretation(String field, ObjectMap pa * id: Comma separated list of Interpretation IDs up to a maximum of 100. Also admits basic regular expressions using the * operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. * uuid: Comma separated list of Interpretation UUIDs up to a maximum of 100. + * name: Comma separated list of Interpretation names up to a maximum of 100. * clinicalAnalysisId: Clinical Analysis id. * analystId: Analyst ID. * methodName: Interpretation method name. Also admits basic regular expressions using the operator '~', i.e. '~{perl-regex}' @@ -717,6 +720,7 @@ public RestResponse summaryRgaVariant(ObjectMap params * dueDate: Clinical Analysis due date. Format: yyyyMMddHHmmss. Examples: >2018, 2017-2018, <201805. * qualityControlSummary: Clinical Analysis quality control summary. * release: Release when it was created. + * snapshot: Snapshot value (Latest version of the entry in the specified release). * status: Filter by status. * internalStatus: Filter by internal status. * annotation: Annotation filters. Example: age>30;gender=FEMALE. For more information, please visit @@ -917,6 +921,8 @@ public RestResponse updateAnnotationSetsAnnotations(String clinicalAnaly * exclude: Fields excluded in the response, whole JSON path must be provided. * flattenAnnotations: Flatten the annotations?. * study: Study [[organization@]project:]study where study and project can be either the ID or UUID. + * version: Comma separated list of clinical versions. 'all' to get all the clinical versions. Not supported if multiple clinical + * ids are provided. * deleted: Boolean to retrieve deleted entries. * @return a RestResponse object. * @throws ClientException ClientException if there is any server error. diff --git a/opencga-client/src/main/javascript/ClinicalAnalysis.js b/opencga-client/src/main/javascript/ClinicalAnalysis.js index 18eac705af1..931d5fe01ce 100644 --- a/opencga-client/src/main/javascript/ClinicalAnalysis.js +++ b/opencga-client/src/main/javascript/ClinicalAnalysis.js @@ -118,6 +118,7 @@ export default class ClinicalAnalysis extends OpenCGAParentClass { * @param {String} [params.dueDate] - Clinical Analysis due date. Format: yyyyMMddHHmmss. Examples: >2018, 2017-2018, <201805. * @param {String} [params.qualityControlSummary] - Clinical Analysis quality control summary. * @param {String} [params.release] - Release when it was created. + * @param {Number} [params.snapshot] - Snapshot value (Latest version of the entry in the specified release). * @param {String} [params.status] - Filter by status. * @param {String} [params.internalStatus] - Filter by internal status. * @param {String} [params.annotation] - Annotation filters. Example: age>30;gender=FEMALE. For more information, please visit @@ -136,6 +137,7 @@ export default class ClinicalAnalysis extends OpenCGAParentClass { * @param {String} [params.id] - Comma separated list of Interpretation IDs up to a maximum of 100. Also admits basic regular expressions * using the operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. * @param {String} [params.uuid] - Comma separated list of Interpretation UUIDs up to a maximum of 100. + * @param {String} [params.name] - Comma separated list of Interpretation names up to a maximum of 100. * @param {String} [params.clinicalAnalysisId] - Clinical Analysis id. * @param {String} [params.analystId] - Analyst ID. * @param {String} [params.methodName] - Interpretation method name. Also admits basic regular expressions using the operator '~', i.e. @@ -166,6 +168,7 @@ export default class ClinicalAnalysis extends OpenCGAParentClass { * @param {String} [params.id] - Comma separated list of Interpretation IDs up to a maximum of 100. Also admits basic regular expressions * using the operator '~', i.e. '~{perl-regex}' e.g. '~value' for case sensitive, '~/value/i' for case insensitive search. * @param {String} [params.uuid] - Comma separated list of Interpretation UUIDs up to a maximum of 100. + * @param {String} [params.name] - Comma separated list of Interpretation names up to a maximum of 100. * @param {String} [params.clinicalAnalysisId] - Clinical Analysis id. * @param {String} [params.analystId] - Analyst ID. * @param {String} [params.methodName] - Interpretation method name. Also admits basic regular expressions using the operator '~', i.e. @@ -607,6 +610,7 @@ export default class ClinicalAnalysis extends OpenCGAParentClass { * @param {String} [params.dueDate] - Clinical Analysis due date. Format: yyyyMMddHHmmss. Examples: >2018, 2017-2018, <201805. * @param {String} [params.qualityControlSummary] - Clinical Analysis quality control summary. * @param {String} [params.release] - Release when it was created. + * @param {Number} [params.snapshot] - Snapshot value (Latest version of the entry in the specified release). * @param {String} [params.status] - Filter by status. * @param {String} [params.internalStatus] - Filter by internal status. * @param {String} [params.annotation] - Annotation filters. Example: age>30;gender=FEMALE. For more information, please visit @@ -803,6 +807,8 @@ export default class ClinicalAnalysis extends OpenCGAParentClass { * @param {String} [params.exclude] - Fields excluded in the response, whole JSON path must be provided. * @param {Boolean} [params.flattenAnnotations = "false"] - Flatten the annotations?. The default value is false. * @param {String} [params.study] - Study [[organization@]project:]study where study and project can be either the ID or UUID. + * @param {String} [params.version] - Comma separated list of clinical versions. 'all' to get all the clinical versions. Not supported if + * multiple clinical ids are provided. * @param {Boolean} [params.deleted = "false"] - Boolean to retrieve deleted entries. The default value is false. * @returns {Promise} Promise object in the form of RestResponse instance. */ diff --git a/opencga-client/src/main/python/pyopencga/rest_clients/clinical_analysis_client.py b/opencga-client/src/main/python/pyopencga/rest_clients/clinical_analysis_client.py index 758dc09416c..0a531515217 100644 --- a/opencga-client/src/main/python/pyopencga/rest_clients/clinical_analysis_client.py +++ b/opencga-client/src/main/python/pyopencga/rest_clients/clinical_analysis_client.py @@ -141,6 +141,8 @@ def distinct(self, field, **options): :param str quality_control_summary: Clinical Analysis quality control summary. :param str release: Release when it was created. + :param int snapshot: Snapshot value (Latest version of the entry in + the specified release). :param str status: Filter by status. :param str internal_status: Filter by internal status. :param str annotation: Annotation filters. Example: @@ -167,6 +169,8 @@ def distinct_interpretation(self, field, **options): sensitive, '~/value/i' for case insensitive search. :param str uuid: Comma separated list of Interpretation UUIDs up to a maximum of 100. + :param str name: Comma separated list of Interpretation names up to a + maximum of 100. :param str clinical_analysis_id: Clinical Analysis id. :param str analyst_id: Analyst ID. :param str method_name: Interpretation method name. Also admits basic @@ -208,6 +212,8 @@ def search_interpretation(self, **options): sensitive, '~/value/i' for case insensitive search. :param str uuid: Comma separated list of Interpretation UUIDs up to a maximum of 100. + :param str name: Comma separated list of Interpretation names up to a + maximum of 100. :param str clinical_analysis_id: Clinical Analysis id. :param str analyst_id: Analyst ID. :param str method_name: Interpretation method name. Also admits basic @@ -748,6 +754,8 @@ def search(self, **options): :param str quality_control_summary: Clinical Analysis quality control summary. :param str release: Release when it was created. + :param int snapshot: Snapshot value (Latest version of the entry in + the specified release). :param str status: Filter by status. :param str internal_status: Filter by internal status. :param str annotation: Annotation filters. Example: @@ -1031,6 +1039,9 @@ def info(self, clinical_analysis, **options): :param bool flatten_annotations: Flatten the annotations?. :param str study: Study [[organization@]project:]study where study and project can be either the ID or UUID. + :param str version: Comma separated list of clinical versions. 'all' + to get all the clinical versions. Not supported if multiple + clinical ids are provided. :param bool deleted: Boolean to retrieve deleted entries. """ diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java b/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java index 0c5c0d27c4b..4d02f049f2a 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/api/ParamConstants.java @@ -437,6 +437,9 @@ public class ParamConstants { public static final String CLINICAL_RELEASE_PARAM = RELEASE_PARAM; public static final String CLINICAL_STATUS_PARAM = STATUS_PARAM; public static final String CLINICAL_INTERNAL_STATUS_PARAM = INTERNAL_STATUS_PARAM; + public static final String CLINICAL_VERSION_PARAM = "version"; + public static final String CLINICAL_VERSION_DESCRIPTION = "Comma separated list of clinical versions. 'all' to get all the clinical" + + " versions. Not supported if multiple clinical ids are provided"; public static final String CLINICAL_TYPE_DESCRIPTION = "Clinical Analysis type"; public static final String CLINICAL_DISORDER_DESCRIPTION = "Clinical Analysis disorder" + REGEX_SUPPORT; public static final String CLINICAL_FILES_DESCRIPTION = "Clinical Analysis files"; @@ -467,6 +470,7 @@ public class ParamConstants { + "Interpretation object is passed."; public static final String INTERPRETATION_ID_PARAM = "id"; public static final String INTERPRETATION_UUID_PARAM = "uuid"; + public static final String INTERPRETATION_NAME_PARAM = "name"; public static final String INTERPRETATION_CLINICAL_ANALYSIS_ID_PARAM = "clinicalAnalysisId"; public static final String INTERPRETATION_ANALYST_ID_PARAM = "analystId"; public static final String INTERPRETATION_METHOD_NAME_PARAM = "methodName"; @@ -1519,6 +1523,7 @@ public class ParamConstants { public static final String CLINICAL_ANALYSES_DESCRIPTION = "Comma separated list of clinical analysis IDs or names" + UP_TO_100; public static final String INTERPRETATION_ID_DESCRIPTION = "Comma separated list of Interpretation IDs" + UP_TO_100 + REGEX_SUPPORT; public static final String INTERPRETATION_UUID_DESCRIPTION = "Comma separated list of Interpretation UUIDs" + UP_TO_100; + public static final String INTERPRETATION_NAME_DESCRIPTION = "Comma separated list of Interpretation names" + UP_TO_100; public static final String INTERPRETATION_DESCRIPTION = "Comma separated list of clinical interpretation IDs " + UP_TO_100; public static final String PANEL_ID_DESCRIPTION = "Comma separated list of panel IDs " + UP_TO_100 + REGEX_SUPPORT; public static final String PANEL_UUID_DESCRIPTION = "Comma separated list of panel UUIDs " + UP_TO_100; 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 61bc01c644f..d2d48863d31 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 @@ -22,7 +22,6 @@ 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.annotations.DataClass; import org.opencb.commons.annotations.DataField; import org.opencb.opencga.core.api.FieldConstants; @@ -100,9 +99,9 @@ public class ClinicalAnalysis extends Annotable { description = FieldConstants.CLINICAL_ANALYSIS_PANELS) private List panels; - @DataField(id = "panelLock", indexed = true, + @DataField(id = "panelLocked", indexed = true, description = FieldConstants.CLINICAL_ANALYSIS_PANEL_LOCK) - private boolean panelLock; + private boolean panelLocked; @DataField(id = "locked", indexed = true, description = FieldConstants.CLINICAL_ANALYSIS_LOCKED) @@ -179,6 +178,14 @@ public class ClinicalAnalysis extends Annotable { description = FieldConstants.GENERIC_RELEASE_DESCRIPTION) private int release; + /** + * Generic: Autoincremental version assigned to the registered entry. + * + * @apiNote Immutable + */ + @DataField(id = "version", managed = true, indexed = true, description = FieldConstants.GENERIC_VERSION_DESCRIPTION) + private int version; + @DataField(id = "qualityControl", indexed = true, description = FieldConstants.GENERIC_QUALITY_CONTROL) private ClinicalAnalysisQualityControl qualityControl; @@ -217,19 +224,19 @@ public class ClinicalAnalysis extends Annotable { */ @DataField(id = "status", indexed = true, uncommentedClasses = {"Status"}, description = FieldConstants.GENERIC_STATUS_DESCRIPTION) - private Status status; + private ClinicalStatus status; 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, + Family family, List panels, boolean panelLocked, boolean locked, Interpretation interpretation, 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) { + String dueDate, int release, int version, List comments, + ClinicalAnalysisQualityControl qualityControl, List audit, ClinicalAnalysisInternal internal, + List annotationSets, Map attributes, ClinicalStatus status) { this.id = id; this.description = description; this.type = type; @@ -238,7 +245,7 @@ public ClinicalAnalysis(String id, String description, Type type, Disorder disor this.proband = proband; this.family = family; this.panels = panels; - this.panelLock = panelLock; + this.panelLocked = panelLocked; this.locked = locked; this.interpretation = interpretation; this.secondaryInterpretations = secondaryInterpretations; @@ -254,6 +261,7 @@ public ClinicalAnalysis(String id, String description, Type type, Disorder disor this.dueDate = dueDate; this.qualityControl = qualityControl; this.release = release; + this.version = version; this.comments = comments; this.audit = audit; this.internal = internal; @@ -274,7 +282,7 @@ public String toString() { sb.append(", proband=").append(proband); sb.append(", family=").append(family); sb.append(", panels=").append(panels); - sb.append(", panelLock=").append(panelLock); + sb.append(", panelLocked=").append(panelLocked); sb.append(", locked=").append(locked); sb.append(", interpretation=").append(interpretation); sb.append(", secondaryInterpretations=").append(secondaryInterpretations); @@ -289,6 +297,7 @@ public String toString() { sb.append(", modificationDate='").append(modificationDate).append('\''); sb.append(", dueDate='").append(dueDate).append('\''); sb.append(", release=").append(release); + sb.append(", version=").append(version); sb.append(", qualityControl=").append(qualityControl); sb.append(", comments=").append(comments); sb.append(", audit=").append(audit); @@ -383,12 +392,23 @@ public ClinicalAnalysis setPanels(List panels) { return this; } + @Deprecated + @JsonIgnore public boolean isPanelLock() { - return panelLock; + return isPanelLocked(); } + @Deprecated public ClinicalAnalysis setPanelLock(boolean panelLock) { - this.panelLock = panelLock; + return setPanelLocked(panelLock); + } + + public boolean isPanelLocked() { + return panelLocked; + } + + public ClinicalAnalysis setPanelLocked(boolean panelLocked) { + this.panelLocked = panelLocked; return this; } @@ -532,6 +552,15 @@ public ClinicalAnalysis setRelease(int release) { return this; } + public int getVersion() { + return version; + } + + public ClinicalAnalysis setVersion(int version) { + this.version = version; + return this; + } + public List getComments() { return comments; } @@ -583,11 +612,11 @@ public ClinicalAnalysis setAttributes(Map attributes) { return this; } - public Status getStatus() { + public ClinicalStatus getStatus() { return status; } - public ClinicalAnalysis setStatus(Status status) { + public ClinicalAnalysis setStatus(ClinicalStatus status) { this.status = status; return this; } 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 7ffbf4b4a9a..157b9f0b12e 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 @@ -46,7 +46,7 @@ public class ClinicalAnalysisCreateParams { private FamilyParam family; private List panels; - private Boolean panelLock; + private Boolean panelLocked; @Deprecated private ClinicalAnalystParam analyst; @@ -75,7 +75,7 @@ public ClinicalAnalysisCreateParams() { public ClinicalAnalysisCreateParams(String id, String description, ClinicalAnalysis.Type type, DisorderReferenceParam disorder, List files, ProbandParam proband, FamilyParam family, - List panels, Boolean panelLock, List analysts, + List panels, Boolean panelLocked, List analysts, ClinicalReport report, ClinicalRequest request, ClinicalResponsible responsible, InterpretationCreateParams interpretation, ClinicalConsentAnnotationParam consent, String creationDate, String modificationDate, String dueDate, List comments, @@ -90,7 +90,7 @@ public ClinicalAnalysisCreateParams(String id, String description, ClinicalAnaly this.proband = proband; this.family = family; this.panels = panels; - this.panelLock = panelLock; + this.panelLocked = panelLocked; this.report = report; this.request = request; this.responsible = responsible; @@ -120,7 +120,7 @@ public static ClinicalAnalysisCreateParams of(ClinicalAnalysis clinicalAnalysis) clinicalAnalysis.getPanels() != null ? clinicalAnalysis.getPanels().stream().map(p -> new PanelReferenceParam(p.getId())).collect(Collectors.toList()) : null, - clinicalAnalysis.isPanelLock(), + clinicalAnalysis.isPanelLocked(), clinicalAnalysis.getAnalysts() != null ? clinicalAnalysis.getAnalysts().stream().map(ClinicalAnalystParam::of).collect(Collectors.toList()) : null, @@ -155,7 +155,7 @@ public String toString() { sb.append(", proband=").append(proband); sb.append(", family=").append(family); sb.append(", panels=").append(panels); - sb.append(", panelLock=").append(panelLock); + sb.append(", panelLocked=").append(panelLocked); sb.append(", analysts=").append(analysts); sb.append(", report=").append(report); sb.append(", request=").append(request); @@ -231,14 +231,14 @@ 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<>(), + diseasePanelList, panelLocked != null ? panelLocked : false, false, primaryInterpretation, new LinkedList<>(), consent != null ? consent.toClinicalConsentAnnotation() : 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, + 1, 1, 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); + annotationSets, attributes, status != null ? status.toClinicalStatus() : null); } public String getId() { @@ -313,12 +313,12 @@ public ClinicalAnalysisCreateParams setPanels(List panels) return this; } - public Boolean getPanelLock() { - return panelLock; + public Boolean getPanelLocked() { + return panelLocked; } - public ClinicalAnalysisCreateParams setPanelLock(Boolean panelLock) { - this.panelLock = panelLock; + public ClinicalAnalysisCreateParams setPanelLocked(Boolean panelLocked) { + this.panelLocked = panelLocked; return this; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisInternal.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisInternal.java index a529d6d7d27..425654bcc55 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisInternal.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisInternal.java @@ -18,21 +18,19 @@ import org.opencb.opencga.core.common.TimeUtils; import org.opencb.opencga.core.models.common.Internal; +import org.opencb.opencga.core.models.common.InternalStatus; public class ClinicalAnalysisInternal extends Internal { - private ClinicalAnalysisStatus status; - public ClinicalAnalysisInternal() { } - public ClinicalAnalysisInternal(String registrationDate, String modificationDate, ClinicalAnalysisStatus status) { - super(null, registrationDate, modificationDate); - this.status = status; + public ClinicalAnalysisInternal(String registrationDate, String modificationDate, InternalStatus status) { + super(status, registrationDate, modificationDate); } public static ClinicalAnalysisInternal init() { - return new ClinicalAnalysisInternal(TimeUtils.getTime(), TimeUtils.getTime(), new ClinicalAnalysisStatus()); + return new ClinicalAnalysisInternal(TimeUtils.getTime(), TimeUtils.getTime(), new InternalStatus()); } @Override @@ -45,11 +43,11 @@ public String toString() { return sb.toString(); } - public ClinicalAnalysisStatus getStatus() { + public InternalStatus getStatus() { return status; } - public ClinicalAnalysisInternal setStatus(ClinicalAnalysisStatus status) { + public ClinicalAnalysisInternal setStatus(InternalStatus status) { this.status = status; return this; } 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 e0cdfadd0c0..724f4ae04a5 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 @@ -9,7 +9,8 @@ public enum ClinicalAnalysisPermissions { 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)); + DELETE_ANNOTATIONS(Arrays.asList(VIEW_ANNOTATIONS, WRITE_ANNOTATIONS, VIEW)), + ADMIN(Arrays.asList(VIEW, WRITE, DELETE, VIEW_ANNOTATIONS, WRITE_ANNOTATIONS, DELETE_ANNOTATIONS)); private final List implicitPermissions; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisStatus.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisStatus.java deleted file mode 100644 index b898a7c21d5..00000000000 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalAnalysisStatus.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.core.models.clinical; - -import org.opencb.opencga.core.models.common.InternalStatus; - -import java.util.Arrays; -import java.util.List; - -public class ClinicalAnalysisStatus extends InternalStatus { - - public static final String INCOMPLETE = "INCOMPLETE"; - public static final String READY_FOR_VALIDATION = "READY_FOR_VALIDATION"; - public static final String READY_FOR_INTERPRETATION = "READY_FOR_INTERPRETATION"; - public static final String INTERPRETATION_IN_PROGRESS = "INTERPRETATION_IN_PROGRESS"; - // public static final String INTERPRETED = "INTERPRETED"; - public static final String READY_FOR_INTEPRETATION_REVIEW = "READY_FOR_INTEPRETATION_REVIEW"; - public static final String INTERPRETATION_REVIEW_IN_PROGRESS = "INTERPRETATION_REVIEW_IN_PROGRESS"; - public static final String READY_FOR_REPORT = "READY_FOR_REPORT"; - public static final String REPORT_IN_PROGRESS = "REPORT_IN_PROGRESS"; - public static final String DONE = "DONE"; - public static final String REVIEW_IN_PROGRESS = "REVIEW_IN_PROGRESS"; - public static final String CLOSED = "CLOSED"; - public static final String REJECTED = "REJECTED"; - - public static final List STATUS_LIST = Arrays.asList(INCOMPLETE, READY, DELETED, READY_FOR_VALIDATION, - READY_FOR_INTERPRETATION, INTERPRETATION_IN_PROGRESS, READY_FOR_INTEPRETATION_REVIEW, INTERPRETATION_REVIEW_IN_PROGRESS, - READY_FOR_REPORT, REPORT_IN_PROGRESS, DONE, REVIEW_IN_PROGRESS, CLOSED, REJECTED); - - public ClinicalAnalysisStatus(String status, String message) { - if (isValid(status)) { - init(status, message); - } else { - throw new IllegalArgumentException("Unknown status " + status); - } - } - - public ClinicalAnalysisStatus(String status) { - this(status, ""); - } - - public ClinicalAnalysisStatus() { - this(READY_FOR_INTERPRETATION, ""); - } - - public static boolean isValid(String status) { - if (InternalStatus.isValid(status)) { - return true; - } - - if (STATUS_LIST.contains(status)) { - return true; - } - return false; - } -} 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 020a44ead6a..e22feef43ae 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 @@ -44,7 +44,7 @@ public class ClinicalAnalysisUpdateParams { private List files; private List panels; - private Boolean panelLock; + private Boolean panelLocked; private ProbandParam proband; private FamilyParam family; @@ -77,7 +77,7 @@ 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, + List panels, Boolean panelLocked, Boolean locked, List analysts, ClinicalReport report, ClinicalRequest request, ClinicalResponsible responsible, ClinicalAnalysisQualityControlUpdateParam qualityControl, ClinicalConsentAnnotationParam consent, String creationDate, String modificationDate, @@ -92,7 +92,7 @@ public ClinicalAnalysisUpdateParams(String id, String description, ClinicalAnaly this.proband = proband; this.family = family; this.panels = panels; - this.panelLock = panelLock; + this.panelLocked = panelLocked; this.locked = locked; this.analysts = analysts; this.report = report; @@ -123,7 +123,7 @@ public ClinicalAnalysis toClinicalAnalysis() { proband != null ? proband.toIndividual() : null, family != null ? family.toFamily() : null, panels != null ? panels.stream().map(p -> new Panel().setId(p.getId())).collect(Collectors.toList()) : null, - panelLock != null ? panelLock : false, + panelLocked != null ? panelLocked : false, locked != null && locked, null, null, consent != null ? consent.toClinicalConsentAnnotation() : null, @@ -133,10 +133,10 @@ public ClinicalAnalysis toClinicalAnalysis() { report, request, responsible, priority != null ? priority.toClinicalPriorityAnnotation() : null, flags != null ? flags.stream().map(FlagValueParam::toFlagAnnotation).collect(Collectors.toList()) : null, creationDate, modificationDate, dueDate, - 1, + 1, 1, comments != null ? comments.stream().map(ClinicalCommentParam::toClinicalComment).collect(Collectors.toList()) : null, qualityControl != null ? qualityControl.toClinicalQualityControl() : null, null, null, annotationSets, attributes, - status != null ? status.toStatus() : null); + status != null ? status.toClinicalStatus() : null); } @Override @@ -148,7 +148,7 @@ public String toString() { sb.append(", disorder=").append(disorder); sb.append(", files=").append(files); sb.append(", panels=").append(panels); - sb.append(", panelLock=").append(panelLock); + sb.append(", panelLocked=").append(panelLocked); sb.append(", proband=").append(proband); sb.append(", family=").append(family); sb.append(", locked=").append(locked); @@ -243,12 +243,22 @@ public ClinicalAnalysisUpdateParams setFamily(FamilyParam family) { return this; } + @Deprecated public Boolean getPanelLock() { - return panelLock; + return getPanelLocked(); } + @Deprecated public ClinicalAnalysisUpdateParams setPanelLock(Boolean panelLock) { - this.panelLock = panelLock; + return setPanelLocked(panelLock); + } + + public Boolean getPanelLocked() { + return panelLocked; + } + + public ClinicalAnalysisUpdateParams setPanelLocked(Boolean panelLocked) { + this.panelLocked = panelLocked; return this; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatus.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatus.java new file mode 100644 index 00000000000..baa92b6f22a --- /dev/null +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatus.java @@ -0,0 +1,77 @@ +package org.opencb.opencga.core.models.clinical; + +public class ClinicalStatus extends ClinicalStatusValue { + + private String author; + private String version; + private String commit; + private String date; + + public ClinicalStatus() { + } + + public ClinicalStatus(String id, String description, ClinicalStatusType type, String author, String version, String commit, + String date) { + super(id, description, type); + this.author = author; + this.version = version; + this.commit = commit; + this.date = date; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ClinicalStatus{"); + sb.append("id='").append(id).append('\''); + sb.append(", description='").append(description).append('\''); + sb.append(", type=").append(type); + sb.append(", author='").append(author).append('\''); + sb.append(", version='").append(version).append('\''); + sb.append(", commit='").append(commit).append('\''); + sb.append(", date='").append(date).append('\''); + sb.append('}'); + return sb.toString(); + } + + @Override + public ClinicalStatus setId(String id) { + super.setId(id); + return this; + } + + public String getVersion() { + return version; + } + + public ClinicalStatus setVersion(String version) { + this.version = version; + return this; + } + + public String getCommit() { + return commit; + } + + public ClinicalStatus setCommit(String commit) { + this.commit = commit; + return this; + } + + public String getAuthor() { + return author; + } + + public ClinicalStatus setAuthor(String author) { + this.author = author; + return this; + } + + public String getDate() { + return date; + } + + public ClinicalStatus setDate(String date) { + this.date = date; + return this; + } +} diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatusValue.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatusValue.java index 9efa33d4a33..68816055dde 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatusValue.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/ClinicalStatusValue.java @@ -2,15 +2,15 @@ public class ClinicalStatusValue { - private String id; - private String description; - private ClinicalStatusType type; + protected String id; + protected String description; + protected ClinicalStatusType type; public enum ClinicalStatusType { NOT_STARTED, - IN_PROGRESS, - CLOSED, - UNKNOWN + ACTIVE, + DONE, + CLOSED } public ClinicalStatusValue() { diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/Interpretation.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/Interpretation.java index 273ce53a4c9..a6774d4f751 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/Interpretation.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/Interpretation.java @@ -20,7 +20,6 @@ import org.opencb.biodata.models.clinical.ClinicalComment; import org.opencb.biodata.models.clinical.interpretation.ClinicalVariant; import org.opencb.biodata.models.clinical.interpretation.InterpretationMethod; -import org.opencb.biodata.models.common.Status; import org.opencb.commons.annotations.DataField; import org.opencb.opencga.core.api.FieldConstants; import org.opencb.opencga.core.models.IPrivateStudyUid; @@ -54,35 +53,56 @@ public class Interpretation extends org.opencb.biodata.models.clinical.interpret description = FieldConstants.GENERIC_RELEASE_DESCRIPTION) private int release; + @DataField(id = "status", indexed = true, + description = FieldConstants.GENERIC_STATUS_DESCRIPTION) + private ClinicalStatus status; + public Interpretation() { super(); } - public Interpretation(String id, String description, String clinicalAnalysisId, ClinicalAnalyst analyst, + public Interpretation(String id, String name, String description, String clinicalAnalysisId, ClinicalAnalyst analyst, InterpretationMethod method, String creationDate, String modificationDate, boolean locked, List primaryFindings, List secondaryFindings, List panels, - List comments, Status status, Map attributes) { - super(id, "", description, clinicalAnalysisId, analyst, method, primaryFindings, secondaryFindings, comments, null, status, - creationDate, modificationDate, locked, 0, attributes); - + List comments, ClinicalStatus status, Map attributes) { + super(id, "", name, description, clinicalAnalysisId, analyst, method, primaryFindings, secondaryFindings, comments, null, locked, + creationDate, modificationDate, 0, attributes); + this.status = status; this.panels = panels; } public Interpretation(org.opencb.biodata.models.clinical.interpretation.Interpretation interpretation) { - this(interpretation.getId(), interpretation.getDescription(), interpretation.getClinicalAnalysisId(), interpretation.getAnalyst(), - interpretation.getMethod(), interpretation.getCreationDate(), interpretation.getModificationDate(), - interpretation.isLocked(), interpretation.getPrimaryFindings(), interpretation.getSecondaryFindings(), - Collections.emptyList(), interpretation.getComments(), interpretation.getStatus(), interpretation.getAttributes()); + this(interpretation.getId(), interpretation.getName(), interpretation.getDescription(), interpretation.getClinicalAnalysisId(), + interpretation.getAnalyst(), interpretation.getMethod(), interpretation.getCreationDate(), + interpretation.getModificationDate(), interpretation.isLocked(), interpretation.getPrimaryFindings(), + interpretation.getSecondaryFindings(), Collections.emptyList(), interpretation.getComments(), null, + interpretation.getAttributes()); } @Override public String toString() { final StringBuilder sb = new StringBuilder("Interpretation{"); - sb.append("studyUid=").append(studyUid); + sb.append("id='").append(id).append('\''); + sb.append(", uuid='").append(uuid).append('\''); + sb.append(", name='").append(name).append('\''); + sb.append(", description='").append(description).append('\''); + sb.append(", studyUid=").append(studyUid); sb.append(", uid=").append(uid); sb.append(", panels=").append(panels); sb.append(", internal=").append(internal); sb.append(", release=").append(release); + sb.append(", status=").append(status); + sb.append(", clinicalAnalysisId='").append(clinicalAnalysisId).append('\''); + sb.append(", analyst=").append(analyst); + sb.append(", method=").append(method); + sb.append(", primaryFindings=").append(primaryFindings); + sb.append(", secondaryFindings=").append(secondaryFindings); + sb.append(", comments=").append(comments); + sb.append(", stats=").append(stats); + sb.append(", locked=").append(locked); + sb.append(", creationDate='").append(creationDate).append('\''); + sb.append(", modificationDate='").append(modificationDate).append('\''); + sb.append(", version=").append(version); sb.append('}'); return sb.toString(); } @@ -185,14 +205,17 @@ public Interpretation setComments(List comments) { } @Override - public Interpretation setStatus(Status status) { - super.setStatus(status); + public Interpretation setLocked(boolean locked) { + super.setLocked(locked); return this; } - @Override - public Interpretation setLocked(boolean locked) { - super.setLocked(locked); + public ClinicalStatus getStatus() { + return status; + } + + public Interpretation setStatus(ClinicalStatus status) { + this.status = status; return this; } } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationCreateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationCreateParams.java index e35ccec46f8..9c710fa0493 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationCreateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationCreateParams.java @@ -26,13 +26,13 @@ import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.stream.Collectors; import static org.opencb.opencga.core.common.JacksonUtils.getUpdateObjectMapper; public class InterpretationCreateParams { + private String name; private String description; private String clinicalAnalysisId; private String creationDate; @@ -50,11 +50,12 @@ public class InterpretationCreateParams { public InterpretationCreateParams() { } - public InterpretationCreateParams(String description, String clinicalAnalysisId, String creationDate, String modificationDate, + public InterpretationCreateParams(String name, String description, String clinicalAnalysisId, String creationDate, String modificationDate, ClinicalAnalystParam analyst, InterpretationMethod method, List primaryFindings, List secondaryFindings, List panels, List comments, StatusParam status, Boolean locked, Map attributes) { + this.name = name; this.description = description; this.clinicalAnalysisId = clinicalAnalysisId; this.creationDate = creationDate; @@ -71,7 +72,7 @@ public InterpretationCreateParams(String description, String clinicalAnalysisId, } public static InterpretationCreateParams of(Interpretation interpretation) { - return new InterpretationCreateParams(interpretation.getDescription(), + return new InterpretationCreateParams(interpretation.getName(), interpretation.getDescription(), interpretation.getClinicalAnalysisId(), interpretation.getCreationDate(), interpretation.getModificationDate(), ClinicalAnalystParam.of(interpretation.getAnalyst()), interpretation.getMethod(), interpretation.getPrimaryFindings(), interpretation.getSecondaryFindings(), @@ -89,7 +90,8 @@ public static InterpretationCreateParams of(Interpretation interpretation) { @Override public String toString() { final StringBuilder sb = new StringBuilder("InterpretationCreateParams{"); - sb.append("description='").append(description).append('\''); + sb.append("name='").append(name).append('\''); + sb.append(", description='").append(description).append('\''); sb.append(", clinicalAnalysisId='").append(clinicalAnalysisId).append('\''); sb.append(", creationDate='").append(creationDate).append('\''); sb.append(", modificationDate='").append(modificationDate).append('\''); @@ -99,25 +101,34 @@ public String toString() { sb.append(", secondaryFindings=").append(secondaryFindings); sb.append(", panels=").append(panels); sb.append(", comments=").append(comments); - sb.append(", status=").append(status); sb.append(", locked=").append(locked); + sb.append(", status=").append(status); sb.append(", attributes=").append(attributes); sb.append('}'); return sb.toString(); } public Interpretation toClinicalInterpretation() { - return new Interpretation(null, description, clinicalAnalysisId, analyst != null ? analyst.toClinicalAnalyst() : null, method, + return new Interpretation("", name, description, clinicalAnalysisId, analyst != null ? analyst.toClinicalAnalyst() : null, method, creationDate, modificationDate, locked != null ? locked : false, primaryFindings, secondaryFindings, panels != null ? panels.stream().map(p -> new Panel().setId(p.getId())).collect(Collectors.toList()) : null, comments != null ? comments.stream().map(ClinicalCommentParam::toClinicalComment).collect(Collectors.toList()) : null, - status != null ? status.toStatus() : null, attributes); + status != null ? status.toClinicalStatus() : null, attributes); } public ObjectMap toInterpretationObjectMap() throws JsonProcessingException { return new ObjectMap(getUpdateObjectMapper().writeValueAsString(this.toClinicalInterpretation())); } + public String getName() { + return name; + } + + public InterpretationCreateParams setName(String name) { + this.name = name; + return this; + } + public String getDescription() { return description; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationUpdateParams.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationUpdateParams.java index c0bee8b89ce..3da416d1b28 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationUpdateParams.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/clinical/InterpretationUpdateParams.java @@ -31,6 +31,7 @@ public class InterpretationUpdateParams { + private String name; private String description; private ClinicalAnalystParam analyst; private InterpretationMethod method; @@ -47,11 +48,12 @@ public class InterpretationUpdateParams { public InterpretationUpdateParams() { } - public InterpretationUpdateParams(String description, ClinicalAnalystParam analyst, InterpretationMethod method, + public InterpretationUpdateParams(String name, String description, ClinicalAnalystParam analyst, InterpretationMethod method, String creationDate, String modificationDate, List primaryFindings, List secondaryFindings, List panels, List comments, StatusParam status, Boolean locked, Map attributes) { + this.name = name; this.description = description; this.analyst = analyst; this.method = method; @@ -74,7 +76,8 @@ public ObjectMap getUpdateMap() throws JsonProcessingException { @Override public String toString() { final StringBuilder sb = new StringBuilder("InterpretationUpdateParams{"); - sb.append("description='").append(description).append('\''); + sb.append("name='").append(name).append('\''); + sb.append(", description='").append(description).append('\''); sb.append(", analyst=").append(analyst); sb.append(", method=").append(method); sb.append(", creationDate='").append(creationDate).append('\''); @@ -90,6 +93,15 @@ public String toString() { return sb.toString(); } + public String getName() { + return name; + } + + public InterpretationUpdateParams setName(String name) { + this.name = name; + return this; + } + public String getDescription() { return description; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/IndexStatus.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/IndexStatus.java index 83836d0f7d4..99c35d2b029 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/IndexStatus.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/IndexStatus.java @@ -19,7 +19,7 @@ public class IndexStatus extends InternalStatus { public IndexStatus(String status, String message) { if (isValid(status)) { - init(status, status, message); + init(status, message); } else { throw new IllegalArgumentException("Unknown status " + status); } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/InternalStatus.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/InternalStatus.java index a934efdc3ee..a1d28c6914b 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/InternalStatus.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/InternalStatus.java @@ -57,8 +57,8 @@ public InternalStatus(String id, String description) { } } - public InternalStatus(String id, String name, String description, String date, String version, String commit) { - super(id, name, description, date); + public InternalStatus(String id, String description, String date, String version, String commit) { + super(id, description, date); if (!isValid(id)) { throw new IllegalArgumentException("Unknown status id '" + id + "'"); } @@ -112,12 +112,7 @@ private static void fillPositiveNegativeList(String[] statusList, List p } protected void init(String statusId, String description) { - init(statusId, statusId, description); - } - - protected void init(String statusId, String statusName, String description) { super.id = statusId; - super.name = statusName; super.description = description; super.date = TimeUtils.getTime(); this.version = GitRepositoryState.getInstance().getBuildVersion(); @@ -150,7 +145,6 @@ public String toString() { sb.append("version='").append(version).append('\''); sb.append(", commit='").append(commit).append('\''); sb.append(", id='").append(id).append('\''); - sb.append(", name='").append(name).append('\''); sb.append(", description='").append(description).append('\''); sb.append(", date='").append(date).append('\''); sb.append('}'); @@ -184,15 +178,6 @@ public InternalStatus setId(String id) { return this; } - public String getName() { - return StringUtils.isNotEmpty(name) ? name : id; - } - - public InternalStatus setName(String name) { - this.name = name; - return this; - } - public String getDate() { return date; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/StatusParam.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/StatusParam.java index 806ef09be4d..d826354369e 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/common/StatusParam.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/common/StatusParam.java @@ -2,6 +2,7 @@ import org.opencb.biodata.models.common.Status; import org.opencb.opencga.core.common.TimeUtils; +import org.opencb.opencga.core.models.clinical.ClinicalStatus; public class StatusParam { @@ -18,10 +19,18 @@ public static StatusParam of(Status status) { return status != null ? new StatusParam(status.getId()) : null; } + public static StatusParam of(ClinicalStatus status) { + return status != null ? new StatusParam(status.getId()) : null; + } + public Status toStatus() { return new Status(id, "", "", TimeUtils.getTime()); } + public ClinicalStatus toClinicalStatus() { + return new ClinicalStatus(id, "", null, "", "", "", ""); + } + @Override public String toString() { final StringBuilder sb = new StringBuilder("StatusParam{"); diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/file/VariantIndexStatus.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/file/VariantIndexStatus.java index a6592c369bf..1e44390761c 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/file/VariantIndexStatus.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/file/VariantIndexStatus.java @@ -24,7 +24,7 @@ public class VariantIndexStatus extends IndexStatus { public VariantIndexStatus(String status, String message) { if (isValid(status)) { - init(status, status, message); + init(status, message); } else { throw new IllegalArgumentException("Unknown status " + status); } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/sample/Sample.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/sample/Sample.java index f45e545a292..10b42230abe 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/sample/Sample.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/sample/Sample.java @@ -107,8 +107,7 @@ public class Sample extends Annotable { private int release; /** - * Generic: Autoincremental version assigned to the registered entry. By default, updates does not create new versions. To enable - * versioning, users must set the `incVersion` flag from the /update web service when updating the document. + * Generic: Autoincremental version assigned to the registered entry. * * @apiNote Immutable */ 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 b7dba9c36de..75f627af7f3 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 @@ -109,7 +109,10 @@ public enum Permissions { 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); + ClinicalAnalysisPermissions.DELETE_ANNOTATIONS.name(), CLINICAL_ANALYSIS), + ADMIN_CLINICAL_ANALYSIS(Arrays.asList(VIEW_CLINICAL_ANALYSIS, WRITE_CLINICAL_ANALYSIS, DELETE_CLINICAL_ANALYSIS, + VIEW_CLINICAL_ANNOTATIONS, WRITE_CLINICAL_ANNOTATIONS, DELETE_CLINICAL_ANNOTATIONS), + ClinicalAnalysisPermissions.ADMIN.name(), CLINICAL_ANALYSIS); private final static Map map; diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/ClinicalAnalysisStudyConfiguration.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/ClinicalAnalysisStudyConfiguration.java index 97d09661407..5f71fe0c6b9 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/ClinicalAnalysisStudyConfiguration.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/ClinicalAnalysisStudyConfiguration.java @@ -1,26 +1,27 @@ package org.opencb.opencga.core.models.study.configuration; -import org.opencb.opencga.core.models.clinical.ClinicalAnalysis; -import org.opencb.opencga.core.models.common.FlagValue; import org.opencb.opencga.core.models.clinical.ClinicalStatusValue; +import org.opencb.opencga.core.models.common.FlagValue; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; public class ClinicalAnalysisStudyConfiguration { - private Map> status; + private List status; private InterpretationStudyConfiguration interpretation; private List priorities; - private Map> flags; + private List flags; private ClinicalConsentConfiguration consent; public ClinicalAnalysisStudyConfiguration() { } - public ClinicalAnalysisStudyConfiguration(Map> status, - InterpretationStudyConfiguration interpretation, List priorities, - Map> flags, ClinicalConsentConfiguration consent) { + public ClinicalAnalysisStudyConfiguration(List status, InterpretationStudyConfiguration interpretation, + List priorities, List flags, + ClinicalConsentConfiguration consent) { this.status = status; this.interpretation = interpretation; this.priorities = priorities; @@ -29,20 +30,21 @@ public ClinicalAnalysisStudyConfiguration(Map> status = new HashMap<>(); - Map> interpretationStatus = new HashMap<>(); + List clinicalStatusValueList = new ArrayList<>(4); + List interpretationStatusList = new ArrayList<>(3); List priorities = new ArrayList<>(5); - Map> flags = new HashMap<>(); List clinicalConsentList = new ArrayList<>(); - List clinicalStatusValueList = new ArrayList<>(4); clinicalStatusValueList.add( new ClinicalStatusValue("READY_FOR_INTERPRETATION", "The Clinical Analysis is ready for interpretations", ClinicalStatusValue.ClinicalStatusType.NOT_STARTED) ); clinicalStatusValueList.add( new ClinicalStatusValue("READY_FOR_REPORT", "The Interpretation is finished and it is to create the report", - ClinicalStatusValue.ClinicalStatusType.IN_PROGRESS) + ClinicalStatusValue.ClinicalStatusType.ACTIVE) + ); + clinicalStatusValueList.add( + new ClinicalStatusValue("DONE", "The Clinical Analysis is done", ClinicalStatusValue.ClinicalStatusType.DONE) ); clinicalStatusValueList.add( new ClinicalStatusValue("CLOSED", "The Clinical Analysis is closed", ClinicalStatusValue.ClinicalStatusType.CLOSED) @@ -50,21 +52,12 @@ public static ClinicalAnalysisStudyConfiguration defaultConfiguration() { clinicalStatusValueList.add( new ClinicalStatusValue("REJECTED", "The Clinical Analysis is rejected", ClinicalStatusValue.ClinicalStatusType.CLOSED) ); - status.put(ClinicalAnalysis.Type.FAMILY, clinicalStatusValueList); - status.put(ClinicalAnalysis.Type.AUTOCOMPARATIVE, clinicalStatusValueList); - status.put(ClinicalAnalysis.Type.CANCER, clinicalStatusValueList); - status.put(ClinicalAnalysis.Type.COHORT, clinicalStatusValueList); - status.put(ClinicalAnalysis.Type.SINGLE, clinicalStatusValueList); - List interpretationStatusList = new ArrayList<>(3); - interpretationStatusList.add(new ClinicalStatusValue("IN_PROGRESS", "Interpretation in progress", ClinicalStatusValue.ClinicalStatusType.IN_PROGRESS)); + interpretationStatusList.add(new ClinicalStatusValue("NOT_STARTED", "Interpretation not started", ClinicalStatusValue.ClinicalStatusType.NOT_STARTED)); + interpretationStatusList.add(new ClinicalStatusValue("IN_PROGRESS", "Interpretation in progress", ClinicalStatusValue.ClinicalStatusType.ACTIVE)); + interpretationStatusList.add(new ClinicalStatusValue("DONE", "Interpretation done", ClinicalStatusValue.ClinicalStatusType.DONE)); interpretationStatusList.add(new ClinicalStatusValue("READY", "Interpretation ready", ClinicalStatusValue.ClinicalStatusType.CLOSED)); interpretationStatusList.add(new ClinicalStatusValue("REJECTED", "Interpretation rejected", ClinicalStatusValue.ClinicalStatusType.CLOSED)); - interpretationStatus.put(ClinicalAnalysis.Type.FAMILY, interpretationStatusList); - interpretationStatus.put(ClinicalAnalysis.Type.AUTOCOMPARATIVE, interpretationStatusList); - interpretationStatus.put(ClinicalAnalysis.Type.CANCER, interpretationStatusList); - interpretationStatus.put(ClinicalAnalysis.Type.COHORT, interpretationStatusList); - interpretationStatus.put(ClinicalAnalysis.Type.SINGLE, interpretationStatusList); priorities.add(new ClinicalPriorityValue("URGENT", "Highest priority of all", 1, false)); priorities.add(new ClinicalPriorityValue("HIGH", "Second highest priority of all", 2, false)); @@ -80,20 +73,15 @@ public static ClinicalAnalysisStudyConfiguration defaultConfiguration() { flagValueList.add(new FlagValue("UNUSUAL_KARYOTYPE", "")); flagValueList.add(new FlagValue("SUSPECTED_MOSAICISM", "")); flagValueList.add(new FlagValue("LOW_QUALITY_SAMPLE", "")); - flags.put(ClinicalAnalysis.Type.FAMILY, flagValueList); - flags.put(ClinicalAnalysis.Type.AUTOCOMPARATIVE, flagValueList); - flags.put(ClinicalAnalysis.Type.CANCER, flagValueList); - flags.put(ClinicalAnalysis.Type.COHORT, flagValueList); - flags.put(ClinicalAnalysis.Type.SINGLE, flagValueList); clinicalConsentList.add(new ClinicalConsent("PRIMARY_FINDINGS", "Primary findings", "")); clinicalConsentList.add(new ClinicalConsent("SECONDARY_FINDINGS", "Secondary findings", "")); clinicalConsentList.add(new ClinicalConsent("CARRIER_FINDINGS", "Carrier findings", "")); clinicalConsentList.add(new ClinicalConsent("RESEARCH_FINDINGS", "Research findings", "")); - return new ClinicalAnalysisStudyConfiguration(status, - new InterpretationStudyConfiguration(interpretationStatus, Collections.emptyList(), Collections.emptyMap(), - Collections.emptyList()), priorities, flags, new ClinicalConsentConfiguration(clinicalConsentList)); + return new ClinicalAnalysisStudyConfiguration(clinicalStatusValueList, + new InterpretationStudyConfiguration(interpretationStatusList, Collections.emptyList(), Collections.emptyMap(), + Collections.emptyList()), priorities, flagValueList, new ClinicalConsentConfiguration(clinicalConsentList)); } @Override @@ -108,11 +96,11 @@ public String toString() { return sb.toString(); } - public Map> getStatus() { + public List getStatus() { return status; } - public ClinicalAnalysisStudyConfiguration setStatus(Map> status) { + public ClinicalAnalysisStudyConfiguration setStatus(List status) { this.status = status; return this; } @@ -135,11 +123,11 @@ public ClinicalAnalysisStudyConfiguration setPriorities(List> getFlags() { + public List getFlags() { return flags; } - public ClinicalAnalysisStudyConfiguration setFlags(Map> flags) { + public ClinicalAnalysisStudyConfiguration setFlags(List flags) { this.flags = flags; return this; } diff --git a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/InterpretationStudyConfiguration.java b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/InterpretationStudyConfiguration.java index b038fd5674d..0b9c98a780a 100644 --- a/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/InterpretationStudyConfiguration.java +++ b/opencga-core/src/main/java/org/opencb/opencga/core/models/study/configuration/InterpretationStudyConfiguration.java @@ -1,6 +1,5 @@ package org.opencb.opencga.core.models.study.configuration; -import org.opencb.opencga.core.models.clinical.ClinicalAnalysis; import org.opencb.opencga.core.models.clinical.ClinicalStatusValue; import java.util.List; @@ -8,16 +7,16 @@ public class InterpretationStudyConfiguration { - private Map> status; + private List status; private List variantCallers; + @Deprecated private Map defaultFilter; private List inclusion; public InterpretationStudyConfiguration() { } - public InterpretationStudyConfiguration(Map> status, - List variantCallers, + public InterpretationStudyConfiguration(List status, List variantCallers, Map defaultFilter, List inclusion) { this.status = status; this.variantCallers = variantCallers; @@ -36,11 +35,11 @@ public String toString() { return sb.toString(); } - public Map> getStatus() { + public List getStatus() { return status; } - public InterpretationStudyConfiguration setStatus(Map> status) { + public InterpretationStudyConfiguration setStatus(List status) { this.status = status; return this; } @@ -54,10 +53,12 @@ public InterpretationStudyConfiguration setVariantCallers(List getDefaultFilter() { return defaultFilter; } + @Deprecated public InterpretationStudyConfiguration setDefaultFilter(Map defaultFilter) { this.defaultFilter = defaultFilter; return this; 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 f893c1f5986..3dd6fa53aa4 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 @@ -401,13 +401,14 @@ public Response delete( public Response info( @ApiParam(value = ParamConstants.CLINICAL_ANALYSES_DESCRIPTION) @PathParam(value = "clinicalAnalysis") String clinicalAnalysisStr, @ApiParam(value = ParamConstants.STUDY_DESCRIPTION) @QueryParam(ParamConstants.STUDY_PARAM) String studyStr, + @ApiParam(value = ParamConstants.CLINICAL_VERSION_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_VERSION_PARAM) String version, @ApiParam(value = ParamConstants.DELETED_DESCRIPTION, defaultValue = "false") @QueryParam(ParamConstants.DELETED_PARAM) boolean deleted) { try { query.remove(ParamConstants.STUDY_PARAM); query.remove("clinicalAnalysis"); List analysisList = getIdList(clinicalAnalysisStr); - DataResult analysisResult = clinicalManager.get(studyStr, analysisList, queryOptions, true, token); + DataResult analysisResult = clinicalManager.get(studyStr, analysisList, query, queryOptions, true, token); return createOkResponse(analysisResult); } catch (Exception e) { return createErrorResponse(e); @@ -450,6 +451,7 @@ public Response search( @ApiParam(value = ParamConstants.CLINICAL_DUE_DATE_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_DUE_DATE_PARAM) String dueDate, @ApiParam(value = ParamConstants.CLINICAL_QUALITY_CONTROL_SUMMARY_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_QUALITY_CONTROL_SUMMARY_PARAM) String qualityControl, @ApiParam(value = ParamConstants.CLINICAL_RELEASE_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_RELEASE_PARAM) String release, + @ApiParam(value = ParamConstants.SNAPSHOT_DESCRIPTION) @QueryParam(ParamConstants.SNAPSHOT_PARAM) int snapshot, @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, @@ -490,6 +492,7 @@ public Response distinct( @ApiParam(value = ParamConstants.CLINICAL_DUE_DATE_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_DUE_DATE_PARAM) String dueDate, @ApiParam(value = ParamConstants.CLINICAL_QUALITY_CONTROL_SUMMARY_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_QUALITY_CONTROL_SUMMARY_PARAM) String qualityControl, @ApiParam(value = ParamConstants.CLINICAL_RELEASE_DESCRIPTION) @QueryParam(ParamConstants.CLINICAL_RELEASE_PARAM) String release, + @ApiParam(value = ParamConstants.SNAPSHOT_DESCRIPTION) @QueryParam(ParamConstants.SNAPSHOT_PARAM) int snapshot, @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, @@ -767,6 +770,7 @@ public Response interpretationSearch( @ApiParam(value = ParamConstants.STUDY_DESCRIPTION) @QueryParam(ParamConstants.STUDY_PARAM) String studyStr, @ApiParam(value = ParamConstants.INTERPRETATION_ID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_ID_PARAM) String id, @ApiParam(value = ParamConstants.INTERPRETATION_UUID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_UUID_PARAM) String uuid, + @ApiParam(value = ParamConstants.INTERPRETATION_NAME_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_NAME_PARAM) String name, @ApiParam(value = ParamConstants.INTERPRETATION_CLINICAL_ANALYSIS_ID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_CLINICAL_ANALYSIS_ID_PARAM) String clinicalAnalysisId, @ApiParam(value = ParamConstants.INTERPRETATION_ANALYST_ID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_ANALYST_ID_PARAM) String analystId, @ApiParam(value = ParamConstants.INTERPRETATION_METHOD_NAME_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_METHOD_NAME_PARAM) String method, @@ -800,6 +804,7 @@ public Response interpretationDistinct( @ApiParam(value = ParamConstants.STUDY_DESCRIPTION) @QueryParam(ParamConstants.STUDY_PARAM) String studyStr, @ApiParam(value = ParamConstants.INTERPRETATION_ID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_ID_PARAM) String id, @ApiParam(value = ParamConstants.INTERPRETATION_UUID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_UUID_PARAM) String uuid, + @ApiParam(value = ParamConstants.INTERPRETATION_NAME_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_NAME_PARAM) String name, @ApiParam(value = ParamConstants.INTERPRETATION_CLINICAL_ANALYSIS_ID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_CLINICAL_ANALYSIS_ID_PARAM) String clinicalAnalysisId, @ApiParam(value = ParamConstants.INTERPRETATION_ANALYST_ID_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_ANALYST_ID_PARAM) String analystId, @ApiParam(value = ParamConstants.INTERPRETATION_METHOD_NAME_DESCRIPTION) @QueryParam(ParamConstants.INTERPRETATION_METHOD_NAME_PARAM) String methodsName,