Skip to content

Commit

Permalink
core: add new CVDB index status in Clinical Analysis, #TASK-5610
Browse files Browse the repository at this point in the history
  • Loading branch information
pfurio committed Nov 18, 2024
1 parent e6160e0 commit 3253853
Show file tree
Hide file tree
Showing 7 changed files with 246 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.opencb.opencga.app.migrations.v4.v4_0_0.catalog;

import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Updates;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.opencb.opencga.catalog.db.api.ClinicalAnalysisDBAdaptor;
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.models.clinical.ClinicalStatusValue;
import org.opencb.opencga.core.models.clinical.CvdbIndexStatus;

import java.util.Arrays;

@Migration(id = "add_cvdb_index_to_clinical_analysis",
description = "Add CVDB index status to Clinical Analysis #TASK-5610", version = "4.0.0",
language = Migration.MigrationLanguage.JAVA, domain = Migration.MigrationDomain.CATALOG, date = 20241118)
public class ClinicalCvdbIndexMigration extends MigrationTool {

@Override
protected void run() throws Exception {
Bson closedCaseQuery = Filters.and(
Filters.exists(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), false),
Filters.eq("status.type", ClinicalStatusValue.ClinicalStatusType.CLOSED)
);
Bson openCaseQuery = Filters.and(
Filters.exists(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), false),
Filters.ne("status.type", ClinicalStatusValue.ClinicalStatusType.CLOSED)
);
CvdbIndexStatus pendingCvdbIndexStatus = new CvdbIndexStatus(CvdbIndexStatus.PENDING);
Document pendingCvdbIndexDoc = convertToDocument(pendingCvdbIndexStatus);
Bson updateClosedCase = Updates.set(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), pendingCvdbIndexDoc);

CvdbIndexStatus noneCvdbIndexStatus = new CvdbIndexStatus(CvdbIndexStatus.NONE);
Document noneCvdbIndexDoc = convertToDocument(noneCvdbIndexStatus);
Bson updateOpenCase = Updates.set(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), noneCvdbIndexDoc);

for (String collection : Arrays.asList(OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_COLLECTION,
OrganizationMongoDBAdaptorFactory.CLINICAL_ANALYSIS_ARCHIVE_COLLECTION,
OrganizationMongoDBAdaptorFactory.DELETED_CLINICAL_ANALYSIS_COLLECTION)) {
getMongoCollection(collection).updateMany(closedCaseQuery, updateClosedCase);
getMongoCollection(collection).updateMany(openCaseQuery, updateOpenCase);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ enum QueryParams implements QueryParam {
INTERNAL_STATUS("internal.status", TEXT_ARRAY, ""),
INTERNAL_STATUS_ID("internal.status.id", TEXT, ""),
INTERNAL_STATUS_DATE("internal.status.date", TEXT, ""),
INTERNAL_CVDB_INDEX("internal.cvdbIndex", OBJECT, ""),
QUALITY_CONTROL("qualityControl", OBJECT, ""),
QUALITY_CONTROL_SUMMARY("qualityControl.summary", TEXT, ""),
CONSENT("consent", OBJECT, ""),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
import org.opencb.opencga.core.common.JacksonUtils;
import org.opencb.opencga.core.common.TimeUtils;
import org.opencb.opencga.core.config.Configuration;
import org.opencb.opencga.core.models.clinical.*;
import org.opencb.opencga.core.models.clinical.ClinicalAnalysis;
import org.opencb.opencga.core.models.clinical.ClinicalAnalysisPermissions;
import org.opencb.opencga.core.models.clinical.FlagValueParam;
import org.opencb.opencga.core.models.clinical.Interpretation;
import org.opencb.opencga.core.models.common.AnnotationSet;
import org.opencb.opencga.core.models.common.Enums;
import org.opencb.opencga.core.models.common.FlagAnnotation;
Expand Down Expand Up @@ -451,7 +454,7 @@ UpdateDocument parseAndValidateUpdateParams(ObjectMap parameters, List<ClinicalA
String[] acceptedObjectParams = {QueryParams.FAMILY.key(), QueryParams.DISORDER.key(), QUALITY_CONTROL.key(),
QueryParams.PROBAND.key(), QueryParams.ALERTS.key(), QueryParams.INTERNAL_STATUS.key(), QueryParams.PRIORITY.key(),
QueryParams.CONSENT.key(), QueryParams.STATUS.key(), QueryParams.INTERPRETATION.key(), REPORT.key(),
REQUEST.key(), RESPONSIBLE.key(), ATTRIBUTES.key(), };
INTERNAL_CVDB_INDEX.key(), REQUEST.key(), RESPONSIBLE.key(), ATTRIBUTES.key(), };
filterObjectParams(parameters, document.getSet(), acceptedObjectParams);

if (parameters.containsKey(INTERPRETATION.key()) && parameters.get(INTERPRETATION.key()) == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -597,9 +597,15 @@ public OpenCGAResult<ClinicalAnalysis> create(String studyStr, ClinicalAnalysis
if (clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) {
String msg = "Case '" + clinicalAnalysis.getId() + "' created with status '"
+ clinicalAnalysis.getStatus().getId() + "', which is of type CLOSED. Automatically locking "
+ "ClinicalAnalysis.";
+ "ClinicalAnalysis and setting CVDB index status to PENDING.";
logger.info(msg);
clinicalAnalysis.setLocked(true);

CvdbIndexStatus cvdbIndexStatus = new CvdbIndexStatus(CvdbIndexStatus.PENDING, "User '" + userId
+ "' created case with status '" + clinicalAnalysis.getStatus().getId() + "', which is of type"
+ " CLOSED. Automatically setting CVDB index status to " + CvdbIndexStatus.PENDING);
clinicalAnalysis.getInternal().setCvdbIndex(cvdbIndexStatus);

events.add(new Event(Event.Type.INFO, clinicalAnalysis.getId(), msg));
}
}
Expand Down Expand Up @@ -761,7 +767,7 @@ private void load(ClinicalAnalysis clinicalAnalysis, String study, String token)
}
}

private void validateAndInitReport(String organizationId, Study study, ClinicalReport report, String userId)
private void validateAndInitReport(String organizationId, Study study, ClinicalReport report, String userId)
throws CatalogException {
if (report == null) {
return;
Expand Down Expand Up @@ -1448,6 +1454,12 @@ private OpenCGAResult<ClinicalAnalysis> update(String organizationId, Study stud
throw new CatalogException("ClinicalAnalysis already have the status '" + clinicalAnalysis.getStatus().getId()
+ "' of type " + ClinicalStatusValue.ClinicalStatusType.CLOSED);
}
} else {
// The user wants to remove the CLOSED status
CvdbIndexStatus cvdbIndexStatus = new CvdbIndexStatus(CvdbIndexStatus.PENDING_REMOVE, "User '" + userId
+ "' requested to remove the status '" + clinicalAnalysis.getStatus().getId() + "' of type "
+ ClinicalStatusValue.ClinicalStatusType.CLOSED + " to set it to '" + updateParams.getStatus().getId() + "'");
parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), cvdbIndexStatus);
}
}

Expand Down Expand Up @@ -1733,10 +1745,28 @@ private OpenCGAResult<ClinicalAnalysis> update(String organizationId, Study stud
if (clinicalStatusValue.getType() == ClinicalStatusValue.ClinicalStatusType.CLOSED) {
String msg = "User '" + userId + "' changed case '" + clinicalAnalysis.getId() + "' to status '"
+ updateParamsClone.getStatus().getId() + "', which is of type CLOSED. Automatically locking "
+ "ClinicalAnalysis";
+ "ClinicalAnalysis and changing CVDB index status to be indexed";
logger.info(msg);
parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.LOCKED.key(), true);
events.add(new Event(Event.Type.INFO, clinicalAnalysis.getId(), msg));

if (StringUtils.isEmpty(clinicalAnalysis.getInternal().getCvdbIndex().getId())
|| clinicalAnalysis.getInternal().getCvdbIndex().getId().equals(CvdbIndexStatus.NONE)) {
CvdbIndexStatus cvdbIndexStatus = new CvdbIndexStatus(CvdbIndexStatus.PENDING, "User '" + userId
+ "' changed case to status '" + updateParamsClone.getStatus().getId() + "', which is of type"
+ " CLOSED. Automatically changing CVDB index status to " + CvdbIndexStatus.PENDING);
parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), cvdbIndexStatus);
} else if (clinicalAnalysis.getInternal().getCvdbIndex().getId().equals(CvdbIndexStatus.PENDING_REMOVE)) {
CvdbIndexStatus cvdbIndexStatus = new CvdbIndexStatus(CvdbIndexStatus.PENDING_OVERWRITE, "User '" + userId
+ "' changed case to status '" + updateParamsClone.getStatus().getId() + "', which is of type"
+ " CLOSED. CVDB index was already in " + CvdbIndexStatus.PENDING_REMOVE + ", so automatically"
+ " changing CVDB index status to " + CvdbIndexStatus.PENDING_OVERWRITE);
parameters.put(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), cvdbIndexStatus);
} else {
logger.warn("CVDB index status is unexpectedly set to '{}'. Although the user is closing the case, OpenCGA"
+ " cannot automatically infer which should be the new CVDB index status.",
clinicalAnalysis.getInternal().getCvdbIndex().getId());
}
}
}
}
Expand All @@ -1760,7 +1790,7 @@ private OpenCGAResult<ClinicalAnalysis> update(String organizationId, Study stud
}

public OpenCGAResult<ClinicalReport> updateReport(String studyStr, String clinicalAnalysisId, ClinicalReport report,
QueryOptions options, String token) throws CatalogException {
QueryOptions options, String token) throws CatalogException {
JwtPayload tokenPayload = catalogManager.getUserManager().validateToken(token);
CatalogFqn studyFqn = CatalogFqn.extractFqnFromStudy(studyStr, tokenPayload);

Expand Down Expand Up @@ -1847,6 +1877,43 @@ public OpenCGAResult<ClinicalReport> updateReport(String studyStr, String clinic
}
}

public OpenCGAResult<?> updateCvdbIndex(String studyFqn, ClinicalAnalysis clinical, CvdbIndexStatus index, String token)
throws CatalogException {
JwtPayload tokenPayload = catalogManager.getUserManager().validateToken(token);
CatalogFqn catalogFqn = CatalogFqn.extractFqnFromStudy(studyFqn, tokenPayload);
String organizationId = catalogFqn.getOrganizationId();
String userId = tokenPayload.getUserId(organizationId);

ObjectMap auditParams = new ObjectMap()
.append("studyFqn", studyFqn)
.append("clinical", clinical.getId())
.append("cvdbIndex", index)
.append("token", token);

String studyId = studyFqn;
String studyUuid = "";
try {
authorizationManager.checkIsAtLeastOrganizationOwnerOrAdmin(organizationId, userId);
Study study = studyManager.resolveId(catalogFqn, StudyManager.INCLUDE_STUDY_IDS, tokenPayload);
studyId = study.getFqn();
studyUuid = study.getUuid();

ObjectMap valueAsMap = new ObjectMap(getUpdateObjectMapper().writeValueAsString(index));
ObjectMap params = new ObjectMap(ClinicalAnalysisDBAdaptor.QueryParams.INTERNAL_CVDB_INDEX.key(), valueAsMap);

OpenCGAResult<?> update = getClinicalAnalysisDBAdaptor(organizationId).update(clinical.getUid(), params, QueryOptions.empty());
auditManager.audit(organizationId, userId, Enums.Action.UPDATE_INTERNAL, Enums.Resource.CLINICAL_ANALYSIS, clinical.getId(),
clinical.getUuid(), studyId, studyUuid, auditParams, new AuditRecord.Status(AuditRecord.Status.Result.SUCCESS));
return new OpenCGAResult<>(update.getTime(), update.getEvents(), 1, Collections.emptyList(), 1);
} catch (Exception e) {
auditManager.audit(organizationId, userId, Enums.Action.UPDATE_INTERNAL, Enums.Resource.CLINICAL_ANALYSIS, clinical.getId(),
clinical.getUuid(), studyId, studyUuid, auditParams, new AuditRecord.Status(AuditRecord.Status.Result.ERROR,
new Error().setName(e.getMessage())));
throw new CatalogException("Could not update CVDB Index status: " + e.getMessage(), e);
}
}


/**
* Sort the family members in the following order: proband, father, mother, others.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,27 @@

public class ClinicalAnalysisInternal extends Internal {

private CvdbIndexStatus cvdbIndex;

public ClinicalAnalysisInternal() {
}

public ClinicalAnalysisInternal(String registrationDate, String modificationDate, InternalStatus status) {
super(status, registrationDate, modificationDate);
public ClinicalAnalysisInternal(InternalStatus status, String registrationDate, String lastModified, CvdbIndexStatus cvdbIndex) {
super(status, registrationDate, lastModified);
this.cvdbIndex = cvdbIndex;
}

public static ClinicalAnalysisInternal init() {
return new ClinicalAnalysisInternal(TimeUtils.getTime(), TimeUtils.getTime(), new InternalStatus());
return new ClinicalAnalysisInternal(new InternalStatus(), TimeUtils.getTime(), TimeUtils.getTime(), new CvdbIndexStatus());
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ClinicalAnalysisInternal{");
sb.append("status=").append(status);
sb.append("cvdbIndex=").append(cvdbIndex);
sb.append(", status=").append(status);
sb.append(", registrationDate='").append(registrationDate).append('\'');
sb.append(", modificationDate='").append(lastModified).append('\'');
sb.append(", lastModified='").append(lastModified).append('\'');
sb.append('}');
return sb.toString();
}
Expand Down Expand Up @@ -69,4 +73,13 @@ public ClinicalAnalysisInternal setLastModified(String lastModified) {
this.lastModified = lastModified;
return this;
}

public CvdbIndexStatus getCvdbIndex() {
return cvdbIndex;
}

public ClinicalAnalysisInternal setCvdbIndex(CvdbIndexStatus cvdbIndex) {
this.cvdbIndex = cvdbIndex;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.opencb.opencga.core.models.clinical;

import org.opencb.opencga.core.models.common.OperationIndexStatus;

import java.util.Arrays;
import java.util.List;

public class CvdbIndexStatus extends OperationIndexStatus {

public static final String ERROR = "ERROR";
public static final String PENDING_REMOVE = "PENDING_REMOVE";
public static final String PENDING_OVERWRITE = "PENDING_OVERWRITE";

public static final List<String> STATUS_LIST = Arrays.asList(NONE, PENDING, PENDING_REMOVE, PENDING_OVERWRITE, READY, ERROR);

public CvdbIndexStatus(String status, String message) {
if (isValid(status)) {
init(status, message);
} else {
throw new IllegalArgumentException("Unknown status " + status);
}
}

public CvdbIndexStatus(String status) {
this(status, "");
}

public CvdbIndexStatus() {
this(NONE, "");
}

@Override
public String getId() {
return super.getId();
}

@Override
public String getName() {
return super.getName();
}

public static CvdbIndexStatus init() {
return new CvdbIndexStatus();
}

public static boolean isValid(String status) {
return status != null
&& (status.equals(NONE)
|| status.equals(PENDING)
|| status.equals(PENDING_REMOVE)
|| status.equals(PENDING_OVERWRITE)
|| status.equals(READY)
|| status.equals(ERROR));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.opencb.opencga.core.models.common;

import java.util.Arrays;
import java.util.List;

public class OperationIndexStatus extends IndexStatus {

public static final String PENDING = "PENDING";

public static final List<String> STATUS_LIST = Arrays.asList(READY, PENDING, NONE);

public OperationIndexStatus(String status, String message) {
if (isValid(status)) {
init(status, message);
} else {
throw new IllegalArgumentException("Unknown status " + status);
}
}

public OperationIndexStatus(String status) {
this(status, "");
}

public OperationIndexStatus() {
this(NONE, "");
}

@Override
public String getId() {
return super.getId();
}

@Override
public String getName() {
return super.getName();
}

public static OperationIndexStatus init() {
return new OperationIndexStatus();
}

public static boolean isValid(String status) {
return status != null
&& (status.equals(READY)
|| status.equals(PENDING)
|| status.equals(NONE));
}
}

0 comments on commit 3253853

Please sign in to comment.