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

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