source: trunk/grails-app/controllers/dbnp/importer/ImporterController.groovy @ 1658

Last change on this file since 1658 was 1658, checked in by t.w.abma@…, 11 years ago
  • importer wizard webtest working
  • native file input HTML element didn't work inside AjaxFlow, so used hidden importfile variable
  • added check for development or test environment in configuration file
  • added webtestfiles folder to web-apps containing Excel files to test
  • Property svn:keywords set to Rev Author Date
File size: 23.3 KB
Line 
1package dbnp.importer
2
3import dbnp.studycapturing.*
4import org.dbnp.gdt.*
5import grails.converters.JSON
6import org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib
7import grails.plugins.springsecurity.Secured
8import org.codehaus.groovy.grails.commons.ConfigurationHolder
9import grails.util.GrailsUtil
10
11
12/**
13 * Wizard Controller
14 *
15 * @author Jeroen Wesbeek
16 * @since 20101206
17 *
18 * Revision information:
19 * $Rev: 1658 $
20 * $Author: t.w.abma@umcutrecht.nl $
21 * $Date: 2011-03-22 15:33:49 +0000 (di, 22 mrt 2011) $
22 */
23@Secured(['IS_AUTHENTICATED_REMEMBERED'])
24class ImporterController {
25        // the pluginManager is used to check if the Grom
26        // plugin is available so we can 'Grom' development
27        // notifications to the unified notifications daemon
28        // (see http://www.grails.org/plugin/grom)
29        def pluginManager
30        def authenticationService
31        def fileService
32        def importerService
33        def validationTagLib = new ValidationTagLib()
34        def gdtService
35
36        /**
37         * index method, redirect to the webflow
38         * @void
39         */
40        def index = {
41                // Grom a development message
42                if (pluginManager.getGrailsPlugin('grom')) "redirecting into the webflow".grom()
43
44                /**
45                 * Do you believe it in your head?
46                 * I can go with the flow
47                 * Don't say it doesn't matter (with the flow) matter anymore
48                 * I can go with the flow (I can go)
49                 * Do you believe it in your head?
50                 */
51                redirect(action: 'pages')
52        }
53
54        /**
55         * WebFlow definition
56         * @void
57         */
58        def pagesFlow = {
59                // start the flow
60                onStart {
61                        // Grom a development message
62                        if (pluginManager.getGrailsPlugin('grom')) "entering the WebFlow".grom()
63
64                        // define variables in the flow scope which is availabe
65                        // throughout the complete webflow also have a look at
66                        // the Flow Scopes section on http://www.grails.org/WebFlow
67                        //
68                        // The following flow scope variables are used to generate
69                        // wizard tabs. Also see common/_tabs.gsp for more information
70                        flow.page = 0
71                        flow.pages = [
72                                [title: 'Import file'],
73                                [title: 'Assign properties'],
74                                [title: 'Check imported data'],
75                                //[title: 'Imported'],
76                                [title: 'Done']
77                        ]
78                        flow.cancel = true;
79                        flow.quickSave = true;
80
81                        success()
82                }
83
84                // render the main wizard page which immediately
85                // triggers the 'next' action (hence, the main
86                // page dynamically renders the study template
87                // and makes the flow jump to the study logic)
88                mainPage {
89                        render(view: "/importer/index")
90                        onRender {
91                                // Grom a development message
92                                if (pluginManager.getGrailsPlugin('grom')) "rendering the main Ajaxflow page (index.gsp)".grom()
93
94                                // let the view know we're in page 1
95                                flow.page = 1
96                                success()
97                        }
98                        on("next").to "pageOne"
99                }
100
101                // File import and entitie template selection page
102                pageOne {
103                        render(view: "_page_one")
104                        onRender {
105                                log.info ".entering import wizard"
106                                // Grom a development message
107                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_one.gsp".grom()
108
109                                flow.page = 1
110                                flow.studies = Study.findAllWhere(owner: authenticationService.getLoggedInUser())
111                                flow.importer_fuzzymatching = "false"
112
113                                success()
114                        }
115
116                        on("refresh") {
117
118                                if (params.entity) {
119                                        flash.importer_datatemplates = Template.findAllByEntity(gdtService.getInstanceByEntity(params.entity.decodeURL()))
120                                }
121
122                                flash.importer_params = params
123
124                                // If the file already exists an "existing*" string is added, but we don't
125                                // want that after a refresh of the first step in the import wizard, so remove
126                                // that string
127                                flash.importer_params.importfile = params.importfile.replace('existing*', '')
128                //flash.importer_params.importfile = new XmlSlurper().parseText(flash.importer_params.importfile[flash.importer_params.importfile.indexOf('<pre')..-1]).toString()
129
130                                success()
131                        }.to "pageOne"
132
133                        on("next") {
134                                flash.wizardErrors = [:]
135
136                                flash.importer_params = params
137                                flash.importer_params.importfile = params.importfile.replace('existing*', '')               
138                //flash.importer_params.importfile = new XmlSlurper().parseText(flash.importer_params.importfile[flash.importer_params.importfile.indexOf('<pre')..-1]).toString()
139
140                                if (params.entity) {
141                                        flash.importer_datatemplates = Template.findAllByEntity(gdtService.getInstanceByEntity(params.entity.decodeURL()))
142                                        def importer_entity_type = gdtService.decryptEntity(params.entity.decodeURL()).toString().split(/\./)
143                                        flow.importer_entity_type = importer_entity_type[importer_entity_type.size()-1]
144                                }
145
146                                // Study selected?
147                                flow.importer_study = (params.study) ? Study.get(params.study.id.toInteger()) : null
148
149                                // Trying to import data into an existing study?
150                                if (flow.importer_study)
151                                        if (flow.importer_study.canWrite(authenticationService.getLoggedInUser()))
152                                                fileImportPage(flow, flash, params) ? success() : error()
153                                        else {
154                                                log.error ".importer wizard wrong permissions"
155                                                this.appendErrorMap(['error': "You don't have the right permissions"], flash.wizardErrors)
156                                                error()
157                                        }
158                                else {
159                                        fileImportPage(flow, flash, params) ? success() : error()
160                                }
161
162                                // put your bussiness logic (if applicable) in here
163                        }.to "pageTwo"
164                }
165
166                // Property to column assignment page
167                pageTwo {
168                        render(view: "_page_two")
169                        onRender {
170                                log.info ".import wizard properties page"
171
172                                def template = Template.get(flow.importer_template_id)
173
174                                // Grom a development message
175                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial: pages/_page_two.gsp".grom()
176
177                                flow.importer_importmappings = ImportMapping.findAllByTemplate(template)
178
179                                flow.page = 2
180                                success()
181                        }
182                        on("refresh") {
183                                def template = Template.get(flow.importer_template_id)
184                                flow.importer_importmappings = ImportMapping.findAllByTemplate(template)
185
186                                // a name was given to the current property mapping, try to store it
187                                if (params.mappingname) {
188                                        flash.importer_columnproperty = params.columnproperty
189                                        propertiesSaveImportMappingPage(flow, flash, params)
190                                } else // trying to load an existing import mapping
191                                if (params.importmapping_id) {
192                                        propertiesLoadImportMappingPage(flow, flash, params)
193                                }
194
195                                if (params.fuzzymatching == "true")
196                                        flow.importer_fuzzymatching = "true" else
197                                        flow.importer_fuzzymatching = "false"
198
199                                success()
200                        }.to "pageTwo"
201
202                        on("next") {
203                                flow.importer_fuzzymatching = "false"
204                                if (propertiesPage(flow, flash, params)) {
205                                        success()
206                                } else {
207                                        log.error ".import wizard, properties are set wrong"
208                                        error()
209                                }
210                        }.to "pageThree"
211                        on("previous").to "pageOne"
212                }
213
214                // Mapping page
215                pageThree {
216                        render(view: "_page_three")
217                        onRender {
218                                log.info ".import wizard mapping page"
219                                // Grom a development message
220                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_three.gsp".grom()
221
222                                flow.page = 3
223                                success()
224                        }
225                        on("refresh") {
226                                success()
227                        }.to "pageThree"
228                        on("next") {
229                                if (mappingsPage(flow, flash, params)) {
230                                        flow.page = 4
231                                        success()
232                                } else {
233                                        log.error ".import wizard mapping error, could not validate all entities"
234                                        error()
235                                }
236                        }.to "save"
237                        on("previous").to "pageTwo"
238                }
239
240                // Imported data overview page
241                pageFour {
242                        render(view: "_page_four")
243                        onRender {
244                                // Grom a development message
245                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_page_four.gsp".grom()
246
247                                flow.page = 4
248                                success()
249                        }
250                        on("next") {
251                                if (importedPage(flow, params)) {
252                                        flow.page = 4
253                                        success()
254                                } else {
255                                        log.error ".import wizard imported error, something went wrong showing the imported entities"
256                                        error()
257                                }
258                        }.to "save"
259                        on("previous").to "pageThree"
260                }
261
262                // Save the imported data
263                save {
264                        action {
265                                // here you can validate and save the
266                                // instances you have created in the
267                                // ajax flow.
268                                // Grom a development message
269                                if (pluginManager.getGrailsPlugin('grom')) ".persisting instances to the database...".grom()
270
271                                // Always delete the uploaded file in the save step to be sure it doesn't reside there anymore
272                                if (GrailsUtil.environment != "test") fileService.delete(flow.importer_importedfile)
273
274                                // Save all entities
275                                if (saveEntities(flow, params)) {
276                                        success()
277                                } else {
278                                        log.error ".import wizard, could not save entities:\n"
279                                        flow.page = 4
280                                        error()
281                                }
282                        }
283                        on("error").to "error"
284                        on(Exception).to "error"
285                        on("success").to "finalPage"
286                }
287
288                // render errors
289                error {
290                        render(view: "_error")
291                        onRender {
292                                // Grom a development message
293                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_error.gsp".grom()
294
295                                // set page to 4 so that the navigation
296                                // works (it is disabled on the final page)
297                                flow.page = 4
298                        }
299                        on("next").to "save"
300                        on("previous").to "pageFour"
301                }
302
303                // last wizard page
304                finalPage {
305                        render(view: "_final_page")
306                        onRender {
307                                // Grom a development message
308                                if (pluginManager.getGrailsPlugin('grom')) ".rendering the partial pages/_final_page.gsp".grom()
309                                success()
310                        }
311                        onEnd {
312                                // clean flow scope
313                                flow.clear()
314                        }
315                }
316        }
317
318        def propertiesManager = {
319                render(view: "common/_propertiesManager")
320        }
321
322        /**
323         * Return templates which belong to a certain entity type
324         *
325         * @param entity entity name string (Sample, Subject, Study et cetera)
326         * @return JSON object containing the found templates
327         */
328        def ajaxGetTemplatesByEntity = {
329                // fetch all templates for a specific entity
330                def templates = Template.findAllByEntity(gdtService.getInstanceByEntity(params.entity.decodeURL()))
331
332                // set output header to json
333                response.contentType = 'application/json'
334
335                // render as JSON
336                render templates as JSON
337        }
338
339        /**
340         * Handle the file import page.
341         *
342         * @param Map LocalAttributeMap (the flow scope)
343         * @param Map GrailsParameterMap (the flow parameters = form data)
344         * @returns boolean true if correctly validated, otherwise false
345         */
346        boolean fileImportPage(flow, flash, params) {       
347                def importedfile = fileService.get(params['importfile'])
348                flow.importer_importedfile = params['importfile']
349       
350        if (importedfile.exists()) {
351                        try {
352                                session.importer_workbook = importerService.getWorkbook(new FileInputStream(importedfile))
353                        } catch (Exception e) {
354                                log.error ".importer wizard could not load file: " + e
355                                this.appendErrorMap(['error': "Wrong file (format), the importer requires an Excel file as input"], flash.wizardErrors)
356                                return false
357                        }
358                }
359
360                if (params.entity && params.template_id) {
361
362                        try {
363                                session.importer_workbook = importerService.getWorkbook(new FileInputStream(importedfile))
364                        } catch (Exception e) {
365                                log.error ".importer wizard could not load file: " + e
366                                this.appendErrorMap(['error': "Excel file required as input"], flash.wizardErrors)
367                                return false
368                        }
369
370                        def selectedentities = []
371
372                        def entityName = gdtService.decryptEntity(params.entity.decodeURL())
373                        def entityClass = gdtService.getInstanceByEntityName(entityName)
374
375                        // Initialize some session variables
376                        //flow.importer_workbook = wb // workbook object must be serialized for this to work
377
378                        flow.importer_template_id = params.template_id
379                        flow.importer_sheetindex = params.sheetindex.toInteger() - 1 // 0 == first sheet
380                        flow.importer_datamatrix_start = params.datamatrix_start.toInteger() - 1 // 0 == first row
381                        flow.importer_headerrow = params.headerrow.toInteger()
382                        flow.importer_entityclass = entityClass
383                        flow.importer_entity = gdtService.cachedEntities.find { it.entity == entityName }
384
385                        // Get the header from the Excel file using the arguments given in the first step of the wizard
386                        flow.importer_header = importerService.getHeader(session.importer_workbook,
387                                flow.importer_sheetindex,
388                                flow.importer_headerrow,
389                                flow.importer_datamatrix_start,
390                                entityClass)
391
392                        session.importer_datamatrix = importerService.getDatamatrix(
393                                session.importer_workbook, flow.importer_header,
394                                flow.importer_sheetindex,
395                                flow.importer_datamatrix_start,
396                                5)
397
398                        flow.importer_templates = Template.get(flow.importer_template_id)
399                        flow.importer_allfieldtypes = "true"
400
401                        return true
402                }
403
404
405                log.error ".importer wizard not all fields are filled in"
406                this.appendErrorMap(['error': "Not all fields are filled in, please fill in or select all fields"], flash.wizardErrors)
407                return false
408        }
409
410        /**
411         * Load an existing import mapping
412         *
413         * @param Map LocalAttributeMap (the flow scope)
414         * @param Map GrailsParameterMap (the flow parameters = form data)
415         * @returns boolean true if correctly validated, otherwise false
416         */
417        boolean propertiesLoadImportMappingPage(flow, flash, params) {
418                def im = ImportMapping.get(params.importmapping_id.toInteger())
419                im.refresh()
420
421                im.mappingcolumns.each { mappingcolumn ->
422                        //def mc = new MappingColumn()
423                        //mc.properties = mappingcolumn.properties
424
425                        flow.importer_header[mappingcolumn.index.toInteger()] = mappingcolumn
426                }
427        }
428
429        /**
430         * Save the properties as an import mapping.
431         *
432         * @param Map LocalAttributeMap (the flow scope)
433         * @param Map GrailsParameterMap (the flow parameters = form data)
434         * @returns boolean true if correctly validated, otherwise false
435         */
436        boolean propertiesSaveImportMappingPage(flow, flash, params) {
437                flash.wizardErrors = [:]
438                def isPreferredIdentifier = false
439
440                // Find actual Template object from the chosen template name
441                def template = Template.get(flow.importer_template_id)
442
443                // Create new ImportMapping instance and persist it
444                def im = new ImportMapping(name: params.mappingname, entity: flow.importer_entityclass, template: template).save()
445
446                params.columnproperty.index.each { columnindex, property ->
447                        // Create an actual class instance of the selected entity with the selected template
448                        // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities                     
449                        //def entityClass = gdtService.getInstanceByEntityName(flow.importer_header[columnindex.toInteger()].entity.getName())
450                        def entityObj = flow.importer_entityclass.newInstance(template: template)
451
452                        def dontimport = (property == "dontimport") ? true : false
453
454                        // Loop through all fields and find the preferred identifier
455                        entityObj.giveFields().each {
456                                isPreferredIdentifier = (it.preferredIdentifier && (it.name == property)) ? true : false
457                        }
458
459                        // Create new MappingColumn instance
460                        def mc = new MappingColumn(importmapping: im,
461                                name: flow.importer_header[columnindex.toInteger()].name,
462                                property: property,
463                                index: columnindex,
464                                entityclass: flow.importer_entityclass,
465                                templatefieldtype: entityObj.giveFieldType(property),
466                                dontimport: dontimport,
467                                identifier: isPreferredIdentifier)
468
469                        // Save mappingcolumn
470                        if (mc.validate()) {
471                                im.addToMappingcolumns(mc)
472                        }
473                        else {
474                                mc.errors.allErrors.each {
475                                        println it
476                                }
477                        }
478
479                        // Save importmapping
480                        if (im.validate()) {
481                                try {
482                                        im.save(flush: true)
483                                } catch (Exception e) {
484                                        //getNextException
485                                        log.error "importer wizard save importmapping error: " + e
486                                }
487                        }
488                        else {
489                                im.errors.allErrors.each {
490                                        println it
491                                }
492                        }
493
494                }
495        }
496
497        /**
498         * Handle the property mapping page.
499         *
500         * @param Map LocalAttributeMap (the flow scope)
501         * @param Map GrailsParameterMap (the flow parameters = form data)
502         * @returns boolean true if correctly validated, otherwise false
503         */
504        boolean propertiesPage(flow, flash, params) {
505                flash.wizardErrors = [:]
506
507                // Find actual Template object from the chosen template name
508                def template = Template.get(flow.importer_template_id)
509
510                params.columnproperty.index.each { columnindex, property ->
511                        // Create an actual class instance of the selected entity with the selected template
512                        // This should be inside the closure because in some cases in the advanced importer, the fields can have different target entities
513                        def entityClass = Class.forName(flow.importer_header[columnindex.toInteger()].entityclass.getName(), true, this.getClass().getClassLoader())
514                        def entityObj = entityClass.newInstance(template: template)
515
516                        // Store the selected property for this column into the column map for the ImporterService
517                        flow.importer_header[columnindex.toInteger()].property = property
518
519                        // Look up the template field type of the target TemplateField and store it also in the map
520                        flow.importer_header[columnindex.toInteger()].templatefieldtype = entityObj.giveFieldType(property)
521
522                        // Is a "Don't import" property assigned to the column?
523                        flow.importer_header[columnindex.toInteger()].dontimport = (property == "dontimport") ? true : false
524
525                        //if it's an identifier set the mapping column true or false
526                        entityObj.giveFields().each {
527                                (it.preferredIdentifier && (it.name == property)) ? flow.importer_header[columnindex.toInteger()].identifier = true : false
528                        }
529                }
530
531                // Import the workbook and store the table with entity records and store the failed cells
532                def (table, failedcells) = importerService.importData(flow.importer_template_id,
533                        session.importer_workbook,
534                        flow.importer_sheetindex,
535                        flow.importer_datamatrix_start,
536                        flow.importer_header)
537
538                flow.importer_importeddata = table
539
540                // loop through all entities to validate them and add them to wizardErrors flash when invalid
541                /*table.each { record ->
542                                        record.each { entity ->
543                                                if (!entity.validate()) {
544                                                this.appendErrors(entity, flash.wizardErrors, 'entity_' + entity.getIdentifier() + '_')
545                                                }
546                                        }
547                                }*/
548
549                flow.importer_failedcells = failedcells
550
551                return true
552        }
553
554        /**
555         * Handle the mapping page.
556         *
557         * @param Map LocalAttributeMap (the flow scope)
558         * @param Map GrailsParameterMap (the flow parameters = form data)
559         * @returns boolean true if correctly validated, otherwise false
560         */
561        boolean mappingsPage(flow, flash, params) {
562                flash.wizardErrors = [:]
563                flow.importer_invalidentities = 0
564
565                flow.importer_importeddata.each { table ->
566                        table.each { entity ->
567                                def invalidfields = 0
568
569                                // Set the fields for this entity by retrieving values from the params
570                                entity.giveFields().each { field ->
571
572                                        // field is a date field, try to set it with the value, if someone enters a non-date value it throws
573                                        // an error, this should be caught to prevent a complete breakdown
574                                        if (field.type == org.dbnp.gdt.TemplateFieldType.DATE) {
575                                                try {
576                                                        entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
577                                                } catch (Exception e) {
578                                                        log.error ".importer wizard could not set date field with value: " +
579                                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()]
580                                                }
581                                        } else
582
583                                        // field of type ontology and value "#invalidterm"?
584                                        if (field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM &&
585                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] == "#invalidterm"
586                                        ) {
587                                                invalidfields++
588                                        } else
589                                        if (field.type == org.dbnp.gdt.TemplateFieldType.ONTOLOGYTERM &&
590                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] != "#invalidterm") {
591                                                if (entity) removeFailedCell(flow.importer_failedcells, entity, field)
592                                                entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
593                                        }
594                                        else
595
596                                        if (field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST &&
597                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] != "#invalidterm") {
598                                                if (entity) removeFailedCell(flow.importer_failedcells, entity, field)
599                                                entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
600                                        } else
601                                        if (field.type == org.dbnp.gdt.TemplateFieldType.STRINGLIST &&
602                                                params["entity_" + entity.getIdentifier() + "_" + field.escapedName()] == "#invalidterm"
603                                        ) {
604                                                invalidfields++
605                                        } else
606
607                                                entity.setFieldValue(field.toString(), params["entity_" + entity.getIdentifier() + "_" + field.escapedName()])
608                                }
609
610                                // Determine entity class and add a parent (defined as Study in first step of wizard)
611                                switch (entity.getClass()) {
612                                        case [Subject, Sample, Event]: entity.parent = flow.importer_study
613                                }
614
615                                // Try to validate the entity now all fields have been set
616                                if (!entity.validate() || invalidfields) {
617                                        flow.importer_invalidentities++
618
619                                        // add errors to map
620                                        this.appendErrors(entity, flash.wizardErrors, "entity_" + entity.getIdentifier() + "_")
621
622                                        entity.errors.getAllErrors().each() {
623                                                log.error ".import wizard imported validation error:" + it
624                                        }
625                                } else {
626                                        //removeFailedCell(flow.importer_failedcells, entity)
627                                } // end else if
628
629                        } // end of record
630                } // end of table
631
632                return (flow.importer_invalidentities == 0) ? true : false
633        } // end of method
634
635        /**
636         * @param failedcell failed ontology cells
637         * @param entity entity to remove from the failedcells list
638         */
639        def removeFailedCell(failedcells, entity, field) {
640                // Valid entity, remove it from failedcells
641                def entityidfield = "entity_" + entity.getIdentifier() + "_" + field.name.toLowerCase()
642
643                failedcells.each { record ->
644                        def tempimportcells = []
645
646
647                        record.importcells.each { cell ->
648                                // remove the cell from the failed cells session
649                                if (cell.entityidentifier != entityidfield) {
650                                        //record.removeFromImportcells(cell)
651                                        tempimportcells.add(cell)
652                                }
653                        }
654
655                        record.importcells = tempimportcells
656                        // } // end of importcells
657                } // end of failedcells
658        }
659
660        /**
661         * Handle the imported entities page.
662         *
663         * @param Map LocalAttributeMap (the flow scope)
664         * @param Map GrailsParameterMap (the flow parameters = form data)
665         * @returns boolean true if correctly validated, otherwise false
666         */
667        boolean importedPage(flow, params) {
668                return true
669        }
670
671        boolean saveEntities(flow, params) {
672                //def (validatedSuccesfully, updatedEntities, failedToPersist) =
673                try {
674                        importerService.saveDatamatrix(flow.importer_study, flow.importer_entity_type, flow.importer_importeddata, authenticationService, log)
675                } catch (Exception e) {
676                        log.error ".import wizard saveEntities error\n" + e.dump()
677                        return false
678                }
679
680                //flow.importer_validatedsuccesfully = validatedSuccesfully
681                //flow.importer_failedtopersist = failedToPersist
682                //flow.imported_updatedentities = updatedEntities
683                //flow.importer_totalrows = flow.importer_importeddata.size
684                //flow.importer_referer = ""
685
686                return true
687        }
688
689        /**
690         * append errors of a particular object to a map
691         * @param object
692         * @param map linkedHashMap
693         * @void
694         */
695        def appendErrors(object, map) {
696                this.appendErrorMap(getHumanReadableErrors(object), map)
697        }
698
699        def appendErrors(object, map, prepend) {
700                this.appendErrorMap(getHumanReadableErrors(object), map, prepend)
701        }
702
703        /**
704         * append errors of one map to another map
705         * @param map linkedHashMap
706         * @param map linkedHashMap
707         * @void
708         */
709        def appendErrorMap(map, mapToExtend) {
710                map.each() {key, value ->
711                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
712                }
713        }
714
715        def appendErrorMap(map, mapToExtend, prepend) {
716                map.each() {key, value ->
717                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
718                }
719        }
720
721        /**
722         * transform domain class validation errors into a human readable
723         * linked hash map
724         * @param object validated domain class
725         * @return object  linkedHashMap
726         */
727        def getHumanReadableErrors(object) {
728                def errors = [:]
729                object.errors.getAllErrors().each() { error ->
730                        // error.codes.each() { code -> println code }           
731
732                        // generally speaking g.message(...) should work,
733                        // however it fails in some steps of the wizard
734                        // (add event, add assay, etc) so g is not always
735                        // availably. Using our own instance of the
736                        // validationTagLib instead so it is always
737                        // available to us
738                        errors[error.getArguments()[0]] = validationTagLib.message(error: error)
739                }
740
741                return errors
742        }
743
744}
Note: See TracBrowser for help on using the repository browser.