Changeset 1605 for trunk


Ignore:
Timestamp:
Mar 8, 2011, 6:04:12 PM (10 years ago)
Author:
s.h.sikkema@…
Message:

commit for Robert: see if webflow works when all logic is moved to SimpleService?

Location:
trunk/grails-app
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/controllers/dbnp/studycapturing/SimpleController.groovy

    r1601 r1605  
    2828        def fileService
    2929        def importerService
    30         def gdtService = new GdtService()
     30        def gdtService
     31    def simpleService
    3132
    3233        /**
     
    4041                entry {
    4142                        action{
    42                                 flow.study = getStudyFromRequest( params )
     43                                flow.study = simpleService.getStudyFromRequest( params )
    4344                                if (!flow.study) retrievalError()
    4445                        }
     
    4950                study {
    5051                        on("next") {
    51                                 handleStudy( flow.study, params )
    52                                 if( !validateObject( flow.study ) )
     52                                simpleService.handleStudy( flow.study, params )
     53                                if( !simpleService.validateObject( flow.study ) )
    5354                                        error()
    5455                        }.to "decisionState"
    55                         on("refresh") { handleStudy( flow.study, params ); }.to "study"
    56                         on( "success" ) { handleStudy( flow.study, params ) }.to "study"
     56                        on("refresh") { simpleService.handleStudy( flow.study, params ) }.to "study"
     57                        on( "success" ) { simpleService.handleStudy( flow.study, params ) }.to "study"
    5758                }
    5859
     
    7475
    7576                                if (flow.study.samples)
    76                                         checkStudySimplicity(flow.study) ? existingSamples() : complexStudy()
     77                                        simpleService.checkStudySimplicity(flow.study) ? existingSamples() : complexStudy()
    7778                                else
    7879                                        samples()
     
    9697                existingSamples {
    9798                        on("next") {
    98                                 handleExistingSamples( flow.study, params, flow ) ? success() : error()
     99                                simpleService.handleExistingSamples( flow.study, params, flow ) ? success() : error()
    99100                        }.to "startAssays"
    100101                        on("previous").to "study"
    101102                        on("update") {
    102                                 handleExistingSamples( flow.study, params, flow ) ? success() : error()
     103                                simpleService.handleExistingSamples( flow.study, params, flow ) ? success() : error()
    103104                        }.to "samples"
    104105
     
    113114                samples {
    114115                        on("next") {
    115                                 handleSamples( flow.study, params, flow ) ? success() : error ()
     116                                simpleService.handleSamples( flow.study, params, flow ) ? success() : error ()
    116117                               
    117118                                // Add domain fields for all entities
     
    140141                columns {
    141142                        on( "next" ) {
    142                                 handleColumns( flow.study, params, flow ) ? success() : error()
     143                                simpleService.handleColumns( flow.study, params, flow ) ? success() : error()
    143144                        }.to "checkImportedEntities"
    144145                        on( "previous" ).to "samples"
     
    166167                missingFields {
    167168                        on( "next" ) {
    168                                 if( !handleMissingFields( flow.study, params ) )
     169                                if( !simpleService.handleMissingFields( flow.study, params ) )
    169170                                        error();
    170171                               
     
    192193                assays {
    193194                        on( "next" ) {
    194                                 handleAssays( flow.assay, params, flow );
    195                                 if( !validateObject( flow.assay ) )
     195                                simpleService.handleAssays( flow.assay, params, flow );
     196                                if( !simpleService.validateObject( flow.assay ) )
    196197                                        error();
    197198                         }.to "overview"
     
    205206                         }.to "overview"
    206207                        on( "previous" ).to "returnFromAssays"
    207                         on("refresh") { handleAssays( flow.assay, params, flow ); }.to "assays"
     208                        on("refresh") { simpleService.handleAssays( flow.assay, params, flow ); }.to "assays"
    208209                }
    209210
     
    266267                }
    267268        }
    268 
    269         /**
    270          * Retrieves the required study from the database or return an empty Study object if
    271          * no id is given
    272          *
    273          * @param params        Request parameters with params.id being the ID of the study to be retrieved
    274          * @return                      A study from the database or an empty study if no id was given
    275          */
    276         protected Study getStudyFromRequest( def params ) {
    277                 int id = params.int( "id" );
    278 
    279                 if( !id ) {
    280                         return new Study( title: "New study", owner: authenticationService.getLoggedInUser() );
    281                 }
    282 
    283                 Study s = Study.get( id );
    284 
    285                 if( !s ) {
    286                         flash.error = "No study found with given id";
    287                         return null;
    288                 }
    289                 if( !s.canWrite( authenticationService.getLoggedInUser() ) ) {
    290                         flash.error = "No authorization to edit this study."
    291                         return null;
    292                 }
    293 
    294                 return s
    295         }
    296 
    297         /**
    298          * Handles study input
    299          * @param study         Study to update
    300          * @param params        Request parameter map
    301          * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    302          */
    303         def handleStudy( study, params ) {
    304                 // did the study template change?
    305                 if (params.get('template') && study.template?.name != params.get('template')) {
    306                         // set the template
    307                         study.template = Template.findByName(params.remove('template'))
    308                 }
    309 
    310                 // does the study have a template set?
    311                 if (study.template && study.template instanceof Template) {
    312                         // yes, iterate through template fields
    313                         study.giveFields().each() {
    314                                 // and set their values
    315                                 study.setFieldValue(it.name, params.get(it.escapedName()))
    316                         }
    317                 }
    318 
    319                 // handle public checkbox
    320                 if (params.get("publicstudy")) {
    321                         study.publicstudy = params.get("publicstudy")
    322                 }
    323 
    324                 // handle publications
    325                 handleStudyPublications(study, params)
    326 
    327                 // handle contacts
    328                 handleStudyContacts(study, params)
    329 
    330                 // handle users (readers, writers)
    331                 handleStudyUsers(study, params, 'readers')
    332                 handleStudyUsers(study, params, 'writers')
    333 
    334                 return true
    335         }
    336        
    337         /**
    338         * Handles the editing of existing samples
    339         * @param study          Study to update
    340         * @param params         Request parameter map
    341         * @return                       True if everything went OK, false otherwise. An error message is put in flash.error
    342         */
    343    def handleExistingSamples( study, params, flow ) {
    344            flash.validationErrors = [:];
    345 
    346            def errors = false;
    347            
    348            // iterate through objects; set field values and validate the object
    349            def eventgroups = study.samples.parentEventGroup.findAll { it }
    350            def events;
    351            if( !eventgroups )
    352                    events = []
    353            else
    354                    events = eventgroups.events?.getAt(0);
    355            
    356            def objects = [
    357                    'Sample': study.samples,
    358                    'Subject': study.samples.parentSubject.findAll { it },
    359                    'SamplingEvent': study.samples.parentEvent.findAll { it },
    360                    'Event': events.flatten().findAll { it }
    361            ];
    362    
    363            objects.each {
    364                    def type = it.key;
    365                    def entities = it.value;
    366                    
    367                    entities.each { entity ->
    368                            // iterate through entity fields
    369                            entity.giveFields().each() { field ->
    370                                    def value = params.get( type.toLowerCase() + '_' + entity.getIdentifier() + '_' + field.escapedName())
    371 
    372                                    // set field value; name cannot be set to an empty value
    373                                    if (field.name != 'name' || value) {
    374                                            log.info "setting "+field.name+" to "+value
    375                                            entity.setFieldValue(field.name, value)
    376                                    }
    377                            }
    378                            
    379                            // has the template changed?
    380                            def templateName = params.get(type.toLowerCase() + '_' + entity.getIdentifier() + '_template')
    381                            if (templateName && entity.template?.name != templateName) {
    382                                    entity.template = Template.findByName(templateName)
    383                            }
    384    
    385                            // validate sample
    386                            if (!entity.validate()) {
    387                                    errors = true;
    388                                    flash.validationErrors << getHumanReadableErrors( entity )
    389                            }
    390                    }
    391            }
    392 
    393            return !errors
    394    }
    395 
    396         /**
    397          * Handles the upload of sample data
    398          * @param study         Study to update
    399          * @param params        Request parameter map
    400          * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    401          */
    402         def handleSamples( study, params, flow ) {
    403                 def filename = params.get( 'importfile' );
    404 
    405                 // Handle 'existing*' in front of the filename. This is put in front to make a distinction between
    406                 // an already uploaded file test.txt (maybe moved to some other directory) and a newly uploaded file test.txt
    407                 // still being in the temporary directory.
    408                 // This import step doesn't have to make that distinction, since all files remain in the temporary directory.
    409                 if( filename == 'existing*' )
    410                         filename = '';
    411                 else if( filename[0..8] == 'existing*' )
    412                         filename = filename[9..-1]
    413 
    414                 def sampleTemplateId  = params.long( 'sample_template_id' )
    415                 def subjectTemplateId  = params.long( 'subject_template_id' )
    416                 def eventTemplateId  = params.long( 'event_template_id' )
    417                 def samplingEventTemplateId  = params.long( 'samplingEvent_template_id' )
    418 
    419                 // These fields have been removed from the form, so will always contain
    420                 // their default value. The code however remains like this for future use.
    421                 int sheetIndex = (params.int( 'sheetindex' ) ?: 1 )
    422                 int dataMatrixStart = (params.int( 'datamatrix_start' ) ?: 2 )
    423                 int headerRow = (params.int( 'headerrow' ) ?: 1 )
    424 
    425                 // Save form data in session
    426                 flow.sampleForm = [
    427                                         importFile: filename,
    428                                         templateId: [
    429                                                 'Sample': sampleTemplateId,
    430                                                 'Subject': subjectTemplateId,
    431                                                 'Event': eventTemplateId,
    432                                                 'SampingEvent': samplingEventTemplateId
    433                                         ],
    434                                         template: [
    435                                                 'Sample': sampleTemplateId ? Template.get( sampleTemplateId ) : null,
    436                                                 'Subject': subjectTemplateId ? Template.get( subjectTemplateId ) : null,
    437                                                 'Event': eventTemplateId ? Template.get( eventTemplateId ) : null,
    438                                                 'SampingEvent': samplingEventTemplateId ? Template.get( samplingEventTemplateId ) : null
    439                                         ],
    440                                         sheetIndex: sheetIndex,
    441                                         dataMatrixStart: dataMatrixStart,
    442                                         headerRow: headerRow
    443                                 ];
    444 
    445                 // Check whether the template exists
    446                 if (!sampleTemplateId || !Template.get( sampleTemplateId ) ){
    447                         log.error ".simple study wizard not all fields are filled in: " + sampleTemplateId
    448                         flash.error = "No template was chosen. Please choose a template for the samples you provided."
    449                         return false
    450                 }
    451 
    452                 def importedfile = fileService.get( filename )
    453                 def workbook
    454                 if (importedfile.exists()) {
    455                         try {
    456                                 workbook = importerService.getWorkbook(new FileInputStream(importedfile))
    457                         } catch (Exception e) {
    458                                 log.error ".simple study wizard could not load file: " + e
    459                                 flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";
    460                                 return false
    461                         }
    462                 } else {
    463                         log.error ".simple study wizard no file given";
    464                         flash.error = "No file was given. Please provide an excel file for entering samples.";
    465                         return false;
    466                 }
    467 
    468                 if( !workbook ) {
    469                         log.error ".simple study wizard could not load file into a workbook"
    470                         flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";
    471                         return false
    472                 }
    473 
    474                 def selectedentities = []
    475 
    476                 if( !excelChecks( workbook, sheetIndex, headerRow, dataMatrixStart ) )
    477                         return false;
    478 
    479                 // Get the header from the Excel file using the arguments given in the first step of the wizard
    480                 def importerHeader;
    481                 def importerDataMatrix;
    482 
    483                 try {
    484                         importerHeader = importerService.getHeader(workbook,
    485                                         sheetIndex - 1,                 // 0 == first sheet
    486                                         headerRow,                              // 1 == first row :s
    487                                         dataMatrixStart - 1,    // 0 == first row
    488                                         Sample.class)
    489 
    490                         importerDataMatrix = importerService.getDatamatrix(
    491                                         workbook,
    492                                         importerHeader,
    493                                         sheetIndex - 1,                 // 0 == first sheet
    494                                         dataMatrixStart - 1,    // 0 == first row
    495                                         5)
    496                 } catch( Exception e ) {
    497                         // An error occurred while reading the excel file.
    498                         log.error ".simple study wizard error while reading the excel file";
    499                         e.printStackTrace();
    500 
    501                         // Show a message to the user
    502                         flash.error = "An error occurred while reading the excel file. Have you provided the right sheet number and row numbers. Contact your system administrator if this problem persists.";
    503                         return false;
    504                 }
    505 
    506                 // Save read excel data into session
    507                 def dataMatrix = [];
    508                 def df = new DataFormatter();
    509                 importerDataMatrix.each {
    510                         dataMatrix << it.collect{ it ? df.formatCellValue(it) : "" }
    511                 }
    512                
    513                 flow.excel = [
    514                                         filename: filename,
    515                                         sheetIndex: sheetIndex,
    516                                         dataMatrixStart: dataMatrixStart,
    517                                         headerRow: headerRow,
    518                                         data: [
    519                                                 header: importerHeader,
    520                                                 dataMatrix: dataMatrix
    521                                         ]
    522                                 ]
    523 
    524                 return true
    525         }
    526 
    527        
    528         /**
    529          * Handles the matching of template fields with excel columns by the user
    530          * @param study         Study to update
    531          * @param params        Request parameter map
    532          * @return                      True if everything went OK, false otherwise. An error message is put in flash.error
    533          *                                      The field session.simpleWizard.imported.numInvalidEntities reflects the number of
    534          *                                      entities that have errors, and should be fixed before saving. The errors for those entities
    535          *                                      are saved into session.simpleWizard.imported.errors
    536          */
    537         def handleColumns( study, params, flow ) {
    538                 // Find actual Template object from the chosen template name
    539                 def templates = [:];
    540                 flow.sampleForm.templateId.each {
    541                         templates[ it.key ] = it.value ? Template.get( it.value ) : null;
    542                 }
    543                
    544                 def headers = flow.excel.data.header;
    545 
    546                 if( !params.matches ) {
    547                         log.error( ".simple study wizard no column matches given" );
    548                         flash.error = "No column matches given";
    549                         return false;
    550                 }
    551 
    552                 // Retrieve the chosen matches from the request parameters and put them into
    553                 // the headers-structure, for later reference
    554                 params.matches.index.each { columnindex, value ->
    555                         // Determine the entity and property by splitting it
    556                         def parts = value.toString().tokenize( "||" );
    557                        
    558                         def property
    559                         def entityName
    560                         if( parts.size() > 1 ) {
    561                                 property = parts[ 1 ];
    562                                 entityName = "dbnp.studycapturing." + parts[ 0 ];
    563                         } else if( parts.size() == 1 ) {
    564                                 property = parts[ 0 ];
    565                                 entityName = headers[columnindex.toInteger()].entityclass.getName();
    566                         }
    567                        
    568                         // Create an actual class instance of the selected entity with the selected template
    569                         // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities
    570                         def entityClass = Class.forName( entityName, true, this.getClass().getClassLoader())
    571                         def entityObj = entityClass.newInstance(template: templates[ entityName[entityName.lastIndexOf( '.' ) + 1..-1] ])
    572 
    573                         headers[ columnindex.toInteger() ].entityclass = entityClass
    574                        
    575                         // Store the selected property for this column into the column map for the ImporterService
    576                         headers[columnindex.toInteger()].property = property
    577 
    578                         // Look up the template field type of the target TemplateField and store it also in the map
    579                         headers[columnindex.toInteger()].templatefieldtype = entityObj.giveFieldType(property)
    580 
    581                         // Is a "Don't import" property assigned to the column?
    582                         headers[columnindex.toInteger()].dontimport = (property == "dontimport") ? true : false
    583 
    584                         //if it's an identifier set the mapping column true or false
    585                         entityClass.giveDomainFields().each {
    586                                 headers[columnindex.toInteger()].identifier = ( it.preferredIdentifier && (it.name == property) )
    587                         }
    588                 }
    589 
    590                 // Import the workbook and store the table with entity records and store the failed cells
    591                 println "Importing samples for study " + study + " (" + study.id + ")";
    592                
    593                 def importedfile = fileService.get( flow.excel.filename )
    594                 def workbook
    595                 if (importedfile.exists()) {
    596                         try {
    597                                 workbook = importerService.getWorkbook(new FileInputStream(importedfile))
    598                         } catch (Exception e) {
    599                                 log.error ".simple study wizard could not load file: " + e
    600                                 flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";
    601                                 return false
    602                         }
    603                 } else {
    604                         log.error ".simple study wizard no file given";
    605                         flash.error = "No file was given. Please provide an excel file for entering samples.";
    606                         return false;
    607                 }
    608 
    609                 if( !workbook ) {
    610                         log.error ".simple study wizard could not load file into a workbook"
    611                         flash.error = "The given file doesn't seem to be an excel file. Please provide an excel file for entering samples.";
    612                         return false
    613                 }
    614                
    615                
    616                 def imported = importerService.importOrUpdateDataBySampleIdentifier(templates,
    617                                 workbook,
    618                                 flow.excel.sheetIndex - 1,
    619                                 flow.excel.dataMatrixStart - 1,
    620                                 flow.excel.data.header,
    621                                 flow.study,
    622                                 true                    // Also create entities for which no data is imported but where templates were chosen
    623                 );
    624 
    625                 def table = imported.table
    626                 def failedcells = imported.failedCells
    627 
    628                 flow.imported = [
    629                         data: table,
    630                         failedCells: failedcells
    631                 ];
    632 
    633                 // loop through all entities to validate them and add them to failedcells if an error occurs
    634                 def numInvalidEntities = 0;
    635                 def errors = [];
    636 
    637                 // Add all samples
    638                 table.each { record ->
    639                         record.each { entity ->
    640                                 if( entity ) {
    641                                         // Determine entity class and add a parent
    642                                         def preferredIdentifier = importerService.givePreferredIdentifier( entity.class );
    643                                         def equalClosure = { it.getFieldValue( preferredIdentifier.name ) == entity.getFieldValue( preferredIdentifier.name ) }
    644        
    645                                         entity.parent = study
    646                                        
    647                                         switch( entity.class ) {
    648                                                 case Sample:
    649                                                         if( preferredIdentifier && !study.samples?.find( equalClosure ) ) {
    650                                                                 study.addToSamples( entity );
    651                                                         }
    652                                                         break;
    653                                                 case Subject:
    654                                                         if( preferredIdentifier && !study.subjects?.find( equalClosure ) ) {
    655                                                                 study.addToSubjects( entity );
    656                                                         }
    657                                                         break;
    658                                                 case Event:
    659                                                         if( preferredIdentifier && !study.events?.find( equalClosure ) ) {
    660                                                                 study.addToEvents( entity );
    661                                                         }
    662                                                         break;
    663                                                 case SamplingEvent:
    664                                                         if( preferredIdentifier && !study.samplingEvents?.find( equalClosure ) ) {
    665                                                                 study.addToSamplingEvents( entity );
    666                                                         }
    667                                                         break;
    668                                         }
    669                                        
    670                                         if (!entity.validate()) {
    671                                                 numInvalidEntities++;
    672                                                
    673                                                 // Add this field to the list of failed cells, in order to give the user feedback
    674                                                 failedcells = addNonValidatingCells( failedcells, entity )
    675        
    676                                                 // Also create a full list of errors
    677                                                 errors += getHumanReadableErrors( entity );
    678                                         }
    679                                 }
    680                         }
    681                 }
    682 
    683                 flow.imported.numInvalidEntities = numInvalidEntities + failedcells?.size();
    684                 flow.imported.errors = errors;
    685 
    686                 return true
    687         }
    688 
    689        
    690        
    691         /**
    692          * Handles the update of the edited fields by the user
    693          * @param study         Study to update
    694          * @param params                Request parameter map
    695          * @return                      True if everything went OK, false otherwise. An error message is put in flash.error.
    696          *                                      The field session.simpleWizard.imported.numInvalidEntities reflects the number of
    697          *                                      entities that still have errors, and should be fixed before saving. The errors for those entities
    698          *                                      are saved into session.simpleWizard.imported.errors
    699          */
    700         def handleMissingFields( study, params, flow ) {
    701                 def numInvalidEntities = 0;
    702                 def errors = [];
    703 
    704                 // Check which fields failed previously
    705                 def failedCells = flow.imported.failedCells
    706 
    707                 flow.imported.data.each { table ->
    708                         table.each { entity ->
    709                                 def invalidFields = 0
    710 
    711                                 // Set the fields for this entity by retrieving values from the params
    712                                 entity.giveFields().each { field ->
    713                                         def fieldName = importerService.getFieldNameInTableEditor( entity, field );
    714 
    715                                         if( params[ fieldName ] == "#invalidterm" ) {
    716                                                 // If the value '#invalidterm' is chosen, the user hasn't fixed anything, so this field is still incorrect
    717                                                 invalidFields++;
    718                                         } else {
    719                                                 if( field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM || field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST ) {
    720                                                         // If this field is an ontologyterm field or a stringlist field, the value has changed, so remove the field from
    721                                                         // the failedCells list
    722                                                         importerService.removeFailedCell( failedCells, entity, field )
    723                                                 }
    724 
    725                                                 // Update the field, regardless of the type of field
    726                                                 entity.setFieldValue(field.name, params[ fieldName ] )
    727                                         }
    728                                 }
    729 
    730                                 // Determine entity class and add a parent
    731                                 entity.parent = study;
    732 
    733                                 // Try to validate the entity now all fields have been set. If it fails, return an error
    734                                 if (!entity.validate() || invalidFields) {
    735                                         numInvalidEntities++;
    736 
    737                                         // Add this field to the list of failed cells, in order to give the user feedback
    738                                         failedCells = addNonValidatingCells( failedCells, entity )
    739 
    740                                         // Also create a full list of errors
    741                                         errors += getHumanReadableErrors( entity );
    742                                 } else {
    743                                         importerService.removeFailedCell( failedCells, entity )
    744                                 }
    745                         } // end of record
    746                 } // end of table
    747 
    748                 flow.imported.numInvalidEntities = numInvalidEntities;
    749                 flow.imported.errors = errors;
    750 
    751                 return true
    752         }
    753        
    754         /**
    755         * Handles assay input
    756         * @param study          Study to update
    757         * @param params         Request parameter map
    758         * @return                       True if everything went OK, false otherwise. An error message is put in flash.error
    759         */
    760    def handleAssays( assay, params, flow ) {
    761            // did the study template change?
    762            if (params.get('template') && assay.template?.name != params.get('template')) {
    763                    // set the template
    764                    assay.template = Template.findByName(params.remove('template'))
    765            }
    766 
    767            // does the study have a template set?
    768            if (assay.template && assay.template instanceof Template) {
    769                    // yes, iterate through template fields
    770                    assay.giveFields().each() {
    771                            // and set their values
    772                            assay.setFieldValue(it.name, params.get(it.escapedName()))
    773                    }
    774            }
    775 
    776            // Save the assay in session
    777            flow.assay = assay;
    778 
    779            return true
    780    }
    781        
    782        
    783         /**
    784          * Checks whether the given study is simple enough to be edited using this controller.
    785          *
    786          * The study is simple enough if the samples, subjects, events and samplingEvents can be
    787          * edited as a flat table. That is:
    788          *              - Every subject belongs to 0 or 1 eventgroup
    789          *              - Every eventgroup belongs to 0 or 1 sample
    790          *              - Every eventgroup has 0 or 1 subjects, 0 or 1 event and 0 or 1 samplingEvents
    791          *              - If a sample belongs to an eventgroup:
    792          *                      - If that eventgroup has a samplingEvent, that same samplingEvent must also be
    793          *                              the sampling event that generated this sample
    794          *                      - If that eventgroup has a subject, that same subject must also be the subject
    795          *                              from whom the sample was taken
    796          *
    797          * @param study         Study to check
    798          * @return                      True if the study can be edited by this controller, false otherwise
    799          */
    800         def checkStudySimplicity( study ) {
    801                 def simplicity = true;
    802 
    803                 if( !study )
    804                         return false
    805 
    806                 if( study.eventGroups ) {
    807                         study.eventGroups.each { eventGroup ->
    808                                 // Check for simplicity of eventgroups: only 0 or 1 subject, 0 or 1 event and 0 or 1 samplingEvent
    809                                 if( eventGroup.subjects?.size() > 1 || eventGroup.events?.size() > 1 || eventGroup.samplingEvents?.size() > 1 ) {
    810                                         flash.message = "One or more eventgroups contain multiple subjects or events."
    811                                         simplicity = false;
    812                                 }
    813 
    814                                 // Check whether this eventgroup only belongs to (max) 1 sample
    815                                 def numSamples = 0;
    816                                 study.samples.each { sample ->
    817                                         // If no id is given for the eventGroup, it has been entered in this wizard, but
    818                                         // not yet saved. In that case, it is always OK
    819                                         if( eventGroup.id && sample.parentEventGroup?.id == eventGroup.id )
    820                                                 numSamples++;
    821                                 }
    822 
    823                                 if( numSamples > 1 ) {
    824                                         flash.message = "One or more eventgroups belong to multiple samples."
    825                                         simplicity = false;
    826                                 }
    827                         }
    828 
    829                         if( !simplicity ) return false;
    830 
    831                         // Check whether subject only belong to zero or one event group
    832                         if( study.subjects ) {
    833                                 study.subjects.each { subject ->
    834                                         def numEventGroups = 0
    835                                         study.eventGroups.each { eventGroup ->
    836                                                 // If no id is given for the subject, it has been entered in this wizard, but
    837                                                 // not yet saved. In that case, it is always OK
    838                                                 if( subject.id && eventGroup.subjects[0]?.id == subject.id )
    839                                                         numEventGroups++
    840                                         }
    841 
    842                                         if( numEventGroups > 1 ) {
    843                                                 flash.message = "One or more subjects belong to multiple eventgroups."
    844                                                 simplicity = false;
    845                                         }
    846                                 }
    847                         }
    848 
    849                         if( !simplicity ) return false;
    850 
    851                         // Check whether the samples that belong to an eventgroup have the right parentObjects
    852                         study.samples.each { sample ->
    853                                 if( sample.parentEventGroup ) {
    854                                         // If no id is given for the subject, it has been entered in this wizard, but
    855                                         // not yet saved. In that case, it is always OK
    856                                         if( sample.parentSubject && sample.parentSubject.id) {
    857                                                 if( !sample.parentEventGroup.subjects || sample.parentEventGroup.subjects[0]?.id != sample.parentSubject.id ) {
    858                                                         flash.message = "The structure of the eventgroups of one or more samples is too complex"
    859                                                         simplicity = false;
    860                                                 }
    861                                         }
    862 
    863                                         // If no id is given for the sampling event, it has been entered in this wizard, but
    864                                         // not yet saved. In that case, it is always OK
    865                                         if( sample.parentEvent && sample.parentEvent.id) {
    866                                                 if( !sample.parentEventGroup.samplingEvents || sample.parentEventGroup.samplingEvents[0]?.id != sample.parentEvent.id ) {
    867                                                         flash.message = "The structure of the eventgroups of one or more samples is too complex"
    868                                                         simplicity = false;
    869                                                 }
    870                                         }
    871                                 }
    872                         }
    873 
    874                         if( !simplicity ) return false;
    875                 }
    876 
    877                 return simplicity;
    878         }
    879 
    880         /**
    881         * Checks an excel workbook whether the given sheetindex and rownumbers are correct
    882         * @param workbook                       Excel workbook to read
    883         * @param sheetIndex             1-based sheet index for the sheet to read (1=first sheet)
    884         * @param headerRow                      1-based row number for the header row (1=first row)
    885         * @param dataMatrixStart        1-based row number for the first data row (1=first row)
    886         * @return                                       True if the sheet index and row numbers are correct.
    887         */
    888    protected boolean excelChecks( def workbook, int sheetIndex, int headerRow, int dataMatrixStart ) {
    889            // Perform some basic checks on the excel file. These checks should be performed by the importerservice
    890            // in a perfect scenario.
    891            if( sheetIndex > workbook.getNumberOfSheets() ) {
    892                    log.error ".simple study wizard Sheet index is too high: " + sheetIndex + " / " + workbook.getNumberOfSheets();
    893                    flash.error = "Your excel sheet contains too few excel sheets. The provided excel sheet has only " + workbook.getNumberOfSheets() + " sheet(s).";
    894                    return false
    895            }
    896 
    897            def sheet = workbook.getSheetAt(sheetIndex - 1);
    898            def firstRowNum = sheet.getFirstRowNum();
    899            def lastRowNum = sheet.getLastRowNum();
    900            def numRows = lastRowNum - firstRowNum + 1;
    901 
    902            if( headerRow > numRows  ) {
    903                    log.error ".simple study wizard Header row number is incorrect: " + headerRow + " / " + numRows;
    904                    flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";
    905                    return false
    906            }
    907 
    908            if( dataMatrixStart > numRows  ) {
    909                    log.error ".simple study wizard Data row number is incorrect: " + dataMatrixStart + " / " + numRows;
    910                    flash.error = "Your excel sheet doesn't contain enough rows (" + numRows + "). Please provide an excel sheet with one header row and data below";
    911                    return false
    912            }
    913 
    914            return true;
    915    }
    916        
    917         /**
    918          * Validates an object and puts human readable errors in validationErrors variable
    919          * @param entity                Entity to validate
    920          * @return                      True iff the entity validates, false otherwise
    921          */
    922         protected boolean validateObject( def entity ) {
    923                 if( !entity.validate() ) {
    924                         flash.validationErrors = getHumanReadableErrors( entity )
    925                         return false;
    926                 }
    927                 return true;
    928         }
    929 
    930         /**
    931          * transform domain class validation errors into a human readable
    932          * linked hash map
    933          * @param object validated domain class
    934          * @return object  linkedHashMap
    935          */
    936         def getHumanReadableErrors(object) {
    937                 def errors = [:]
    938                 object.errors.getAllErrors().each() { error ->
    939                         // error.codes.each() { code -> println code }
    940 
    941                         // generally speaking g.message(...) should work,
    942                         // however it fails in some steps of the wizard
    943                         // (add event, add assay, etc) so g is not always
    944                         // availably. Using our own instance of the
    945                         // validationTagLib instead so it is always
    946                         // available to us
    947                         errors[error.getArguments()[0]] = validationTagLib.message(error: error)
    948                 }
    949 
    950                 return errors
    951         }
    952269}
Note: See TracChangeset for help on using the changeset viewer.