Changeset 14


Ignore:
Timestamp:
Feb 16, 2011, 2:24:56 PM (9 years ago)
Author:
robert@…
Message:

Implemented improved authorization (#16)
Built in select all checkboxes (#25)

Location:
trunk
Files:
1 deleted
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/conf/BaseFilters.groovy

    r12 r14  
    184184                                                log.info "User is not authenticated during synchronizatino. Redirecting to GSCF."
    185185                                                redirect( url: gscfService.urlAuthRemote(params, session.sessionToken) )
     186                                                return false;
    186187                                        } catch( Exception e ) {
    187188                                                // Synchronization fails. Log error and continue; don't bother the user with it
  • trunk/grails-app/conf/UrlMappings.groovy

    r2 r14  
    88                }
    99
    10                 "/"(controller: "study")
     10                "/"(controller: "run")
    1111                "500"(view:'/error')
    1212        }
  • trunk/grails-app/controllers/nl/tno/metagenomics/AssayController.groovy

    r13 r14  
    11package nl.tno.metagenomics
     2
     3import java.util.List;
    24
    35import org.codehaus.groovy.grails.commons.ConfigurationHolder
     
    1921                        gscfAddUrl: gscfService.urlAddStudy() ]
    2022        }
    21        
     23
    2224        def show = {
    2325                def assay = getAssay( params.id );
     
    6567                }
    6668
     69                if (!assay.study.canRead( session.user ) ) {
     70                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
     71                        redirect(action: 'index')
     72                        return null
     73                }
     74               
    6775                redirect( action: "show", id: assay.id );
    6876        }
     
    95103         */
    96104        def parseTagExcel = {
    97                 def assay = getAssay( params.id );
     105                def assay = getAssay( params.id, true );
    98106                if( !assay )
    99107                        return
     
    129137                }
    130138                session.possibleFields = excelData.possibleFields
    131                
     139
    132140                [assay: assay, headers: excelData.headers, exampleData: excelData.exampleData, filename: filename, possibleFields: [ "Don't import" ] + excelData.possibleFields, bestMatches: excelData.bestMatches]
    133141        }
     
    137145         */
    138146        def updateTagsByExcel = {
    139                 def assay = getAssay( params.id );
     147                def assay = getAssay( params.id, true );
    140148                if( !assay ) {
    141149                        // Now delete the file, since we don't need it anymore
     
    158166                // Now loop through the excel sheet and update all samples with the specified data
    159167                File file = new File( fileService.getUploadDir(), session.filename );
    160                
     168
    161169                if( !file.exists() || !file.canRead() ) {
    162170                        flash.error = "Excel file has been removed since previous step. Please try again."
     
    164172                        return
    165173                }
    166                
     174
    167175                def excelData = sampleExcelService.updateTagsByExcel( matchColumns, session.possibleFields, file, assay.assaySamples );
    168176
     
    178186                                flash.message += excelData.failedRows.size() + " row(s) could not be imported, because the sample names could not be found in the database."
    179187                }
     188               
     189                // Now delete the file, since we don't need it anymore
     190                _deleteUploadedFileFromSession()
     191
    180192                redirect( action: 'show', id: params.id )
    181193        }
     
    185197         */
    186198        def updateTagsManually = {
    187                 def assay = getAssay( params.id );
     199                def assay = getAssay( params.id, true );
    188200                if( !assay )
    189201                        return
     
    224236         */
    225237        def addExistingRuns = {
    226                 def assay = getAssay( params.id );
     238                def assay = getAssay( params.id, true );
    227239                if( !assay )
    228240                        return
     
    250262
    251263        /**
    252          * Adds existing runs to this assay
     264         * Removes a run from this assay
    253265         */
    254266        def removeRun = {
    255                 def assay = getAssay( params.id );
     267                def assay = getAssay( params.id, true );
    256268                if( !assay )
    257269                        return
     
    300312                session.filename = ''
    301313        }
    302        
    303         protected Assay getAssay(def assayId) {
    304                 // load study with id specified by param.id
    305                 def assay
    306                 try {
    307                         assay = Assay.get(assayId as Long)
    308                 } catch( Exception e ) {
    309                         flash.error = "Incorrect id given: " + assayId
    310                         redirect(controller: 'study')
    311                         return null
    312                 }
    313 
    314                 if (!assay) {
    315                         flash.error = "No assay found with id: " + assayId
    316                         redirect(controller: 'study')
    317                         return null
    318                 }
    319                
    320                 if (!assay.study.canRead( session.user ) ) {
    321                         flash.error = "You don't have the right authorizaton to access assay " + assay.name
    322                         redirect(controller: 'study')
    323                         return null
    324                 }
    325                
    326                 return assay
    327         }
    328        
     314
    329315        /**
    330316         * Exports data about one or more assays in fasta format
    331317         */
    332318        def exportAsFasta = {
    333                 def tokens = params.list( 'tokens' );
    334                 def ids = params.list( 'ids' );
    335                 def name;
    336                
    337                 ids = ids.findAll { it.isLong() }.collect { Long.parseLong( it ) }
    338                
    339                 if( !tokens && !ids ) {
    340                         def message = "No assay tokens or ids given"
    341                         response.setStatus( 400, message)
    342                         render message;
    343                         return;
    344                 }
    345                                
    346                 def assaySamples = [];
    347                
    348                 // Determine which assaySamples to export
    349                 def assay;
    350                 tokens.each { token ->
    351                         assay = Assay.findByAssayToken( token );
    352                         if( assay )
    353                                 assaySamples += assay.assaySamples
    354                 }
    355                 ids.each { id ->
    356                         assay = Assay.get( id );
    357                         if( assay )
    358                                 assaySamples += assay.assaySamples
    359                 }
    360 
    361                 if( ( ids.size() + tokens.size() ) == 1 && assay )
    362                         name = "Assay_" + assay?.name?.replace( ' ', '_' );
    363                 else
     319                def assaySamples = getAssaySamples( params );
     320                def name
     321
     322                if( assaySamples == null ) {
     323                        return
     324                } else if( assaySamples*.assay.unique().size() == 1 ) {
     325                        name = "Assay_" + assaySamples[0].assay?.name?.replace( ' ', '_' );
     326                } else {
    364327                        name = "assays";
    365                        
     328                }
     329
    366330                // Export the sequences and quality scores
    367331                response.setHeader "Content-disposition", "attachment; filename=" + name.trim() + ".zip"
     
    373337                }
    374338        }
     339
     340        /**
     341         * Export metadata of selected samples in excel format
     342         */
     343        def exportMetaData = {
     344                def assaySamples = getAssaySamples( params );
     345                def name
     346
     347                if( assaySamples == null ) {
     348                        return
     349                } else if( assaySamples*.assay.unique().size() == 1 ) {
     350                        name = "Assay_" + assaySamples[0].assay?.name?.replace( ' ', '_' );
     351                } else {
     352                        name = "assays";
     353                }
     354
     355                // Export the metadata
     356                response.setHeader "Content-disposition", "attachment; filename=${name}.xls"
     357                try {
     358                        // The export functionality needs a assaySample-tag list, but it
     359                        // should be empty when only exporting metadata
     360                        def tags = [];
     361                        assaySamples.unique().each { assaySample ->
     362                                tags << [assaySampleId: assaySample.id, sampleName: assaySample.sample.name, assayName: assaySample.assay.name, studyName: assaySample.assay.study.name, tag: "-"]
     363                        }
     364                        sampleExcelService.exportExcelSampleData( assaySamples.unique(), tags, response.getOutputStream() );
     365                        response.outputStream.flush();
     366                } catch( Exception e ) {
     367                        log.error( "Exception occurred during export of metadata. Probably the user has cancelled the download." );
     368                }
     369        }
     370
     371       
     372        /**
     373         * Retrieves an assay from the database, based on the assay ID given
     374         * @param assayId               ID of the assay
     375         * @param writeAccess   True if you require write access to this assay. The system will check for sufficient privileges
     376         * @return
     377         */
     378        protected Assay getAssay(def assayId, boolean writeAccess = false ) {
     379                // load study with id specified by param.id
     380                def assay
     381                try {
     382                        assay = Assay.get(assayId as Long)
     383                } catch( Exception e ) {
     384                        flash.error = "Incorrect id given: " + assayId
     385                        redirect(action: 'index')
     386                        return null
     387                }
     388
     389                if (!assay) {
     390                        flash.error = "No assay found with id: " + assayId
     391                        redirect(action: 'index')
     392                        return null
     393                }
     394
     395                if ( !assay.study.canRead( session.user ) || ( writeAccess && !assay.study.canWrite( session.user ) ) ) {
     396                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
     397                        redirect(action: 'index')
     398                        return null
     399                }
     400               
     401                return assay
     402        }
     403
     404       
     405        protected List getAssaySamples( params ) {
     406                def tokens = params.list( 'tokens' );
     407                def ids = params.list( 'ids' );
     408                def name;
     409
     410                ids = ids.findAll { it.isLong() }.collect { Long.parseLong( it ) }
     411
     412                if( !tokens && !ids ) {
     413                        def message = "No assay tokens or ids given"
     414                        flash.error = message
     415                        redirect( action: "index" );
     416                        return;
     417                }
     418
     419                def assaySamples = [];
     420
     421                // Determine which assaySamples to export
     422                def assay;
     423                tokens.each { token ->
     424                        assay = Assay.findByAssayToken( token );
     425                        if( assay && assay.study.canRead( session.user ) )
     426                                assaySamples += assay.assaySamples
     427                }
     428                ids.each { id ->
     429                        assay = Assay.get( id );
     430                        if( assay && assay.study.canRead( session.user ) )
     431                                assaySamples += assay.assaySamples
     432                }
     433
     434                return assaySamples;
     435        }
     436
     437
    375438}
  • trunk/grails-app/controllers/nl/tno/metagenomics/FastaController.groovy

    r12 r14  
    6969                        case "run":
    7070                                entity = getRun( params.id );
    71                                 assaySamples = entity.assaySamples;
     71                                assaySamples = entity.assaySamples.findAll { it.assay.study.canRead( session.user ) };
    7272                                break;
    7373                        case "assay":
  • trunk/grails-app/controllers/nl/tno/metagenomics/RunController.groovy

    r13 r14  
    3535
    3636                // Determine runs not used in this assay
    37                 def otherAssays = Assay.list( sort: "name" ).findAll { !it.runs.contains( run ) }
     37                def otherAssays = Assay.list( sort: "name" ).findAll { !it.runs.contains( run ) && it.study.canRead( session.user ) }
    3838
    3939                // Send the assay information to the view
     
    6767
    6868        def create = {
     69                // Retrieve the assay from the database, but don't exit with an error if no assay is found
    6970                Assay a = getAssay(params.id);
    7071                flash.error = "";
     
    133134                }
    134135
     136                // Check whether the user has sufficient privileges to remove the run from all assays
     137                def hasPrivileges = true;
     138                run.assay.each {
     139                        if( !it.study.canWrite( session.user ) )
     140                                hasPrivileges = false
     141                }
     142               
     143                if( !hasPrivileges ) {
     144                        flash.message = "Run could not be deleted because you don't have sufficient privileges to remove the run from all assays.";
     145                        redirect( controller: "assay", action: "show", id: params.assayId )
     146                }
     147               
    135148                // Remove all associations
    136149                run.assays.each {
     
    257270                def assaySamples = run.assaySamples.findAll { it.assay.study.canWrite( session.user ) }
    258271
     272                println "Matchcolumns: " + matchColumns
     273                println "Possible fields: " + session.possibleFields
     274                println "Assay samples: " + assaySamples.sample.name
     275               
    259276                def excelData = sampleExcelService.updateTagsByExcel( matchColumns, session.possibleFields, file, assaySamples );
    260277
     278                println excelData
     279               
    261280                // Return a message to the user
    262281                if( !excelData.success ) {
     
    270289                                flash.message += excelData.failedRows.size() + " row(s) could not be imported, because the sample names could not be found in the database or you don't have the proper permissions to change them."
    271290                }
     291
     292                // Now delete the file, since we don't need it anymore
     293                _deleteUploadedFileFromSession()
     294
    272295                redirect( action: 'show', id: params.id )
    273296        }
     
    289312
    290313                if( sampleParams ) {
    291                         run.assaySamples.each { assaySample ->
     314                        run.assaySamples.findAll { it.assay.study.canWrite( session.user ) }.each { assaySample ->
    292315                                def assaySampleParams = sampleParams.get( assaySample.id as String );
    293316                                if( assaySampleParams ) {
     
    318341
    319342                if( !run ) {
    320                         redirect(controller: 'study')
     343                        redirect(controller: 'run', action: 'index')
    321344                        return
    322345                }
     
    332355                        try {
    333356                                def assaySample = AssaySample.findById( assaySampleId as Long )
    334                                 if( run.assaySamples == null || !run.assaySamples.contains( assaySample ) ) {
    335                                         run.addToAssaySamples( assaySample );
    336                                         numAdded++;
     357                                if( assaySample.assay.study.canWrite( session.user ) ) {
     358                                        if( run.assaySamples == null || !run.assaySamples.contains( assaySample ) ) {
     359                                                run.addToAssaySamples( assaySample );
     360                                                numAdded++;
     361                                        }
    337362                                }
    338363                        } catch( Exception e ) {}
     
    355380
    356381                if( !params.assaySampleId ) {
    357                         flash.message = "No sample id given"
     382                        flash.error = "No sample id given"
    358383                        redirect(action: 'show', id: params.id)
    359384                        return
     
    366391                } catch( Exception e ) {
    367392                        log.error e
    368                         flash.message = "Incorrect assaysample id given: " + params.assaySampleId
     393                        flash.error = "Incorrect assaysample id given: " + params.assaySampleId
    369394                        redirect(action: 'show', id: params.id)
    370395                        return
    371396                }
    372 
     397               
     398                if( !assaySample.assay.study.canWrite( session.user ) ) {
     399                        flash.error = "You don't have sufficient privileges to remove the specified sample from this run."
     400                        redirect(action: 'show', id: params.id)
     401                        return
     402                }
     403               
    373404                if( run.assaySamples.contains( assaySample ) ) {
    374405                        run.removeFromAssaySamples( assaySample );
     
    403434                        try {
    404435                                def assay = Assay.findById( assay_id as Long )
    405                                 if( run.assays == null || !run.assays.contains( assay ) ) {
    406                                         run.addToAssays( assay );
    407                                         numAdded++;
     436                                if( assay.study.canWrite( session.user ) ) {
     437                                        if( run.assays == null || !run.assays.contains( assay ) ) {
     438                                                run.addToAssays( assay );
     439                                                numAdded++;
     440                                        }
    408441                                }
    409442                        } catch( Exception e ) {}
     
    442475                }
    443476
     477                if( !assay.study.canWrite( session.user ) ) {
     478                        flash.error = "You don't have sufficient privileges to remove the specified assay from this run."
     479                        redirect(action: 'show', id: params.id)
     480                        return
     481                }
     482               
    444483                if( run.assays.contains( assay ) ) {
    445484                        run.removeFromAssays( assay );
     
    456495         */
    457496        def exportAsFasta = {
    458                 def ids = params.list( 'ids' );
    459 
    460                 ids = ids.findAll { it.isLong() }.collect { Long.parseLong( it ) }
    461 
    462                 if( !ids ) {
    463                         def message = "No run ids given"
    464                         response.setStatus( 400, message)
    465                         render message;
     497                def assaySamples = getAssaySamples( params );
     498
     499                if( assaySamples == null )
    466500                        return;
    467                 }
    468 
    469                 def assaySamples = [];
     501
    470502                def name
    471503
    472                 if( ids.size() == 1 )
    473                         name = "Run_" + Run.get( ids[ 0 ] )?.name?.replace( ' ', '_' );
     504                if( assaySamples.size() == 0 ) {
     505                        flash.error = "No samples found for selected runs";
     506                        redirect( action: "list" );
     507                        return;
     508                } else if( assaySamples*.run.unique().size() == 1 )
     509                        name = "Run_" + assaySamples[0].run?.name?.replace( ' ', '_' );
    474510                else
    475511                        name = "runs";
    476 
    477                 // Determine which assaySamples to export
    478                 ids.each { id ->
    479                         def run = Run.get( id );
    480                         if( run )
    481                                 assaySamples += run.assaySamples
    482                 }
    483512
    484513                // Export the sequences and quality scores
     
    491520                }
    492521        }
    493 
     522       
     523        /**
     524         * Export metadata of selected samples in excel format
     525         */
     526        def exportMetaData = {
     527                def assaySamples = getAssaySamples( params );
     528                def name
     529               
     530                if( assaySamples == null )
     531                        return;
     532                       
     533                if( assaySamples.size() == 0 ) {
     534                        flash.error = "No samples found for selected runs";
     535                        redirect( action: "list" );
     536                        return;
     537                } else if( assaySamples*.run.unique().size() == 1 ) {
     538                        name = "Run_" + assaySamples[0].run?.name?.replace( ' ', '_' );
     539                } else {
     540                        name = "runs";
     541                }
     542
     543                // Export the metadata
     544                response.setHeader "Content-disposition", "attachment; filename=${name}.xls"
     545                try {
     546                        // The export functionality needs a assaysSample-tag list, but it
     547                        // should be empty when only exporting metadata
     548                        def tags = [];
     549                        assaySamples.unique().each { assaySample ->
     550                                tags << [assaySampleId: assaySample.id, sampleName: assaySample.sample.name, assayName: assaySample.assay.name, studyName: assaySample.assay.study.name, tag: "-"]
     551                        }
     552                        sampleExcelService.exportExcelSampleData( assaySamples.unique(), tags, response.getOutputStream() );
     553                        response.outputStream.flush();
     554                } catch( Exception e ) {
     555                        log.error( "Exception occurred during export of sequences. Probably the user has cancelled the download." );
     556                }
     557        }
     558       
     559        protected List getAssaySamples( params ) {
     560                def ids = params.list( 'ids' );
     561               
     562                ids = ids.findAll { it.isLong() }.collect { Long.parseLong( it ) }
     563
     564                if( !ids ) {
     565                        def message = "No run ids given"
     566                        flash.error = message
     567                        redirect( action: "index" );
     568                        return;
     569                }
     570
     571                def assaySamples = [];
     572
     573                // Determine which assaySamples to export
     574                ids.each { id ->
     575                        def run = Run.get( id );
     576                        if( run )
     577                                assaySamples += run.assaySamples.findAll { it.assay.study.canRead( session.user ) }
     578                }
     579               
     580                return assaySamples;
     581        }
    494582
    495583        /**
  • trunk/grails-app/controllers/nl/tno/metagenomics/SampleController.groovy

    r13 r14  
    11package nl.tno.metagenomics
     2
     3import java.util.List;
    24
    35import org.codehaus.groovy.grails.commons.ConfigurationHolder
     
    57class SampleController {
    68        def fastaService
     9        def sampleExcelService
    710
    811        def index = {
    912                redirect( controller: 'study' );
    1013        }
     14
     15        /**
     16        * Exports data about one or more studies in fasta format
     17        */
     18   def exportAsFasta = {
     19           def assaySamples = getAssaySamples( params );
     20           def name
     21
     22           if( assaySamples == null ) {
     23                   return
     24           } else if( assaySamples*.sample.unique().size() == 1 ) {
     25                   name = "Sample_" + assaySamples[0].sample.name?.replace( ' ', '_' );
     26           } else {
     27                   name = "samples";
     28           }
     29
     30           // Export the sequences and quality scores
     31           response.setHeader "Content-disposition", "attachment; filename=" + name.trim() + ".zip"
     32           try {
     33                   fastaService.export( assaySamples.unique(), response.getOutputStream(), name );
     34                   response.outputStream.flush();
     35           } catch( Exception e ) {
     36                   log.error( "Exception occurred during export of sequences. Probably the user has cancelled the download." );
     37           }
     38   }
     39
     40   /**
     41        * Export metadata of one or more studies in excel format
     42        */
     43   def exportMetaData = {
     44           def assaySamples = getAssaySamples( params );
     45           def name
     46
     47           if( assaySamples == null ) {
     48                   return
     49           } else if( assaySamples*.sample.unique().size() == 1 ) {
     50                   name = "Sample_" + assaySamples[0].sample.name?.replace( ' ', '_' );
     51           } else {
     52                   name = "samples";
     53           }
     54
     55           // Export the metadata
     56           response.setHeader "Content-disposition", "attachment; filename=${name}.xls"
     57           try {
     58                   // The export functionality needs a assaySample-tag list, but it
     59                   // should be empty when only exporting metadata
     60                   def tags = [];
     61                   assaySamples.unique().each { assaySample ->
     62                           tags << [assaySampleId: assaySample.id, sampleName: assaySample.sample.name, assayName: assaySample.assay.name, studyName: assaySample.assay.study.name, tag: "-"]
     63                   }
     64                   sampleExcelService.exportExcelSampleData( assaySamples.unique(), tags, response.getOutputStream() );
     65                   response.outputStream.flush();
     66           } catch( Exception e ) {
     67                   log.error( "Exception occurred during export of metadata. Probably the user has cancelled the download." );
     68                   e.printStackTrace();
     69           }
     70   }
     71               
    1172       
     73       
     74               
    1275        /**
    13          * Exports data about one or more samples in fasta format
     76         * Parse the given parameters and try to extract assaysamples using ids and tokens of samples
     77         * @param params
     78         * @return
    1479         */
    15         def exportAsFasta = {
     80        protected List getAssaySamples( params ) {
    1681                def tokens = params.list( 'tokens' );
    1782                def ids = params.list( 'ids' );
    18                
     83                def name;
     84
    1985                ids = ids.findAll { it.isLong() }.collect { Long.parseLong( it ) }
    20                
     86
    2187                if( !tokens && !ids ) {
    2288                        def message = "No sample tokens or ids given"
    23                         response.setStatus( 400, message)
    24                         render message;
     89                        flash.error = message
     90                        redirect( action: "index" );
    2591                        return;
    2692                }
    27                
     93
    2894                def assaySamples = [];
    29                 def name = "samples";
    30                
     95
    3196                // Determine which assaySamples to export
     97                def sample;
    3298                tokens.each { token ->
    33                         def sample = Sample.findBySampleToken( token );
    34                         if( sample )
    35                                 assaySamples += sample.assaySamples
     99                        sample = Sample.findBySampleToken( token );
     100                        if( sample.study.canRead( session.user ) ) {
     101                                if( sample && sample.assaySamples )
     102                                        assaySamples += sample.assaySamples;
     103                        }
    36104                }
    37105                ids.each { id ->
    38                         def sample = Sample.get( id );
    39                         if( sample )
    40                                 assaySamples += sample.assaySamples
     106                        sample = Sample.get( id );
     107                        if( sample.study.canRead( session.user ) ) {
     108                                if( sample && sample.assaySamples )
     109                                        assaySamples += sample.assaySamples;
     110                        }
    41111                }
    42                
    43                 // Export the sequences and quality scores
    44                 response.setHeader "Content-disposition", "attachment; filename=${name}.zip"
    45                 fastaService.export( assaySamples.unique(), response.getOutputStream(), name );
    46                 response.outputStream.flush();
     112
     113                return assaySamples;
    47114        }
     115
     116       
    48117}
  • trunk/grails-app/controllers/nl/tno/metagenomics/StudyController.groovy

    r13 r14  
    11package nl.tno.metagenomics
     2
     3import java.util.List;
    24
    35class StudyController {
     
    68        def fileService
    79        def trashService
     10        def fastaService
     11        def sampleExcelService
    812       
    913        def index = {
     
    2125        }
    2226       
    23         def exportAsExcel = {
    24                 render "To be implemented"
     27
     28        /**
     29         * Exports data about one or more studies in fasta format
     30         */
     31        def exportAsFasta = {
     32                def assaySamples = getAssaySamples( params );
     33                def name
     34
     35                if( assaySamples == null ) {
     36                        return
     37                } else if( assaySamples*.assay*.study.unique().size() == 1 ) {
     38                        name = "Study_" + assaySamples[0].assay.study.name?.replace( ' ', '_' );
     39                } else {
     40                        name = "studies";
     41                }
     42
     43                // Export the sequences and quality scores
     44                response.setHeader "Content-disposition", "attachment; filename=" + name.trim() + ".zip"
     45                try {
     46                        fastaService.export( assaySamples.unique(), response.getOutputStream(), name );
     47                        response.outputStream.flush();
     48                } catch( Exception e ) {
     49                        log.error( "Exception occurred during export of sequences. Probably the user has cancelled the download." );
     50                }
     51        }
     52
     53        /**
     54         * Export metadata of one or more studies in excel format
     55         */
     56        def exportMetaData = {
     57                def assaySamples = getAssaySamples( params );
     58                def name
     59
     60                if( assaySamples == null ) {
     61                        return
     62                } else if( assaySamples*.assay*.study.unique().size() == 1 ) {
     63                        name = "Study_" + assaySamples[0].assay.study.name?.replace( ' ', '_' );
     64                } else {
     65                        name = "studies";
     66                }
     67
     68                // Export the metadata
     69                response.setHeader "Content-disposition", "attachment; filename=${name}.xls"
     70                try {
     71                        // The export functionality needs a assaySample-tag list, but it
     72                        // should be empty when only exporting metadata
     73                        def tags = [];
     74                        assaySamples.unique().each { assaySample ->
     75                                tags << [assaySampleId: assaySample.id, sampleName: assaySample.sample.name, assayName: assaySample.assay.name, studyName: assaySample.assay.study.name, tag: "-"]
     76                        }
     77                        sampleExcelService.exportExcelSampleData( assaySamples.unique(), tags, response.getOutputStream() );
     78                        response.outputStream.flush();
     79                } catch( Exception e ) {
     80                        log.error( "Exception occurred during export of metadata. Probably the user has cancelled the download." );
     81                        e.printStackTrace();
     82                }
     83        }
     84
     85        /**
     86         * Parse the given parameters and try to extract studies using ids and tokens
     87         * @param params
     88         * @return
     89         */
     90        protected List getAssaySamples( params ) {
     91                def tokens = params.list( 'tokens' );
     92                def ids = params.list( 'ids' );
     93                def name;
     94
     95                ids = ids.findAll { it.isLong() }.collect { Long.parseLong( it ) }
     96
     97                if( !tokens && !ids ) {
     98                        def message = "No assay tokens or ids given"
     99                        flash.error = message
     100                        redirect( action: "index" );
     101                        return;
     102                }
     103
     104                def assaySamples = [];
     105
     106                // Determine which assaySamples to export
     107                def study;
     108                tokens.each { token ->
     109                        study = Study.findByStudyToken( token );
     110                        if( study && study.canRead( session.user ) )
     111                                assaySamples += study.assays*.assaySamples.flatten();
     112                }
     113                ids.each { id ->
     114                        study = Study.get( id );
     115                        if( study && study.canRead( session.user ) )
     116                                assaySamples += study.assays*.assaySamples.flatten();
     117                }
     118
     119                return assaySamples;
    25120        }
    26121
  • trunk/grails-app/controllers/nl/tno/metagenomics/integration/RestController.groovy

    r13 r14  
    233233                                        log.error "Data was requested for " + entity.toLowerCase() + " " + object.name + " but the user " + session.user.username + " doesn't have the right privileges."
    234234                                        continue;
    235                                 } else {
    236                                         log.error "Data was requested for " + entity.toLowerCase() + " " + object.name + ": " + session.user.username + " - " + study.canRead( session.user )
    237235                                }
    238236                               
     
    373371                        switch( entity ) {
    374372                                case "Study":
    375                                         actions[ entity ] = [ [ name: "excel", description: "Export as excel", url: createLink( controller: "study", action: "exportAsExcel", absolute: true ) ] ]
     373                                        actions[ entity ] = [
     374                                                [ name: "excel", description: "Export metadata", url: createLink( controller: "study", action: "exportMetaData", absolute: true ) ],
     375                                                [ name: "fasta", description: "Export as fasta", url: createLink( controller: "study", action: "exportAsFasta", absolute: true ) ]
     376                                        ]
    376377                                        break;
    377378                                case "Assay":
    378                                         actions[ entity ] = [ [ name: "fasta", description: "Export as fasta", url: createLink( controller: "assay", action: "exportAsFasta", absolute: true ) ] ]
     379                                        actions[ entity ] = [
     380                                                [ name: "fasta", description: "Export as fasta", url: createLink( controller: "assay", action: "exportAsFasta", absolute: true ) ],
     381                                                [ name: "excel", description: "Export metadata", url: createLink( controller: "assay", action: "exportMetaData", absolute: true ) ]
     382                                        ]
    379383                                        break;
    380384                                case "Sample":
    381                                         actions[ entity ] = [ [ name: "fasta", description: "Export as fasta", url: createLink( controller: "sample", action: "exportAsFasta", absolute: true ) ] ]
     385                                        actions[ entity ] = [
     386                                                [ name: "fasta", description: "Export as fasta", url: createLink( controller: "sample", action: "exportAsFasta", absolute: true ) ],
     387                                                [ name: "excel", description: "Export metadata", url: createLink( controller: "sample", action: "exportMetaData", absolute: true ) ]
     388                                        ]
    382389                                        break;
    383390                                default:
  • trunk/grails-app/services/nl/tno/metagenomics/SampleExcelService.groovy

    r13 r14  
    8787                       
    8888                headers.eachWithIndex { header, idx ->
    89                         // Do matching using fuzzy search. The 0.1 treshold makes sure that no match if chosen if
     89                        // Do matching using fuzzy search. The 0.8 treshold makes sure that no match if chosen if
    9090                        // there is actually no match at all.
    91                         bestMatches[idx] = fuzzySearchService.mostSimilar( header, possibleFields, 0.1 );
     91                        if( !header || header.toString().trim() == "" )
     92                                bestMatches[idx] = null
     93                        else
     94                                bestMatches[idx] = fuzzySearchService.mostSimilar( header, possibleFields, 0.8 );
    9295                }
    9396               
     
    119122                def dataMatches = false;
    120123                possibleFields.each { columnName ->
    121                         columns[ columnName ] = matchColumns.findIndexOf { it.value == columnName }
     124                        def foundColumn = matchColumns.find { it.value == columnName };
     125                       
     126                        columns[ columnName ] = ( foundColumn && foundColumn.key.toString().isInteger() ) ? Integer.valueOf( foundColumn.key.toString() ) : -1;
    122127
    123128                        if( columnName != sampleNameName && columns[ columnName ] != -1 )
     
    125130                }
    126131
     132                println columns
     133               
    127134                // A column to match the sample name must be present
    128135                if( columns[ sampleNameName ] == -1 ) {
    129                         // Now delete the file, since we don't need it anymore
    130                         _deleteUploadedFileFromSession()
    131 
    132136                        return [ success: false, message: "There must be a column present in the excel file that matches the sample name. Please try again." ]
    133137                }
     
    135139                // A column with data should also be present
    136140                if( !dataMatches ) {
    137                         // Now delete the file, since we don't need it anymore
    138                         _deleteUploadedFileFromSession()
    139 
    140141                        return [ success: false, message: "There are no data columns present in the excel file. No samples are updated." ]
    141142                }
     
    166167                        String sampleName = rowData[ columns[ sampleNameName ] ] as String
    167168
     169                        // If no sample name is found, the row is either empty or contains no sample name
     170                        if( !sampleName ) {
     171                                failedRows << [ row: rowData, sampleName: "" ];
     172                                continue;
     173                        }
     174                               
    168175                        // Find assay by sample name. Since sample names are unique within an assay (enforced by GSCF),
    169176                        // this will always work when only using one assay. When multiple assays are used, this might pose
    170177                        // a problem
     178                        // TODO: Fix problem with multiple assays
    171179                        AssaySample assaySample = assaySamples.find { it.sample.id == Sample.findByName( sampleName )?.id };
     180                        println "Row: " + i + " - Sample name: " + sampleName + " - " + assaySample
    172181
    173182                        // If no assaysample is found, add this row to the failed-row list
  • trunk/grails-app/services/nl/tno/metagenomics/integration/GscfService.groovy

    r13 r14  
    2424         */
    2525        public String urlAuthRemote( def params, def token ) {
    26                 def redirectURL = "${config.gscf.baseURL}/login/auth_remote?moduleURL=${this.moduleURL()}&consumer=${this.consumerID()}&token=${token}&returnUrl=${config.grails.serverURL}"
    27 
     26                def redirectURL = "${config.gscf.baseURL}/login/auth_remote?moduleURL=${this.moduleURL()}&consumer=${this.consumerID()}&token=${token}&"
     27
     28                def returnUrl = config.grails.serverURL
    2829                if (params.controller != null){
    29                         redirectURL += "/${params.controller}"
     30                        returnUrl += "/${params.controller}"
    3031                        if (params.action != null){
    31                                 redirectURL += "/${params.action}"
     32                                returnUrl += "/${params.action}"
    3233                                if (params.id != null){
    33                                         redirectURL += "/${params.id}"
     34                                        returnUrl += "/${params.id}"
    3435                                }
    3536                        }
    3637                }
    3738
    38                 return redirectURL
     39                // Append other parameters
     40                returnUrl += "?" + params.collect {
     41                        if( it.key != "controller" && it.key != "action" && it.key != "id" )
     42                                return it.key.toString().encodeAsURL() + "=" + it.value.toString().encodeAsURL();
     43                        else
     44                                return ""
     45                }.findAll { it }.join( "&" );
     46               
     47                return redirectURL + "returnUrl=" + returnUrl.encodeAsURL();
    3948        }
    4049
     
    6574         * @return Map
    6675         */
    67         public Map getUser(String sessionToken) {
     76        public Map getUser(String sessionToken) throws Exception {
    6877                def user = [:]
    69                 this.callGSCF(sessionToken, "getUser").each {
    70                         user[ it.key ] = it.value;
    71                 }
    72                 return user
     78                try {
     79                        this.callGSCF(sessionToken, "getUser").each {
     80                                user[ it.key ] = it.value;
     81                        }
     82                        return user
     83                } catch( Exception e ) {
     84                        throw new Exception( "Retrieving user details from GSCF failed", e );
     85                }
    7386        }
    7487
     
    8093         * @return ArrayList
    8194         */
    82         public ArrayList getStudies(String sessionToken) {
     95        public ArrayList getStudies(String sessionToken) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    8396                return this.callGSCF(sessionToken, "getStudies")
    8497        }
     
    92105         * @return ArrayList
    93106         */
    94         public ArrayList getStudies(String sessionToken, ArrayList studyTokens ) {
     107        public ArrayList getStudies(String sessionToken, ArrayList studyTokens ) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception  {
    95108                return this.callGSCF(sessionToken, "getStudies", [ "studyToken": studyTokens ] );
    96109        }
     
    104117         * @return ArrayList
    105118         */
    106         public def getStudy(String sessionToken, String studyToken) throws NotAuthorizedException, ResourceNotFoundException {
     119        public def getStudy(String sessionToken, String studyToken) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    107120                def list
    108121
     
    131144         * @return ArrayList
    132145         */
    133         public ArrayList getAssays(String sessionToken, String studyToken) throws NotAuthorizedException, ResourceNotFoundException {
     146        public ArrayList getAssays(String sessionToken, String studyToken) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    134147                try {
    135148                        return this.callGSCF(sessionToken, "getAssays", ["studyToken": studyToken])
     
    150163         * @return ArrayList
    151164         */     
    152         public def getAssay(String sessionToken, String studyToken, String assayToken ) throws NotAuthorizedException, ResourceNotFoundException {
     165        public def getAssay(String sessionToken, String studyToken, String assayToken )throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    153166                def list
    154167                try {
     
    178191         * @return ArrayList
    179192         */
    180         public def getSample(String sessionToken, String assayToken, String sampleToken) throws NotAuthorizedException, ResourceNotFoundException {
     193        public def getSample(String sessionToken, String assayToken, String sampleToken) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    181194                def list
    182195
     
    205218         * @return ArrayList
    206219         */
    207         public ArrayList getSamples(String sessionToken, String assayToken) throws NotAuthorizedException, ResourceNotFoundException {
     220        public ArrayList getSamples(String sessionToken, String assayToken) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    208221                // Samples of a Study limited to a single Assay
    209222                try {
     
    225238         * @return ArrayList
    226239         */
    227         public def getSamples(String sessionToken, List sampleTokens) throws NotAuthorizedException, ResourceNotFoundException {
     240        public def getSamples(String sessionToken, List sampleTokens) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    228241                def list
    229242
     
    249262         * @return ArrayList
    250263         */
    251         public HashMap getAuthorizationLevel(String sessionToken, String studyToken) throws ResourceNotFoundException {
     264        public HashMap getAuthorizationLevel(String sessionToken, String studyToken) throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    252265                ArrayList list
    253266
  • trunk/grails-app/services/nl/tno/metagenomics/integration/SynchronizationService.groovy

    r13 r14  
    6767                        }
    6868                }
     69               
     70                // Append other parameters
     71                returnUrl += "?" + params.collect {
     72                        if( it.key != "controller" && it.key != "action" && it.key != "id" )
     73                                return it.key.toString().encodeAsURL() + "=" + it.value.toString().encodeAsURL();
     74                        else
     75                                return ""
     76                }.findAll { it }.join( "&" );
     77               
    6978                if( timeForFullSynchronization() ) {
    7079                        return ConfigurationHolder.config.grails.serverURL + "/synchronize/full?redirect=" + returnUrl.encodeAsURL()
     
    91100         * @return      ArrayList       List of studies or null if the synchronization has failed
    92101         */
    93         public ArrayList<Study> synchronizeStudies() throws NotAuthenticatedException, Exception {
     102        public ArrayList<Study> synchronizeStudies() throws BadRequestException, NotAuthenticatedException, NotAuthorizedException, ResourceNotFoundException, Exception {
    94103                if( !performSynchronization() )
    95104                        return Study.findAllWhereTrashcan(false)
     
    140149                        // synchronizing and return null
    141150                        log.error( "Exception occurred when fetching studies: " + e.getMessage() )
    142                         throw new Exception( "Error while fetching studies", e)
     151                        throw e
    143152                }
    144153
  • trunk/grails-app/views/assay/index.gsp

    r13 r14  
    1717                                <thead>
    1818                                        <tr>
    19                                                 <th class="nonsortable"></th>
     19                                                <th class="nonsortable"><input type="checkbox" id="checkAll" onClick="checkAllPaginated(this);" /></th>
    2020                                                <th>Assay</th>
    2121                                                <th>Study</th>
     
    2929                                                        <g:each in="${study.assays}" var="assay">
    3030                                                                <tr>
    31                                                                         <td><g:checkBox name="ids" value="${assay.id}" checked="${false}" /></td>
     31                                                                        <td><g:checkBox name="ids" value="${assay.id}" checked="${false}" onClick="updateCheckAll(this);" /></td>
    3232                                                               
    3333                                                                        <td><g:link controller="assay" action="show" id="${assay.id}">${assay.name}</g:link></td>
     
    5050                        <p class="options">
    5151                                <a class="fasta" href="#" onClick="submitPaginatedForm( $( '#assayForm' ), '<g:createLink action="exportAsFasta" />', '#assays', 'Please select an assay to export' ); return false;">Export as fasta</a>
     52                                <a class="excel" href="#" onClick="submitPaginatedForm( $( '#assayForm' ), '<g:createLink action="exportMetaData" />', '#assays', 'Please select an assay to export' ); return false;">Export metadata</a>
    5253                        </p>
    5354                       
  • trunk/grails-app/views/common/_topnav.gsp

    r9 r14  
    11    <!-- TOPNAV //-->
    22    <ul class="topnav">
    3      <li><g:link controller="study">Home</g:link></li>
     3     <li><g:link controller="run">Home</g:link></li>
    44        <li>
    55      <a href="#" onClick="return false;">View</a>
     
    77                <li><g:link controller="run">Runs</g:link></li>
    88                <li><g:link controller="assay">Assays</g:link></li>
     9                <li><g:link controller="study">Studies</g:link></li>
    910      </ul>
    1011    </li>
  • trunk/grails-app/views/layouts/main.gsp

    r13 r14  
    3737                        <div id="content">
    3838                                <g:if test="${lastSynchronized}">
    39                                         <p>Last full synchronization: ${lastSynchronized}</p>
     39                                        <!-- Last full synchronization: ${lastSynchronized} -->
    4040                                </g:if>
    4141                                <g:if test="${flash.error}">
  • trunk/grails-app/views/run/index.gsp

    r13 r14  
    3030                                <thead>
    3131                                        <tr>
    32                                                 <th class="nonsortable"></th>
     32                                                <th class="nonsortable"><input type="checkbox" id="checkAll" onClick="checkAllPaginated(this);" /></th>
    3333                                                <th>Run</th>
    3434                                                <th># samples</th>
     
    3939                                        <g:each in="${runs}" var="run">
    4040                                                <tr>
    41                                                         <td><g:checkBox name="ids" value="${run.id}" checked="${false}" /></td>
     41                                                        <td><g:checkBox name="ids" value="${run.id}" checked="${false}" onClick="updateCheckAll(this);" /></td>
    4242                                                        <td><g:link controller="run" action="show" id="${run.id}">${run.name}</g:link></td>
    4343                                                        <td>${run.assaySamples?.size()}</td>
     
    5050                                <a class="add" href="#" onClick="showAddRunDialog(); return false;">Add run</a>
    5151                                <a class="fasta" href="#" onClick="submitPaginatedForm( $( '#runForm' ), '<g:createLink action="exportAsFasta" />', '#runs', 'Please select a run to export' ); return false;">Export as fasta</a>
     52                                <a class="excel" href="#" onClick="submitPaginatedForm( $( '#runForm' ), '<g:createLink action="exportMetaData" />', '#runs', 'Please select a run to export' ); return false;">Export metadata</a>
    5253                        </p>
    5354                </g:else>
  • trunk/grails-app/views/study/index.gsp

    r7 r14  
    1212                </g:if>
    1313                <g:else>
    14                         <table class="paginate">
     14                        <form id="assayForm">
     15                        </form>
     16               
     17                        <table id="studies" class="paginate">
    1518                                <thead>
    1619                                        <tr>
    17 
     20                                                <th class="nonsortable"><input type="checkbox" id="checkAll" onClick="checkAllPaginated(this);" /></th>
     21                                                <th>Study</th>
    1822                                                <th>Assay</th>
    19                                                 <th>Study</th>
    2023                                                <th># samples</th>
    2124                                        </tr>
     
    3437                                                        <g:each in="${study.assays}" var="assay">
    3538                                                                <tr>
     39                                                                        <td><g:checkBox name="ids" value="${assay.id}" checked="${false}" onClick="updateCheckAll(this);" /></td>
     40                                                                        <td><a href="${study.viewUrl()}">${study.name}</a></td>
    3641                                                                        <td><g:link controller="assay" action="show" id="${assay.id}">${assay.name}</g:link></td>
    37                                                                         <td><a href="${study.viewUrl()}">${study.name}</a></td>
    3842                                                                        <td>${assay.assaySamples?.size()}</td>
    3943                                                                </tr>
     
    4347                                </tbody>
    4448                        </table>
     49                        <p class="options">
     50                                <a class="fasta" href="#" onClick="submitPaginatedForm( $( '#assayForm' ), '<g:createLink controller="assay" action="exportAsFasta" />', '#studies', 'Please select one or more studies to export' ); return false;">Export as fasta</a>
     51                                <a class="excel" href="#" onClick="submitPaginatedForm( $( '#assayForm' ), '<g:createLink controller="assay" action="exportMetaData" />', '#studies', 'Please select one or more studies to export' ); return false;">Export metadata</a>
     52                        </p>                   
    4553                </g:else>                       
    4654        </body>
  • trunk/web-app/css/buttons.css

    r13 r14  
    66        padding-bottom: 2px;
    77        line-height: 20px;
    8         padding-left: 28px;     
     8        padding-left: 26px;     
     9       
     10        background-image: transparent;
     11        background-repeat: no-repeat;
     12        background-position: 3px 50%;
    913}
    1014
     
    1216
    1317.options a.fasta {
    14         background: transparent url(../plugins/famfamfam-1.0.1/images/icons/brick_go.png) 5px 50% no-repeat;
     18        background-image: url(../plugins/famfamfam-1.0.1/images/icons/brick_go.png);
    1519}
    1620.options a.excel {
     
    1822}
    1923.options a.edit {
    20         background: transparent url(../plugins/famfamfam-1.0.1/images/icons/pencil.png) 5px 50% no-repeat;
     24        background-image:  url(../plugins/famfamfam-1.0.1/images/icons/pencil.png);
    2125}
    2226.options a.add {
    23         background: transparent url(../plugins/famfamfam-1.0.1/images/icons/add.png) 5px 50% no-repeat;
     27        background-image:  url(../plugins/famfamfam-1.0.1/images/icons/add.png);
    2428}
    2529.options a.addSequences {
    26         background: transparent url(../plugins/famfamfam-1.0.1/images/icons/page_attach.png) 5px 50% no-repeat;
     30        background-image:  url(../plugins/famfamfam-1.0.1/images/icons/page_attach.png);
    2731}
    2832
    2933.options a.addAssociation {
    30         background: transparent url(../plugins/famfamfam-1.0.1/images/icons/application_add.png) 5px 50% no-repeat;
     34        background-image:  url(../plugins/famfamfam-1.0.1/images/icons/application_add.png);
    3135}
    3236.options a.editAssociation {
    33         background: transparent url(../plugins/famfamfam-1.0.1/images/icons/application_edit.png) 5px 50% no-repeat;
     37        background-image:  url(../plugins/famfamfam-1.0.1/images/icons/application_edit.png);
    3438}
  • trunk/web-app/css/datatables/demo_table_jui.css

    r11 r14  
    7878.dataTables_wrapper { font-size: 10px; }
    7979
     80/* Check all checkbox */
     81input.transparent {
     82        -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";
     83        filter: alpha(opacity=30);
     84        opacity: 0.3;
     85        -moz-opacity: 0.3;
     86        -khtml-opacity: 0.3;
     87}
     88
    8089/*
    8190 * Sort arrow icon positioning
  • trunk/web-app/js/paginate.js

    r4 r14  
    4949                }
    5050        });
     51}
     52
     53function checkAllPaginated( input ) {
     54        var paginatedTable = $(input).closest( '.paginate' );
     55        var dataTable = paginatedTable.closest( '.dataTables_wrapper' );
     56        var checkAll = $( '#checkAll', paginatedTable );
    5157       
     58        var oTable = paginatedTable.dataTable();
     59        var inputs = $('input', oTable.fnGetNodes())
     60       
     61        // If any of the inputs is checked, uncheck all. Otherwise, check all
     62        var check = false;
     63       
     64        for(var i = 0; i < inputs.length; i++ ) {
     65                if( !$(inputs[i]).attr( 'checked' ) ) {
     66                        check = true;
     67                        break;
     68                }
     69        }
     70       
     71        inputs.each( function( idx, el ) {
     72                $(el).attr( 'checked', check );
     73        })
     74       
     75        updateCheckAll( checkAll );
     76}
     77
     78function updateCheckAll( input ) {
     79        var paginatedTable = $(input).closest( '.paginate' );
     80        var dataTable = paginatedTable.closest( '.dataTables_wrapper' );
     81       
     82        var checkAll = $( '#checkAll', paginatedTable );
     83       
     84        var oTable = paginatedTable.dataTable();
     85        var inputs = $('input', oTable.fnGetNodes())
     86       
     87        // Is none checked, are all checked or are some checked
     88        var numChecked = 0
     89        for(var i = 0; i < inputs.length; i++ ) {
     90                if( $(inputs[i]).attr( 'checked' ) ) {
     91                        numChecked++;
     92                }
     93        }
     94       
     95        checkAll.attr( 'checked', numChecked > 0 );
     96       
     97        if( numChecked > 0 && numChecked < inputs.length - 1 ) {
     98                checkAll.addClass( 'transparent' );
     99        } else {
     100                checkAll.removeClass( 'transparent' );
     101        }
    52102}
    53103
Note: See TracChangeset for help on using the changeset viewer.