Skip to content

Commit

Permalink
[bench-4474] Return Cohort SQL in describeExport response (#1058)
Browse files Browse the repository at this point in the history
  • Loading branch information
dexamundsen authored Nov 1, 2024
1 parent 21e4b1b commit 66993e9
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,7 @@ public ResponseEntity<Void> deleteCohort(
@Override
public ResponseEntity<ApiCohort> getCohort(
String studyId, String cohortId, String cohortRevisionId) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(COHORT, READ),
ResourceId.forCohort(studyId, cohortId));
accessControlService.checkReadAccess(studyId, List.of(cohortId), List.of());
return ResponseEntity.ok(ToApiUtils.toApiObject(cohortService.getCohort(studyId, cohortId)));
}

Expand Down Expand Up @@ -162,10 +159,7 @@ public ResponseEntity<ApiCohort> cloneCohort(
@Override
public ResponseEntity<ApiInstanceCountList> queryCohortCounts(
String studyId, String cohortId, ApiCohortCountQuery body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(COHORT, READ),
ResourceId.forCohort(studyId, cohortId));
accessControlService.checkReadAccess(studyId, List.of(cohortId), List.of());
Cohort cohort = cohortService.getCohort(studyId, cohortId);

accessControlService.throwIfUnauthorized(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package bio.terra.tanagra.app.controller;

import static bio.terra.tanagra.service.accesscontrol.Action.READ;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.COHORT;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.FEATURE_SET;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.UNDERLAY;

import bio.terra.tanagra.api.field.AttributeField;
import bio.terra.tanagra.api.field.ValueDisplayField;
import bio.terra.tanagra.api.filter.EntityFilter;
import bio.terra.tanagra.api.query.list.ListQueryRequest;
import bio.terra.tanagra.api.query.list.ListQueryResult;
import bio.terra.tanagra.app.authentication.SpringAuthentication;
Expand All @@ -25,8 +21,6 @@
import bio.terra.tanagra.generated.model.ApiInstanceListResult;
import bio.terra.tanagra.service.UnderlayService;
import bio.terra.tanagra.service.accesscontrol.AccessControlService;
import bio.terra.tanagra.service.accesscontrol.Permissions;
import bio.terra.tanagra.service.accesscontrol.ResourceId;
import bio.terra.tanagra.service.artifact.CohortService;
import bio.terra.tanagra.service.artifact.FeatureSetService;
import bio.terra.tanagra.service.artifact.StudyService;
Expand Down Expand Up @@ -83,10 +77,7 @@ public ExportApiController(

@Override
public ResponseEntity<ApiExportModelList> listExportModels(String underlayName) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
// Get a map of implementation name -> (display name, class instance).
List<DataExportModel> exportModels = dataExportService.getModels(underlayName);
ApiExportModelList apiExportImpls = new ApiExportModelList();
Expand All @@ -97,32 +88,18 @@ public ResponseEntity<ApiExportModelList> listExportModels(String underlayName)
@Override
public ResponseEntity<ApiInstanceListResult> previewExportInstances(
String underlayName, String entityName, ApiExportPreviewRequest body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
for (String cohortId : body.getCohorts()) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(COHORT, READ),
ResourceId.forCohort(body.getStudy(), cohortId));
}
for (String featureSetId : body.getFeatureSets()) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(FEATURE_SET, READ),
ResourceId.forFeatureSet(body.getStudy(), featureSetId));
}
accessControlService.checkUnderlayAccess(underlayName);
accessControlService.checkReadAccess(body.getStudy(), body.getCohorts(), body.getFeatureSets());

// Build the entity outputs.
// Build the entity output previews.
List<Cohort> cohorts =
body.getCohorts().stream()
.map(cohortId -> cohortService.getCohort(body.getStudy(), cohortId))
.collect(Collectors.toList());
.toList();
List<FeatureSet> featureSets =
body.getFeatureSets().stream()
.map(featureSetId -> featureSetService.getFeatureSet(body.getStudy(), featureSetId))
.collect(Collectors.toList());
.toList();
List<EntityOutputPreview> entityOutputPreviews =
filterBuilderService.buildOutputPreviewsForExport(
cohorts, featureSets, body.isIncludeAllAttributes());
Expand Down Expand Up @@ -169,26 +146,18 @@ public ResponseEntity<ApiInstanceListResult> previewExportInstances(
@Override
public ResponseEntity<ApiEntityOutputPreviewList> describeExport(
String underlayName, ApiExportPreviewRequest body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
for (String featureSetId : body.getFeatureSets()) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(FEATURE_SET, READ),
ResourceId.forFeatureSet(body.getStudy(), featureSetId));
}
accessControlService.checkUnderlayAccess(underlayName);
accessControlService.checkReadAccess(body.getStudy(), body.getCohorts(), body.getFeatureSets());

// Build the entity output previews.
List<Cohort> cohorts =
body.getCohorts().stream()
.map(cohortId -> cohortService.getCohort(body.getStudy(), cohortId))
.collect(Collectors.toList());
.toList();
List<FeatureSet> featureSets =
body.getFeatureSets().stream()
.map(featureSetId -> featureSetService.getFeatureSet(body.getStudy(), featureSetId))
.collect(Collectors.toList());
.toList();
List<EntityOutputPreview> entityOutputPreviews =
filterBuilderService.buildOutputPreviewsForExport(
cohorts, featureSets, body.isIncludeAllAttributes());
Expand Down Expand Up @@ -250,32 +219,26 @@ public ResponseEntity<ApiEntityOutputPreviewList> describeExport(
SqlFormatter.format(sourceSqlForEntityOutputs.get(entityOutputPreview)));
apiEntityOutputs.addEntityOutputsItem(apiEntityOutput);
});
return ResponseEntity.ok(apiEntityOutputs);

EntityFilter combinedCohortFilter =
filterBuilderService.buildFilterForCohortRevisions(
underlayName,
cohorts.stream().map(Cohort::getMostRecentRevision).collect(Collectors.toList()));
Entity idEntity = underlay.getPrimaryEntity();
AttributeField idAttributeField =
new AttributeField(underlay, idEntity, idEntity.getIdAttribute(), true);
ListQueryRequest indexListQueryRequest =
ListQueryRequest.dryRunAgainstIndexData(
underlay, idEntity, List.of(idAttributeField), combinedCohortFilter, null, null);
String entityIdSql = underlay.getQueryRunner().run(indexListQueryRequest).getSqlNoParams();
return ResponseEntity.ok(apiEntityOutputs.entityIdSql(SqlFormatter.format(entityIdSql)));
}

@Override
public ResponseEntity<ApiExportResult> exportInstancesAndAnnotations(
String underlayName, ApiExportRequest body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
for (String cohortId : body.getCohorts()) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(COHORT, READ),
ResourceId.forCohort(body.getStudy(), cohortId));
}
List<String> featureSetIds = new ArrayList<>();
if (body.getFeatureSets() != null) {
featureSetIds.addAll(body.getFeatureSets());
}
for (String featureSetId : featureSetIds) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(FEATURE_SET, READ),
ResourceId.forFeatureSet(body.getStudy(), featureSetId));
}
accessControlService.checkUnderlayAccess(underlayName);
accessControlService.checkReadAccess(body.getStudy(), body.getCohorts(), body.getFeatureSets());

Underlay underlay = underlayService.getUnderlay(underlayName);
Study study = studyService.getStudy(body.getStudy());
Expand All @@ -284,7 +247,7 @@ public ResponseEntity<ApiExportResult> exportInstancesAndAnnotations(
.map(cohortId -> cohortService.getCohort(body.getStudy(), cohortId))
.collect(Collectors.toList());
List<FeatureSet> featureSets =
featureSetIds.stream()
body.getFeatureSets().stream()
.map(featureSetId -> featureSetService.getFeatureSet(body.getStudy(), featureSetId))
.collect(Collectors.toList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,7 @@ public ResponseEntity<Void> deleteFeatureSet(String studyId, String featureSetId

@Override
public ResponseEntity<ApiFeatureSet> getFeatureSet(String studyId, String featureSetId) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(FEATURE_SET, READ),
ResourceId.forFeatureSet(studyId, featureSetId));
accessControlService.checkReadAccess(studyId, List.of(), List.of(featureSetId));
return ResponseEntity.ok(toApiObject(featureSetService.getFeatureSet(studyId, featureSetId)));
}

Expand Down Expand Up @@ -138,10 +135,7 @@ public ResponseEntity<ApiFeatureSet> cloneFeatureSet(
UserId user = SpringAuthentication.getCurrentUser();

// should have read access to original feature set
accessControlService.throwIfUnauthorized(
user,
Permissions.forActions(FEATURE_SET, READ),
ResourceId.forFeatureSet(studyId, featureSetId));
accessControlService.checkReadAccess(studyId, List.of(), List.of(featureSetId));

// should have write access to create feature set in destination study
String destinationStudyId =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,7 @@ public ResponseEntity<ApiUnderlaySummaryList> listUnderlaySummaries() {

@Override
public ResponseEntity<ApiUnderlay> getUnderlay(String underlayName) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
Underlay underlay = underlayService.getUnderlay(underlayName);
return ResponseEntity.ok(
new ApiUnderlay()
Expand All @@ -107,10 +104,7 @@ public ResponseEntity<ApiUnderlay> getUnderlay(String underlayName) {

@Override
public ResponseEntity<ApiEntityList> listEntities(String underlayName) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
ApiEntityList apiEntities = new ApiEntityList();
underlayService
.getUnderlay(underlayName)
Expand All @@ -121,21 +115,15 @@ public ResponseEntity<ApiEntityList> listEntities(String underlayName) {

@Override
public ResponseEntity<ApiEntity> getEntity(String underlayName, String entityName) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
Entity entity = underlayService.getUnderlay(underlayName).getEntity(entityName);
return ResponseEntity.ok(toApiObject(entity));
}

@Override
public ResponseEntity<ApiInstanceListResult> listInstances(
String underlayName, String entityName, ApiQuery body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
Underlay underlay = underlayService.getUnderlay(underlayName);
ListQueryRequest listQueryRequest =
FromApiUtils.fromApiObject(body, underlay.getEntity(entityName), underlay);
Expand All @@ -148,10 +136,7 @@ public ResponseEntity<ApiInstanceListResult> listInstances(
@Override
public ResponseEntity<ApiInstanceListResult> listInstancesForPrimaryEntity(
String underlayName, String entityName, ApiQueryFilterOnPrimaryEntity body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
Underlay underlay = underlayService.getUnderlay(underlayName);

// Build the attribute fields to select.
Expand Down Expand Up @@ -205,10 +190,7 @@ public ResponseEntity<ApiInstanceListResult> listInstancesForPrimaryEntity(
@Override
public ResponseEntity<ApiInstanceCountList> countInstances(
String underlayName, String entityName, ApiCountQuery body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);

// Build the entity filter.
Underlay underlay = underlayService.getUnderlay(underlayName);
Expand Down Expand Up @@ -236,10 +218,7 @@ public ResponseEntity<ApiInstanceCountList> countInstances(
@Override
public ResponseEntity<ApiDisplayHintList> queryHints(
String underlayName, String entityName, ApiHintQuery body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);
Underlay underlay = underlayService.getUnderlay(underlayName);
Entity entity = underlay.getEntity(entityName);
HintQueryResult hintQueryResult;
Expand Down Expand Up @@ -279,10 +258,7 @@ public ResponseEntity<ApiDisplayHintList> queryHints(
@Override
public ResponseEntity<ApiInstanceCountList> queryCriteriaCounts(
String underlayName, ApiCriteriaCountQuery body) {
accessControlService.throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
accessControlService.checkUnderlayAccess(underlayName);

// Build the entity filter.
List<CriteriaGroupSection> criteriaGroupSections =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
package bio.terra.tanagra.service.accesscontrol;

import static bio.terra.tanagra.service.accesscontrol.Action.READ;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.COHORT;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.FEATURE_SET;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.STUDY;
import static bio.terra.tanagra.service.accesscontrol.ResourceType.UNDERLAY;

import bio.terra.common.exception.UnauthorizedException;
import bio.terra.tanagra.app.authentication.SpringAuthentication;
import bio.terra.tanagra.app.configuration.AccessControlConfiguration;
import bio.terra.tanagra.exception.SystemException;
import bio.terra.tanagra.service.accesscontrol.model.CoreModel;
import bio.terra.tanagra.service.accesscontrol.model.FineGrainedAccessControl;
import bio.terra.tanagra.service.artifact.StudyService;
import bio.terra.tanagra.service.authentication.UserId;
import com.google.common.annotations.VisibleForTesting;
import jakarta.validation.constraints.NotNull;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -173,4 +182,35 @@ public ResourceCollection listAuthorizedResources(
};
return allResources.filter(permissions);
}

public void checkUnderlayAccess(@NotNull String underlayName) {
throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(UNDERLAY, READ),
ResourceId.forUnderlay(underlayName));
}

public void checkReadAccess(
@NotNull String studyName,
@NotNull List<String> cohortIds,
@NotNull List<String> featureSetIds) {
throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(STUDY, READ),
ResourceId.forStudy(studyName));

for (String cohortId : cohortIds) {
throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(COHORT, READ),
ResourceId.forCohort(studyName, cohortId));
}

for (String featureSetId : featureSetIds) {
throwIfUnauthorized(
SpringAuthentication.getCurrentUser(),
Permissions.forActions(FEATURE_SET, READ),
ResourceId.forFeatureSet(studyName, featureSetId));
}
}
}
3 changes: 3 additions & 0 deletions service/src/main/resources/api/service_openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2876,6 +2876,9 @@ components:
type: array
items:
$ref: "#/components/schemas/EntityOutputPreview"
entityIdSql:
type: string
description: SQL string for the entityId attribute.
required:
- entityOutputs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,8 +344,7 @@ public SqlQueryRequest buildListQuerySqlAgainstIndexData(ListQueryRequest listQu
return buildListQuerySqlAgainstIndexData(listQueryRequest, Instant.now());
}

@VisibleForTesting
public SqlQueryRequest buildListQuerySqlAgainstIndexData(
private SqlQueryRequest buildListQuerySqlAgainstIndexData(
ListQueryRequest listQueryRequest, Instant queryInstant) {
return buildQuerySqlAgainstIndexData(
listQueryRequest.getUnderlay(),
Expand Down

0 comments on commit 66993e9

Please sign in to comment.