Skip to content

Commit

Permalink
Hide export buttons for users wo export permis.
Browse files Browse the repository at this point in the history
For users with VIEW only permission for a study.
  • Loading branch information
Ruslan Forostianov committed Apr 3, 2015
1 parent 204707b commit 7bd72ce
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 64 deletions.
Expand Up @@ -3,34 +3,30 @@ package com.recomdata.transmart.data.export
import grails.converters.JSON
import org.transmartproject.core.exceptions.AccessDeniedException
import org.transmartproject.core.exceptions.InvalidArgumentsException
import org.transmartproject.core.ontology.Study
import org.transmartproject.core.users.User

import java.util.regex.Matcher
import java.util.regex.Pattern

import static org.transmartproject.core.users.ProtectedOperation.WellKnownOperations.EXPORT

class DataExportController {

def exportService
def exportMetadataService
def springSecurityService
def queriesResourceAuthorizationDecorator
def studiesResourceService
def currentUserBean
def dataExportService

private static final String ROLE_ADMIN = 'ROLE_ADMIN'

def index = {}

//We need to gather a JSON Object to represent the different data types.
def getMetaData() {
checkParamResultInstanceIds()
List<Long> resultInstanceIds = parseResultInstanceIds()
checkRightsToExport(resultInstanceIds)

render exportMetadataService.getMetaData(
params.long("result_instance_id1"),
params.long("result_instance_id2")) as JSON
resultInstanceIds[0],
resultInstanceIds[1]) as JSON
}

def downloadFileExists() {
Expand Down Expand Up @@ -79,23 +75,41 @@ class DataExportController {
* Method that will run a data export and is called asynchronously from the datasetexplorer -> Data Export tab
*/
def runDataExport() {
checkParamResultInstanceIds()
checkRightsToExport(parseResultInstanceIds())

def jsonResult = exportService.exportData(params, springSecurityService.getPrincipal().username)

response.setContentType("text/json")
response.outputStream << jsonResult.toString()
}

private void checkParamResultInstanceIds() {
def resultInstanceId1 = params.long("result_instance_id1")
def resultInstanceId2 = params.long("result_instance_id2")
def isCurrentUserAllowedToExport() {
boolean isAllowed = dataExportService
.isUserAllowedToExport(currentUserBean, parseResultInstanceIds())
render([result: isAllowed] as JSON)
}

private List<Long> parseResultInstanceIds() {
List<Long> result = []
int subsetNumber = 1
while (params.containsKey('result_instance_id' + subsetNumber)) {
result << params.long('result_instance_id' + subsetNumber)
subsetNumber += 1
}
result
}

if (!resultInstanceId1 && !resultInstanceId2) {
private void checkRightsToExport(List<Long> resultInstanceIds) {
if (!resultInstanceIds) {
throw new InvalidArgumentsException("No result instance id provided")
}

checkResultInstanceIds resultInstanceId1, resultInstanceId2
if (!dataExportService
.isUserAllowedToExport(currentUserBean,
resultInstanceIds)) {
throw new AccessDeniedException("User ${currentUserBean.username} has no EXPORT permission" +
" on one of the result sets: ${resultInstanceIds}")
}
}

private checkJobAccess(String jobName) {
Expand All @@ -115,27 +129,6 @@ class DataExportController {
}
}

private void checkResultInstanceIds(... rids) {
// check that the user has export access in the studies of patients
Set<Study> studies = (rids as List).
findAll().collect {
queriesResourceAuthorizationDecorator.getQueryResultFromId it
}*.
patients.
inject { a, b -> a + b }. // merge two patient sets into one
inject([] as Set, { a, b -> a + b.trial }).
collect { studiesResourceService.getStudyById it }

studies.each { study ->
assert currentUserBean instanceof User
if (!currentUserBean.canPerform(EXPORT, study)) {
throw new AccessDeniedException("User " +
"$currentUserBean.username has no EXPORT permission on " +
"study $study.id")
}
}
}

// copied from Rmodules' AnalysisFilesController
// Job control and file download access ought to be unified
private boolean isAdmin() {
Expand Down
@@ -1,9 +1,11 @@
package com.recomdata.transmart.asynchronous.job

import com.recomdata.transmart.domain.i2b2.AsyncJob
import groovy.json.JsonSlurper
import org.apache.commons.lang.StringUtils
import org.json.JSONArray
import org.json.JSONObject
import org.transmartproject.core.users.User

class AsyncJobService {

Expand All @@ -12,6 +14,7 @@ class AsyncJobService {
def quartzScheduler
def springSecurityService
def jobResultsService
def dataExportService

/**
* Method that will get the list of jobs to show in the jobs tab
Expand Down Expand Up @@ -106,7 +109,7 @@ class AsyncJobService {
*/
def getjobresults(jobName) {
JSONObject result = new JSONObject()
def jobResults = AsyncJob.findByJobName("${jobName}").results
def jobResults = AsyncJob.findByJobName(jobName).results
result.put("jobResults", jobResults)
return result
}
Expand Down Expand Up @@ -147,6 +150,16 @@ class AsyncJobService {
return result;
}

def updateJobInputs(final String jobName, final Map params) {
assert jobName
assert params

def job = AsyncJob.findByJobName(jobName)
assert "${jobName} job is not found.", job

job.jobInputsJson = new JSONObject(params).toString()
}

/**
* Method called that will cancel a running job
*/
Expand Down Expand Up @@ -262,4 +275,24 @@ class AsyncJobService {

return retValue
}

boolean isUserAllowedToExportResults(final User user, final String jobName) {
assert user
assert jobName

def job = AsyncJob.findByJobName(jobName)
assert "${jobName} is not found.", job

job.jobInputsJson
def jobInputsJsonObj = new JsonSlurper().parseText(job.jobInputsJson)

List<Long> resultInstanceIds = []
int subsetNumber = 1
while (jobInputsJsonObj['result_instance_id' + subsetNumber]) {
resultInstanceIds << (jobInputsJsonObj['result_instance_id' + subsetNumber] as Long)
subsetNumber += 1
}
dataExportService.isUserAllowedToExport(user, resultInstanceIds)
}

}
Expand Up @@ -7,6 +7,10 @@ import groovy.json.JsonSlurper
import groovy.sql.Sql
import org.apache.commons.lang.StringUtils
import org.springframework.transaction.annotation.Transactional
import org.transmartproject.core.ontology.Study
import org.transmartproject.core.users.User

import static org.transmartproject.core.users.ProtectedOperation.WellKnownOperations.EXPORT

class DataExportService {

Expand All @@ -24,6 +28,8 @@ class DataExportService {
def additionalDataService
def vcfDataService
def dataSource
def queriesResourceAuthorizationDecorator
def studiesResourceService

@Transactional(readOnly = true)
def exportData(jobDataMap) {
Expand Down Expand Up @@ -426,4 +432,22 @@ class DataExportService {

}

boolean isUserAllowedToExport(final User user, final List<Long> resultInstanceIds) {
assert user
assert resultInstanceIds
// check that the user has export access in the studies of patients
Set<Study> studies = resultInstanceIds.findAll().collect {
queriesResourceAuthorizationDecorator.getQueryResultFromId it
}*.patients.
inject { a, b -> a + b }. // merge two patient sets into one
inject([] as Set, { a, b -> a + b.trial }).
collect { studiesResourceService.getStudyById it }

Study forbiddenExportStudy = studies.find { Study study ->
if (!user.canPerform(EXPORT, study)) {
return true
}
}
!forbiddenExportStudy
}
}
Expand Up @@ -110,8 +110,8 @@ class DataExportControllerTests {
}
}

assertThat exception.message, containsString(
"user_${user.id} has no EXPORT permission on study STUDY_ID_2")
assertThat exception.message, startsWith(
"User user_${user.id} has no EXPORT permission on one of the result set")
}

@Test
Expand Down Expand Up @@ -144,8 +144,8 @@ class DataExportControllerTests {
createNewJob accessLevelTestData.users[4]
}

assertThat exception.message, containsString(
"has no EXPORT permission on study STUDY_ID_2")
assertThat exception.message, startsWith(
"User ${accessLevelTestData.users[4].username} has no EXPORT permission on one of the result set")
}

@Test
Expand Down
47 changes: 24 additions & 23 deletions web-app/js/datasetExplorer/datasetExplorer.js
Expand Up @@ -3311,9 +3311,7 @@ function getSummaryGridData() {
}

gridstore = new Ext.data.JsonStore({
url: pageInfo.basePath+'/chart/analysisGrid',
root: 'rows',
fields: ['name', 'url']
url: pageInfo.basePath+'/chart/analysisGrid'
});

gridstore.on('load', storeLoaded);
Expand All @@ -3332,18 +3330,7 @@ function getSummaryGridData() {
});
}

function storeLoaded() {

var exportButton = new Ext.Button ({
text: 'Export to Excel',
listeners: {
click: function () {
window.location = 'data:application/vnd.ms-excel;base64,' +
Base64.encode(grid.getExcelXml());
}
}
});

function storeLoaded(jsonStore, rows, paramsObject) {
var cm = buildColumnModel(gridstore.reader.meta.fields);

grid = analysisGridPanel.getComponent('gridView');
Expand All @@ -3352,30 +3339,44 @@ function storeLoaded() {
analysisGridPanel.remove(grid);
}

var bbar = new Ext.Toolbar({ height: 25 });

if (paramsObject && paramsObject.params) {
jQuery.get(pageInfo.basePath + '/dataExport/isCurrentUserAllowedToExport?' + paramsObject.params, function(data) {
if (data.result) {
var exportButton = new Ext.Button ({
text: 'Export to Excel',
listeners: {
click: function () {
window.location = 'data:application/vnd.ms-excel;base64,' +
Base64.encode(grid.getExcelXml());
}
}
});
bbar.add(exportButton);
}
});
}

grid = new GridViewPanel({
id: 'gridView',
title: 'Grid View',
viewConfig: {
forceFit: true
},
bbar: new Ext.Toolbar({
buttons: [exportButton]
}),
bbar: bbar,
frame:true,
layout: 'fit',
cm: cm,
store: gridstore
});

analysisGridPanel.add(grid);
analysisGridPanel.doLayout();
}

function getAnalysisGridData(concept_key) {
gridstore = new Ext.data.JsonStore({
url: pageInfo.basePath+'/chart/analysisGrid',
root: 'rows',
fields: ['name', 'url']
url: pageInfo.basePath+'/chart/analysisGrid'
});
gridstore.on('load', storeLoaded);
var myparams = Ext.urlEncode({
Expand Down Expand Up @@ -3813,4 +3814,4 @@ function contains(a, obj) {
}
}
return false;
}
}

0 comments on commit 7bd72ce

Please sign in to comment.