Skip to content

Commit

Permalink
feat: added different levels of variable summary visibility #4467 (#4469
Browse files Browse the repository at this point in the history
)

* feat: added global summary statistics policy #4467

* feat: added simple flags for dealing with summary in the variable template

* feat: OPEN_STATS renamed to OPEN_SUMMARY
  • Loading branch information
ymarcon authored Dec 4, 2024
1 parent f6fc0ac commit bb99c25
Show file tree
Hide file tree
Showing 21 changed files with 192 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import org.apache.shiro.SecurityUtils;
import org.obiba.magma.NoSuchValueTableException;
import org.obiba.magma.NoSuchVariableException;
import org.obiba.magma.ValueTable;
Expand All @@ -40,6 +41,8 @@
import org.obiba.mica.dataset.event.DatasetUpdatedEvent;
import org.obiba.mica.file.FileUtils;
import org.obiba.mica.file.service.FileSystemService;
import org.obiba.mica.micaConfig.domain.MicaConfig;
import org.obiba.mica.micaConfig.domain.SummaryStatisticsAccessPolicy;
import org.obiba.mica.micaConfig.service.MicaConfigService;
import org.obiba.mica.micaConfig.service.OpalService;
import org.obiba.mica.network.service.NetworkService;
Expand Down Expand Up @@ -518,6 +521,11 @@ protected EventBus getEventBus() {
return eventBus;
}

@Override
protected MicaConfig getMicaConfig() {
return micaConfigService.getConfig();
}

//
// Private methods
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import com.google.common.base.Strings;
import com.google.common.eventbus.EventBus;
import org.apache.shiro.SecurityUtils;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.NoSuchValueTableException;
import org.obiba.magma.NoSuchVariableException;
Expand All @@ -26,10 +27,13 @@
import org.obiba.mica.dataset.NoSuchDatasetException;
import org.obiba.mica.dataset.domain.Dataset;
import org.obiba.mica.dataset.domain.DatasetVariable;
import org.obiba.mica.micaConfig.domain.MicaConfig;
import org.obiba.mica.micaConfig.domain.SummaryStatisticsAccessPolicy;
import org.obiba.mica.micaConfig.service.OpalService;
import org.obiba.mica.network.service.NetworkService;
import org.obiba.mica.spi.tables.StudyTableSource;
import org.obiba.mica.study.service.StudyService;
import org.obiba.mica.web.model.Mica;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -77,6 +81,44 @@ public abstract DatasetVariable getDatasetVariable(T dataset, String name)

protected abstract EventBus getEventBus();

protected abstract MicaConfig getMicaConfig();

/**
* Apply summary statistics visibility policy.
*
* @param summary
* @return
*/
public Mica.DatasetVariableAggregationDto getFilteredVariableSummary(Mica.DatasetVariableAggregationDto summary) {
SummaryStatisticsAccessPolicy policy = getMicaConfig().getSummaryStatisticsAccessPolicy();
if (summary == null || policy.equals(SummaryStatisticsAccessPolicy.OPEN_ALL)) return summary;
if (!SecurityUtils.getSubject().isAuthenticated()) {
if (policy.equals(SummaryStatisticsAccessPolicy.OPEN_SUMMARY)) return summary;
// strip out detailed stats because user is not authenticated
summary = summary.toBuilder().clearFrequencies().build();
summary = summary.toBuilder().clearStatistics().build();
}
return summary;
}

/**
* Apply summary statistics visibility policy.
*
* @param summary
* @return
*/
public Mica.DatasetVariableAggregationsDto getFilteredVariableSummary(Mica.DatasetVariableAggregationsDto summary) {
SummaryStatisticsAccessPolicy policy = getMicaConfig().getSummaryStatisticsAccessPolicy();
if (summary == null || policy.equals(SummaryStatisticsAccessPolicy.OPEN_ALL)) return summary;
if (!SecurityUtils.getSubject().isAuthenticated()) {
if (policy.equals(SummaryStatisticsAccessPolicy.OPEN_SUMMARY)) return summary;
// strip out detailed stats because user is not authenticated
summary = summary.toBuilder().clearFrequencies().build();
summary = summary.toBuilder().clearStatistics().build();
}
return summary;
}

/**
* Find all dataset identifiers.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.eventbus.EventBus;
import org.apache.shiro.SecurityUtils;
import org.obiba.magma.*;
import org.obiba.magma.support.Disposables;
import org.obiba.mica.NoSuchEntityException;
Expand All @@ -35,6 +36,8 @@
import org.obiba.mica.dataset.event.DatasetUpdatedEvent;
import org.obiba.mica.file.FileUtils;
import org.obiba.mica.file.service.FileSystemService;
import org.obiba.mica.micaConfig.domain.MicaConfig;
import org.obiba.mica.micaConfig.domain.SummaryStatisticsAccessPolicy;
import org.obiba.mica.micaConfig.service.MicaConfigService;
import org.obiba.mica.micaConfig.service.OpalService;
import org.obiba.mica.network.service.NetworkService;
Expand Down Expand Up @@ -438,6 +441,11 @@ protected EventBus getEventBus() {
return eventBus;
}

@Override
protected MicaConfig getMicaConfig() {
return micaConfigService.getConfig();
}

//
// Private methods
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ public class MicaConfig extends AbstractAuditableDocument implements Serializabl

private boolean variableSummaryRequiresAuthentication = false;

private SummaryStatisticsAccessPolicy summaryStatisticsAccessPolicy;

private boolean usePublicUrlForSharedLink = true;

private String style;
Expand Down Expand Up @@ -543,6 +545,21 @@ public boolean isVariableSummaryRequiresAuthentication() {

public void setVariableSummaryRequiresAuthentication(boolean variableSummaryRequiresAuthentication) {
this.variableSummaryRequiresAuthentication = variableSummaryRequiresAuthentication;
if (summaryStatisticsAccessPolicy == null) {
summaryStatisticsAccessPolicy = variableSummaryRequiresAuthentication ? SummaryStatisticsAccessPolicy.RESTRICTED_ALL : SummaryStatisticsAccessPolicy.OPEN_ALL;
}
}

public SummaryStatisticsAccessPolicy getSummaryStatisticsAccessPolicy() {
if (summaryStatisticsAccessPolicy == null) {
summaryStatisticsAccessPolicy = variableSummaryRequiresAuthentication ? SummaryStatisticsAccessPolicy.RESTRICTED_ALL : SummaryStatisticsAccessPolicy.OPEN_ALL;
}
return summaryStatisticsAccessPolicy;
}

public void setSummaryStatisticsAccessPolicy(SummaryStatisticsAccessPolicy summaryStatisticsAccessPolicy) {
this.summaryStatisticsAccessPolicy = summaryStatisticsAccessPolicy;
this.variableSummaryRequiresAuthentication = !SummaryStatisticsAccessPolicy.OPEN_ALL.equals(summaryStatisticsAccessPolicy);
}

public boolean hasStyle() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.obiba.mica.micaConfig.domain;

/**
* Specify the access policy to the variable stats.
*/
public enum SummaryStatisticsAccessPolicy {

OPEN_ALL, // open basic counts, detailed stats and contingency

OPEN_SUMMARY, // open basic counts and detailed stats, restricted contingency

OPEN_BASICS, // open basic counts, restricted detailed stats and contingency

RESTRICTED_ALL, // restricted basic counts, detailed stats and contingency

}
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ Mica.MicaConfigDto asDto(@NotNull MicaConfig config, String language) {
builder.setIsCollectedDatasetEnabled(config.isStudyDatasetEnabled());
builder.setIsHarmonizedDatasetEnabled(config.isHarmonizationDatasetEnabled());
builder.setVariableSummaryRequiresAuthentication(config.isVariableSummaryRequiresAuthentication());
builder.setSummaryStatisticsAccessPolicy(config.getSummaryStatisticsAccessPolicy().name());
builder.setIsImportStudiesFeatureEnabled(config.isImportStudiesFeatureEnabled());

if(config.hasStyle()) builder.setStyle(config.getStyle());
Expand Down Expand Up @@ -249,6 +250,7 @@ MicaConfig fromDto(@NotNull Mica.MicaConfigDtoOrBuilder dto) {
config.setHarmonizationDatasetEnabled(dto.getIsHarmonizedDatasetEnabled());
config.setImportStudiesFeatureEnabled(dto.getIsImportStudiesFeatureEnabled());
if (dto.hasVariableSummaryRequiresAuthentication()) config.setVariableSummaryRequiresAuthentication(dto.getVariableSummaryRequiresAuthentication());
config.setSummaryStatisticsAccessPolicy(SummaryStatisticsAccessPolicy.valueOf(dto.getSummaryStatisticsAccessPolicy()));

if (dto.hasSignupEnabled()) config.setSignupEnabled(dto.getSignupEnabled());
config.setSignupWithPassword(dto.getSignupWithPassword());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ public DatasetVariable getVariable(@PathParam("id") String id, @PathParam("proje
@Path("/collected/{project}/{table}/{variableName}/_summary")
public Mica.DatasetVariableAggregationDto getVariableSummary(@PathParam("id") String id, @PathParam("project") String project, @PathParam("table") String table, @PathParam("variableName") String variableName) {
checkVariableSummaryAccess();
return collectedDatasetService.getVariableSummary(alternativeStudyDataset(id, project, table), variableName);
Mica.DatasetVariableAggregationDto summary = collectedDatasetService.getVariableSummary(alternativeStudyDataset(id, project, table), variableName);
return collectedDatasetService.getFilteredVariableSummary(summary);
}

private Dataset getDataset(String id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.obiba.mica.dataset.domain.Dataset;
import org.obiba.mica.dataset.domain.DatasetVariable;
import org.obiba.mica.dataset.domain.HarmonizationDataset;
import org.obiba.mica.micaConfig.domain.SummaryStatisticsAccessPolicy;
import org.obiba.mica.micaConfig.service.MicaConfigService;
import org.obiba.mica.micaConfig.service.TaxonomiesService;
import org.obiba.mica.security.service.SubjectAclService;
Expand Down Expand Up @@ -308,10 +309,18 @@ protected List<Taxonomy> getTaxonomies() {
protected void checkContingencyAccess() {
if (!micaConfigService.getConfig().isContingencyEnabled())
throw new ForbiddenException();
if (micaConfigService.getConfig().getSummaryStatisticsAccessPolicy().equals(SummaryStatisticsAccessPolicy.OPEN_ALL))
return;
// other require authentication
if (!SecurityUtils.getSubject().isAuthenticated())
throw new ForbiddenException();
}

protected void checkVariableSummaryAccess() {
if (!SecurityUtils.getSubject().isAuthenticated() && micaConfigService.getConfig().isVariableSummaryRequiresAuthentication())
if (micaConfigService.getConfig().getSummaryStatisticsAccessPolicy().name().startsWith("OPEN_"))
return;
// other require authentication
if (!SecurityUtils.getSubject().isAuthenticated())
throw new ForbiddenException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ public Mica.DatasetVariableAggregationDto getVariableAggregations(@QueryParam("s
StudyDataset dataset = getDataset(StudyDataset.class, datasetId);
StudyTable studyTable = dataset.getSafeStudyTable();
try {
return dtos.asDto(studyTable, datasetService.getVariableSummary(dataset, variableName), withStudySummary).build();
Mica.DatasetVariableAggregationDto summary = datasetService.getVariableSummary(dataset, variableName);
return dtos.asDto(studyTable, datasetService.getFilteredVariableSummary(summary), withStudySummary).build();
} catch (Exception e) {
if (log.isDebugEnabled())
log.warn("Unable to retrieve statistics: {}", e.getMessage(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.Response;
import org.apache.commons.math3.util.Pair;
import org.obiba.mica.core.domain.BaseStudyTable;
Expand All @@ -36,13 +31,13 @@
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -91,7 +86,8 @@ public Mica.DatasetVariableAggregationsDto getVariableAggregations(@QueryParam("
BaseStudyTable opalTable = studyTables.get(i);
Future<Mica.DatasetVariableAggregationDto> futureResult = results.get(i);
try {
builder.add(dtos.asDto(opalTable, futureResult.get(), withStudySummary).build());
Mica.DatasetVariableAggregationDto summary = futureResult.get();
builder.add(dtos.asDto(opalTable, summary, withStudySummary).build());
} catch (Exception e) {
if (log.isDebugEnabled())
log.warn("Unable to retrieve statistics: {}", e.getMessage(), e);
Expand All @@ -108,9 +104,9 @@ public Mica.DatasetVariableAggregationsDto getVariableAggregations(@QueryParam("
if (allAggDto.hasStatistics()) aggDto.setStatistics(allAggDto.getStatistics());
aggDto.addAllFrequencies(allAggDto.getFrequenciesList());

aggDto.addAllAggregations(aggsDto);
aggDto.addAllAggregations(aggsDto.stream().map((summary) -> datasetService.getFilteredVariableSummary(summary)).toList());

return aggDto.build();
return datasetService.getFilteredVariableSummary(aggDto.build());
}

@GET
Expand Down Expand Up @@ -259,24 +255,25 @@ protected Future<Mica.DatasetVariableAggregationDto> getVariableFacet(Harmonizat
BaseStudyTable table) {
try {
String studyId = table.getStudyId();
return new AsyncResult<>(datasetService.getVariableSummary(dataset, variableName, studyId, table.getSource()));
Mica.DatasetVariableAggregationDto summary = datasetService.getVariableSummary(dataset, variableName, studyId, table.getSource());
return CompletableFuture.supplyAsync(() -> summary);
} catch (Exception e) {
if (log.isDebugEnabled())
log.warn("Unable to retrieve statistics: {}", e.getMessage(), e);
else
log.warn("Unable to retrieve statistics: {}", e.getMessage());
return new AsyncResult<>(null);
return CompletableFuture.supplyAsync(() -> null);
}
}

@Async
protected Future<Mica.DatasetVariableContingencyDto> getContingencyTable(HarmonizationDataset dataset, DatasetVariable var,
DatasetVariable crossVar, BaseStudyTable studyTable) {
try {
return new AsyncResult<>(datasetService.getContingencyTable(dataset, studyTable, var, crossVar));
return CompletableFuture.supplyAsync(() -> datasetService.getContingencyTable(dataset, studyTable, var, crossVar));
} catch (Exception e) {
log.warn("Unable to retrieve contingency statistics: " + e.getMessage(), e);
return new AsyncResult<>(null);
return CompletableFuture.supplyAsync(() -> null);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ public Mica.DatasetVariableAggregationDto getVariableAggregations(@QueryParam("s
for (BaseStudyTable baseTable : getBaseStudyTables(dataset)) {
if (baseTable.isFor(studyId, source)) {
try {
return dtos.asDto(baseTable,
datasetService.getVariableSummary(dataset, variableName, studyId, source), withStudySummary).build();
Mica.DatasetVariableAggregationDto summary = datasetService.getVariableSummary(dataset, variableName, studyId, source);
return dtos.asDto(baseTable, datasetService.getFilteredVariableSummary(summary), withStudySummary).build();
} catch (Exception e) {
if (log.isDebugEnabled())
log.warn("Unable to retrieve statistics: {}", e.getMessage(), e);
Expand Down
1 change: 1 addition & 0 deletions mica-web-model/src/main/protobuf/Mica.proto
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ message MicaConfigDto {
required bool isStudiesExportEnabled = 68;
required bool isNetworksExportEnabled = 69;
repeated string usableVariableTaxonomiesForConceptTagging = 70;
required string summaryStatisticsAccessPolicy = 71;
}

message PublicMicaConfigDto {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.apache.shiro.SecurityUtils;
import org.obiba.magma.NoSuchVariableException;
import org.obiba.mica.core.domain.HarmonizationStudyTable;
import org.obiba.mica.core.domain.StudyTable;
Expand All @@ -10,6 +11,8 @@
import org.obiba.mica.dataset.domain.HarmonizationDataset;
import org.obiba.mica.dataset.service.CollectedDatasetService;
import org.obiba.mica.dataset.service.HarmonizedDatasetService;
import org.obiba.mica.micaConfig.domain.MicaConfig;
import org.obiba.mica.micaConfig.domain.SummaryStatisticsAccessPolicy;
import org.obiba.mica.micaConfig.service.TaxonomiesService;
import org.obiba.mica.spi.search.Indexer;
import org.obiba.mica.spi.search.Searcher;
Expand Down Expand Up @@ -141,6 +144,8 @@ public ModelAndView variable(@PathVariable String id) {
params.put("query", "variable(" + query.toString() + ")");

params.put("showDatasetContingencyLink", showDatasetContingencyLink());
params.put("showVariableSummary", showVariableSummary());
params.put("showSigninForVariableSummary", showSigninForVariableSummary());

return new ModelAndView("variable", params);
}
Expand Down Expand Up @@ -250,4 +255,19 @@ private HarmonizationDataset getHarmonizationDataset(String id) {
return harmonizedDatasetService.findById(id);
}

private boolean showVariableSummary() {
MicaConfig config = micaConfigService.getConfig();
if (config.getSummaryStatisticsAccessPolicy().name().startsWith("OPEN_"))
return true;
return SecurityUtils.getSubject().isAuthenticated();
}

private boolean showSigninForVariableSummary() {
MicaConfig config = micaConfigService.getConfig();
if (config.getSummaryStatisticsAccessPolicy().equals(SummaryStatisticsAccessPolicy.OPEN_ALL))
return false;
if (config.getSummaryStatisticsAccessPolicy().equals(SummaryStatisticsAccessPolicy.OPEN_SUMMARY))
return false;
return !SecurityUtils.getSubject().isAuthenticated();
}
}
Loading

0 comments on commit bb99c25

Please sign in to comment.