source: trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy @ 529

Last change on this file since 529 was 529, checked in by duh, 12 years ago
  • updated version 0.2.4
  • fixed group table not having a slider
  • Property svn:keywords set to Date Author Rev
File size: 28.2 KB
Line 
1package dbnp.studycapturing
2
3import dbnp.data.*
4
5// Grails convertors is imported in order to create JSON objects
6import grails.converters.*
7
8
9/**
10 * Wizard Controler
11 *
12 * The wizard controller handles the handeling of pages and data flow
13 * through the study capturing wizard.
14 *
15 * @author Jeroen Wesbeek
16 * @since 20100107
17 * @package studycapturing
18 *
19 * Revision information:
20 * $Rev: 529 $
21 * $Author: duh $
22 * $Date: 2010-06-04 11:01:21 +0000 (vr, 04 jun 2010) $
23 */
24class WizardController {
25        /**
26         * index method, redirect to the webflow
27         * @void
28         */
29        def index = {
30                /**
31                 * Do you believe it in your head?
32                 * I can go with the flow
33                 * Don't say it doesn't matter (with the flow) matter anymore
34                 * I can go with the flow (I can go)
35                 * Do you believe it in your head?
36                 */
37                redirect(action: 'pages')
38        }
39
40        /**
41         * WebFlow definition
42         * @see http://grails.org/WebFlow
43         * @void
44         */
45        def pagesFlow = {
46                // start the flow
47                onStart {
48                        // define flow variables
49                        flow.page = 0
50                        flow.pages = [
51                                //[title: 'Templates'],                 // templates
52                                [title: 'Start'],                               // load or create a study
53                                [title: 'Study'],                               // study
54                                [title: 'Subjects'],                    // subjects
55                                [title: 'Events'],                              // events and event grouping
56                                [title: 'Groups'],                              // groups
57                                [title: 'Samples'],                             // samples
58                                [title: 'Confirmation'],                // confirmation page
59                                [title: 'Done']                                 // finish page
60                        ]
61                        success()
62                }
63
64                // render the main wizard page which immediately
65                // triggers the 'next' action (hence, the main
66                // page dynamically renders the study template
67                // and makes the flow jump to the study logic)
68                mainPage {
69                        render(view: "/wizard/index")
70                        onRender {
71                                flow.page = 1
72                                success()
73                        }
74                        on("next").to "start"
75                }
76
77                // create or modify a study
78                start {
79                        render(view: "_start")
80                        onRender {
81                                flow.page = 1
82                                success()
83                        }
84                        on("next") {
85                                // clean the flow scope
86                                flow.remove('study')
87                                flow.remove('subjects')
88                                flow.remove('subjectTemplates')
89                                flow.remove('event')
90                                flow.remove('events')
91                                flow.remove('eventGroups')
92                                flow.remove('eventTemplates')
93                        }.to "study"
94                        on("modify").to "modify"
95                }
96
97                // load a study to modify
98                modify {
99                        render(view: "_modify")
100                        onRender {
101                                flow.page = 1
102                                flash.cancel = true
103                                success()
104                        }
105                        on("cancel") {
106                                flow.study = null
107
108                                success()
109                        }.to "start"
110                        on("next") {
111                                // load study
112                                try {
113                                        flow.study = Study.findByTitle(params.study)
114
115                                        // recreate subjects
116                                        flow.subjects = [:]
117                                        flow.subjectTemplates = [:]
118                                        flow.study.subjects.each() { subject ->
119                                                def subjectIncrement = flow.subjects.size()
120                                                flow.subjects[ subjectIncrement ] = subject
121
122                                                // add subject template?
123                                                if (!flow.subjectTemplates[ subject.template.name ]) {
124                                                        flow.subjectTemplates[ subject.template.name ] = [
125                                                                name: subject.template.name,
126                                                                template: subject.template,
127                                                                subjects: [:]
128                                                        ]
129                                                }
130
131                                                // reference subject in template
132                                                flow.subjectTemplates[ subject.template.name ].subjects[ flow.subjectTemplates[ subject.template.name ].subjects.size() ] = subjectIncrement
133                                        }
134
135                                        // recreate events
136                                        flow.events = []
137                                        flow.eventGroups = []
138                                        flow.eventTemplates     = [:]
139                                        flow.study.events.each() { event ->
140                                                def eventIncrement = flow.events.size()
141                                                flow.events[ eventIncrement ] = event
142
143                                                // add event template?
144                                                if (!flow.eventTemplates[ event.template.name ]) {
145                                                        flow.eventTemplates[ event.template.name ] = [
146                                                                name: event.template.name,
147                                                                template: event.template,
148                                                                events: new ArrayList()
149                                                        ]
150                                                }
151
152                                                // reference event in template
153                                                flow.eventTemplates[ event.template.name ].events[ flow.eventTemplates[ event.template.name ].events.size() ] = eventIncrement
154
155                                                // set dummy event
156                                                flow.event = event
157                                        }
158
159                                        // recreate sample events
160                                        flow.study.samplingEvents.each() { event ->
161                                                def eventIncrement = flow.events.size()
162                                                flow.events[ eventIncrement ] = event
163
164                                                // add event template?
165                                                if (!flow.eventTemplates[ event.template.name ]) {
166                                                        flow.eventTemplates[ event.template.name ] = [
167                                                                name: event.template.name,
168                                                                template: event.template,
169                                                                events: new ArrayList()
170                                                        ]
171                                                }
172
173                                                // reference event in template
174                                                flow.eventTemplates[ event.template.name ].events[ flow.eventTemplates[ event.template.name ].events.size() ] = eventIncrement
175
176                                                // set dummy event
177                                                flow.event = event
178                                        }
179
180                                        // recreate eventGroups
181                                        flow.study.eventGroups.each() { eventGroup ->
182                                                flow.eventGroups[ flow.eventGroups.size() ] = eventGroup
183                                        }
184
185                                        success()
186                                } catch (Exception e) {
187                                        // rollback
188                                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace' ], flash.errors)
189
190                                        error()
191                                }
192                        }.to "study"
193                }
194
195                // render and handle the study page
196                // TODO: make sure both template as well as logic will
197                //       handle Study templates as well!!!
198                study {
199                        render(view: "_study")
200                        onRender {
201                                flow.page = 2
202                                success()
203                        }
204                        on("refresh") {
205                                flash.values = params
206
207                                // handle study data
208                                this.handleStudy(flow, flash, params)
209
210                                // remove errors as we don't want any warnings now
211                                flash.errors = [:]
212
213                                success()
214                        }.to "study"
215                        on("switchTemplate") {
216                                flash.values = params
217
218                                // handle study data
219                                this.handleStudy(flow, flash, params)
220
221                                // remove errors as we don't want any warnings now
222                                flash.errors = [:]
223
224                                success()
225                        }.to "study"
226                        on("previous") {
227                                flash.errors = [:]
228
229                                // handle the study
230                                this.handleStudy(flow, flash, params)
231
232                                // reset errors
233                                flash.errors = [:]
234
235                                success()
236                        }.to "start"
237                        on("next") {
238                                flash.errors = [:]
239
240                                if (this.handleStudy(flow, flash, params)) {
241                                        success()
242                                } else {
243                                        error()
244                                }
245                        }.to "subjects"
246                }
247
248                // render and handle subjects page
249                subjects {
250                        render(view: "_subjects")
251                        onRender {
252                                flow.page = 3
253
254                                if (!flow.subjects) {
255                                        flow.subjects = [:]
256                                        flow.subjectTemplates = [:]
257                                }
258
259                                success()
260                        }
261                        on("refresh") {
262                                flash.values = params
263                                success()
264                        }.to "subjects"
265                        on("add") {
266                                // handle subjects
267                                this.handleSubjects(flow, flash, params)
268
269                                flash.errors = [:]
270                                flash.values = params
271                                def speciesTerm = Term.findByName(params.species);
272                                def subjectTemplateName = params.get('template');
273                                def subjectTemplate = Template.findByName(subjectTemplateName);
274
275                                // add this subject template to the subject template array
276                                if (!flow.subjectTemplates[ subjectTemplateName ]) {
277                                        flow.subjectTemplates[ subjectTemplateName ] = [
278                                                name: subjectTemplateName,
279                                                template: subjectTemplate,
280                                                subjects: [:]
281                                        ]
282                                }
283
284                                // add x subjects of species y
285                                (params.addNumber as int).times {
286                                        def increment = (flow.subjects.size()) ? (flow.subjects.keySet().max() + 1) : 0
287                                        def subject = new Subject(
288                                                name: 'Subject ' + (increment + 1),
289                                                species: speciesTerm,
290                                                template: subjectTemplate
291                                        )
292
293                                        // instantiate a new Subject
294                                        flow.subjects[ increment ] = subject
295
296                                        // and remember the subject id with the template
297                                        def subjectsSize = (flow.subjectTemplates[ subjectTemplateName ].subjects.size()) ? (flow.subjectTemplates[ subjectTemplateName ].subjects.keySet().max() + 1) : 0
298                                        flow.subjectTemplates[ subjectTemplateName ].subjects[ subjectsSize ] = increment
299                                }
300
301                                success()
302                        }.to "subjects"
303                        on("next") {
304                                flash.errors = [:]
305
306                                // check if we have at least one subject
307                                // and check form data
308                                if (flow.subjects.size() < 1) {
309                                        // append error map
310                                        this.appendErrorMap(['subjects': 'You need at least to create one subject for your study'], flash.errors)
311                                        error()
312                                } else if (!this.handleSubjects(flow, flash, params)) {
313                                        error()
314                                } else {
315                                        success()
316                                }
317                        }.to "events"
318                        on("delete") {
319                                // handle subjects
320                                this.handleSubjects(flow, flash, params)
321
322                                flash.errors = [:]
323                                def delete = params.get('do') as int;
324
325                                // remove subject
326                                if (flow.subjects[ delete ] && flow.subjects[ delete ] instanceof Subject) {
327                                        // remove subject from templates
328                                        flow.subjectTemplates.each() { templateName, templateData ->
329                                                templateData.subjects.remove( delete )
330                                        }
331
332                                        // remove subject altogether
333                                        flow.subjects.remove( delete )
334                                }
335                        }.to "subjects"
336                        on("previous") {
337                                flash.errors = [:]
338
339                                // handle form data
340                                if (!this.handleSubjects(flow, flash, params)) {
341                                        error()
342                                } else {
343                                        success()
344                                }
345                        }.to "study"
346                }
347
348                // render events page
349                events {
350                        render(view: "_events")
351                        onRender {
352                                flow.page = 4
353
354                                if (!flow.event) {
355                                        flow.event                      = new Event()
356                                        flow.events                     = []
357                                        flow.eventGroups        = []
358                                        flow.eventGroups[0]     = new EventGroup(name: 'Group 1')       // 1 group by default
359                                        flow.eventTemplates     = [:]
360                                } else if (!flash.values) {
361                                        // set flash.values.templateType based on the event instance
362                                        flash.values = [:]
363                                        flash.values.templateType = (flow.event instanceof Event) ? 'event' : 'sample'
364                                }
365                                success()
366                        }
367                        on("switchTemplate") {
368                                flash.values = params
369
370                                // handle study data
371                                this.handleEvents(flow, flash, params)
372
373                                // remove errors as we don't want any warnings now
374                                flash.errors = [:]
375                        }.to "events"
376                        on("add") {
377                                flash.values                    = params
378                                def eventTemplateName   = (params.get('eventType') == 'event') ? params.get('eventTemplate') : params.get('sampleTemplate')
379                                def eventTemplate               = Template.findByName(eventTemplateName)
380
381                                // handle study data
382                                this.handleEvents(flow, flash, params)
383
384                                // validate event object
385                                if (flow.event.validate()) {
386                                        // add this event template to the event template array
387                                        if (!flow.eventTemplates[ eventTemplateName ]) {
388                                                flow.eventTemplates[ eventTemplateName ] = [
389                                                        name: eventTemplateName,
390                                                        template: eventTemplate,
391                                                        events: []
392                                                ]
393                                        }
394
395                                        // it validated! Duplicate the event object...
396                                        def newEvent    = flow.event
397                                        def increment   = flow.events.size()
398
399                                        // ...store it in the events map in the flow scope...
400                                        flow.events[ increment ] = newEvent
401
402                                        // ...and 'reset' the event object in the flow scope
403                                        flow.event = new Event(template: newEvent.template)
404                                       
405                                        // remember the event id with the template
406                                        def eventSize = flow.eventTemplates[ eventTemplateName ]['events'].size()
407                                        flow.eventTemplates[ eventTemplateName ]['events'][ eventSize ] = increment
408
409                                        success()
410                                } else {
411                                        // it does not validate, show error feedback
412                                        flash.errors = [:]
413                                        this.appendErrors(flow.event, flash.errors)
414                                        error()
415                                }
416                        }.to "events"
417                        on("deleteEvent") {
418                                flash.values = params
419                                def delete = params.get('do') as int;
420
421                                // handle event groupings
422                                this.handleEventGrouping(flow, flash, params)
423
424                                // remove event
425                                if (flow.events[ delete ] && flow.events[ delete ] instanceof Event) {
426                                        flow.events.remove(delete)
427                                }
428
429                                success()
430                        }.to "events"
431                        on("addEventGroup") {
432                                flash.values = params
433                               
434                                // handle study data
435                                this.handleEvents(flow, flash, params)
436
437                                // handle event groupings
438                                this.handleEventGrouping(flow, flash, params)
439
440                                def increment = flow.eventGroups.size()
441                                def groupName = "Group " + (increment + 1)
442
443                                // check if group name exists
444                                def nameExists = true
445                                def u = 0
446
447                                // make sure a unique name is generated
448                                while (nameExists) {
449                                        u++
450                                        def count = 0
451                                       
452                                        flow.eventGroups.each() {
453                                                if (it.name == groupName) {
454                                                        groupName = "Group " + (increment + 1) + "," + u
455                                                } else {
456                                                        count++
457                                                }
458                                        }
459
460                                        nameExists = !(count == flow.eventGroups.size())
461                                }
462
463                                flow.eventGroups[increment] = new EventGroup( name: groupName )
464
465                                success()
466                        }.to "events"
467                        on("deleteEventGroup") {
468                                flash.values = params
469                                def delete = params.get('do') as int;
470
471                                // handle event groupings
472                                this.handleEventGrouping(flow, flash, params)
473
474                                // remove the group with this specific id
475                                if (flow.eventGroups[delete] && flow.eventGroups[delete] instanceof EventGroup) {
476                                        // remove this eventGroup
477                                        flow.eventGroups.remove(delete)
478                                }
479
480                                success()
481                        }.to "events"
482                        on("previous") {
483                                // handle event groupings
484                                this.handleEventGrouping(flow, flash, params)
485                        }.to "subjects"
486                        on("next") {
487                                flash.values = params
488                                flash.errors = [:]
489
490                                // handle study data
491                                if (flow.events.size() < 1) {
492                                        // append error map
493                                        this.appendErrorMap(['events': 'You need at least to create one event for your study'], flash.errors)
494                                        error()                                         
495                                } else if (this.handleEvents(flow, flash, params)) {
496                                        success()
497                                } else {
498                                        error()
499                                }
500                        }.to "groups"
501                }
502
503                // groups page
504                groups {
505                        render(view: "_groups")
506                        onRender {
507                                flow.page = 5
508                                success()
509                        }
510                        on("previous") {
511                                this.handleSubjectGrouping(flow, flash, params)
512                                success()
513                        }.to "events"
514                        on("next") {
515                                this.handleSubjectGrouping(flow, flash, params)
516                                success()
517                        }.to "samples"
518                }
519
520                // samples page
521                samples {
522                        render(view: "_samples")
523                        onRender {
524                                flow.page = 6
525                                flow.bla = "samples"
526
527                                // iterate through subjects
528                                flow.subjects.each() { subject ->
529                                        println subject.value.name
530
531                                        // iterate through events
532                                        flow.events.each() { event ->
533                                                println "bla"
534                                                if (event instanceof SamplingEvent) {
535                                                        //println event.getFieldValue('name')
536                                                        println event.startTime
537                                                        println event.endTime
538                                                }
539
540                                        }
541                                }
542
543                                success()
544                        }
545                        on("previous") {
546                                success()
547                        }.to "groups"
548                        on("next") {
549                                success()
550                        }.to "confirm"
551                }
552
553                // confirmation
554                confirm {
555                        render(view: "_confirmation")
556                        onRender {
557                                flow.page = 7
558                        }
559                        on("toStudy").to "study"
560                        on("toSubjects").to "subjects"
561                        on("toEvents").to "events"
562                        on("toGroups").to "groups"
563                        on("previous").to "samples"
564                        on("next").to "waitForSave"
565                }
566
567                waitForSave {
568                        render(view: "_wait")
569                        onRender {
570                                flow.page = 8
571                        }
572                        on("next").to "save"
573                }
574
575                // store all study data
576                save {
577                        action {
578                                println "saving..."
579                                flash.errors = [:]
580
581                                // persist data to the database
582                                try {
583                                        println ".saving wizard data..."
584
585                                        // add events to study
586                                        println ".add events to study"
587                                        flow.events.each() { event ->
588                                                if (event instanceof SamplingEvent) {
589                                                        flow.study.addToSamplingEvents(event)
590                                                } else {
591                                                        flow.study.addToEvents(event)
592                                                }
593                                        }
594
595                                        // add subjects to study
596                                        println ".add subjects to study"
597                                        flow.subjects.each() { subjectId, subject ->
598                                                flow.study.addToSubjects(subject)
599                                        }
600
601                                        // add eventGroups to study
602                                        println ".add eventGroups to study"
603                                        flow.eventGroups.each() { eventGroup ->
604                                                flow.study.addToEventGroups(eventGroup)
605                                        }
606
607                                        // save study
608                                        println ".saving study"
609                                        if (!flow.study.save(flush:true)) {
610                                                this.appendErrors(flow.study, flash.errors)
611                                                throw new Exception('error saving study')
612                                        }
613                                        println ".saved study "+flow.study+" (id: "+flow.study.id+")"
614
615                                        success()
616                                } catch (Exception e) {
617                                        // rollback
618                                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace' ], flash.errors)
619
620                                        // stacktrace in flash scope
621                                        flash.debug = e.getStackTrace()
622
623                                        error()
624                                }
625                        }
626                        on("error").to "error"
627                        on(Exception).to "error"
628                        on("success").to "done"
629                }
630
631                // error storing data
632                error {
633                        render(view: "_error")
634                        onRender {
635                                flow.page = 7
636                        }
637                        on("next").to "waitForSave"
638                        on("previous").to "samples"
639                }
640
641                // render page three
642                done {
643                        render(view: "_done")
644                        onRender {
645                                flow.page = 8
646                        }
647                        on("previous") {
648                                // TODO
649                        }.to "confirm"
650                }
651        }
652
653        /**
654         * re-usable code for handling study form data in a web flow
655         * @param Map LocalAttributeMap (the flow scope)
656         * @param Map localAttributeMap (the flash scope)
657         * @param Map GrailsParameterMap (the flow parameters = form data)
658         * @returns boolean
659         */
660        def handleStudy(flow, flash, params) {
661                // create study instance if we have none
662                if (!flow.study) flow.study = new Study();
663
664                // create date instance from date string?
665                // @see WizardTagLibrary::dateElement{...}
666                if (params.get('startDate')) {
667                        params.startDate = new Date().parse("d/M/yyyy", params.get('startDate').toString())
668                } else {
669                        params.remove('startDate')
670                }
671
672                // if a template is selected, get template instance
673                def template = params.remove('template')
674                if (template instanceof String && template.size() > 0) {
675                        flow.study.template = Template.findByName(template)
676                } else if (template instanceof Template) {
677                        flow.study.template = template
678                }
679
680                // iterate through fields
681                if (flow.study.template) {
682                        flow.study.giveFields().each() {
683                                flow.study.setFieldValue(it.name, params.get(it.escapedName()))
684                        }
685                }
686
687                // handle Publications and Contacts
688                handlePublications(flow, flash, params)
689                handleContacts(flow, flash, params)
690
691                // validate study
692                if (flow.study.validate()) {
693                        return true
694                } else {
695                        // validation failed, feedback errors
696                        flash.errors = [:]
697                        this.appendErrors(flow.study, flash.errors)
698                        return false
699                }
700        }
701
702        /**
703         * re-usable code for handling publications form data in a web flow
704         * @param Map LocalAttributeMap (the flow scope)
705         * @param Map localAttributeMap (the flash scope)
706         * @param Map GrailsParameterMap (the flow parameters = form data)
707         * @returns boolean
708         */
709        def handlePublications(flow, flash, params) {
710                // create study instance if we have none
711                if (!flow.study) flow.study = new Study();
712                if (!flow.study.publications ) flow.study.publications = [];
713
714                // Check the ids of the pubblications that should be attached
715                // to this study. If they are already attached, keep 'm. If
716                // studies are attached that are not in the selected (i.e. the
717                // user deleted them), remove them
718                def publicationIDs = params.get( 'publication_ids' );
719                if( publicationIDs ) {
720                    // Find the individual IDs and make integers
721                    publicationIDs = publicationIDs.split(',').collect { Integer.parseInt( it, 10 ) };
722
723                    // First remove the publication that are not present in the array
724                    flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
725
726                    // Add those publications not yet present in the database
727                    publicationIDs.each { id ->
728                        if( !flow.study.publications.find { publication -> id == publication.id } ) {
729                            def publication = Publication.get( id );
730                            if( publication ) {
731                                flow.study.addToPublications( publication );
732                            } else {
733                                println( 'Publication with ID ' + id + ' not found in database.' );
734                            }
735                        }
736                    }
737
738                } else {
739                    println( 'No publications selected.')
740                    flow.study.publications.clear();
741                }
742
743        }
744
745        /**
746         * re-usable code for handling contacts form data in a web flow
747         * @param Map LocalAttributeMap (the flow scope)
748         * @param Map localAttributeMap (the flash scope)
749         * @param Map GrailsParameterMap (the flow parameters = form data)
750         * @returns boolean
751         */
752        def handleContacts(flow, flash, params) {
753                // create study instance if we have none
754                if (!flow.study) flow.study = new Study();
755                if (!flow.study.persons ) flow.study.persons = [];
756
757                // Check the ids of the contacts that should be attached
758                // to this study. If they are already attached, keep 'm. If
759                // studies are attached that are not in the selected (i.e. the
760                // user deleted them), remove them
761
762                // Contacts are saved as [person_id]-[role_id]
763                println( params );
764                def contactIDs = params.get( 'contacts_ids' );
765                println( contactIDs );
766                if( contactIDs ) {
767                    // Find the individual IDs and make integers
768                    contactIDs = contactIDs.split(',').collect {
769                        def parts = it.split( '-' );
770                        return [ person: Integer.parseInt( parts[0] ), role: Integer.parseInt( parts[1] ) ];
771                    };
772
773                    // First remove the contacts that are not present in the array
774                    flow.study.persons.removeAll {
775                        studyperson -> !contactIDs.find { ids -> ( ids.person == studyperson.person.id ) && ( ids.role == studyperson.role.id ) }
776                    };
777
778                    // Add those contacts not yet present in the database
779                    contactIDs.each { ids ->
780                        if( !flow.study.persons.find { studyperson -> ( ids.person == studyperson.person.id ) && ( ids.role == studyperson.role.id ) } ) {
781                            def person = Person.get( ids.person );
782                            def role = PersonRole.get( ids.role );
783                            if( person && role ) {
784                                // Find a studyperson object with these parameters
785                                def studyPerson = StudyPerson.findAll().find { studyperson -> studyperson.person.id == person.id && studyperson.role.id == role.id };
786
787                                // If if does not yet exist, save the example
788                                if( !studyPerson ) {
789                                    studyPerson = new StudyPerson(
790                                        person: person,
791                                        role: role
792                                    );
793                                    studyPerson.save( flush: true );
794                                }
795
796                                flow.study.addToPersons( studyPerson );
797                            } else {
798                                println( 'Person ' + ids.person + ' or Role ' + ids.role + ' not found in database.' );
799                            }
800                        }
801                    }
802
803                } else {
804                    println( 'No persons selected.')
805                    flow.study.persons.clear();
806                }
807
808        }
809        /**
810         * re-usable code for handling subject form data in a web flow
811         * @param Map LocalAttributeMap (the flow scope)
812         * @param Map localAttributeMap (the flash scope)
813         * @param Map GrailsParameterMap (the flow parameters = form data)
814         * @returns boolean
815         */
816        def handleSubjects(flow, flash, params) {
817                def names = [:]
818                def errors = false
819                def id = 0
820
821println flow.subjects
822                // iterate through subject templates
823                flow.subjectTemplates.each() { subjectTemplate ->
824                        // iterate through subjects
825                        subjectTemplate.value.subjects.each() { subjectIncrement, subjectId ->
826                                // iterate through fields (= template fields and domain properties)
827                                flow.subjects[ subjectId ].giveFields().each() { subjectField ->
828                                        // set the field
829                                        flow.subjects[ subjectId ].setFieldValue(
830                                                subjectField.name,
831                                                params.get( 'subject_' + subjectId + '_' + subjectField.escapedName() )
832                                        )
833                                }
834
835                                // validate subject
836                                if (!flow.subjects[ subjectId ].validate()) {
837                                        errors = true
838                                        this.appendErrors(flow.subjects[ subjectId ], flash.errors, 'subject_' + subjectId + '_')
839                                }
840                        }
841                }
842
843                return !errors
844        }
845
846        /**
847         * re-usable code for handling event form data in a web flow
848         * @param Map LocalAttributeMap (the flow scope)
849         * @param Map localAttributeMap (the flash scope)
850         * @param Map GrailsParameterMap (the flow parameters = form data)
851         * @returns boolean
852         */
853        def handleEvents(flow, flash, params) {
854                def errors = false
855                def template = null
856
857                // handle the type of event
858                if (params.eventType == 'event') {
859                        flow.event = new Event();
860                        template = params.remove('eventTemplate')
861                } else if (params.eventType == 'sample') {
862                        flow.event = new SamplingEvent();
863                        template = params.remove('sampleTemplate')
864                }
865
866                // if a template is selected, get template instance
867                if (template instanceof String && template.size() > 0) {
868                        params.template = Template.findByName(template)
869                } else if (template instanceof Template) {
870                        params.template = template
871                } else {
872                        params.template = null
873                }
874
875                // set template
876                if (params.template) flow.event.template = params.template
877
878                // update event instance with parameters
879                flow.event.giveFields().each() { eventField ->
880                        flow.event.setFieldValue(eventField.name, params[ eventField.escapedName() ])   
881                }
882
883                // handle event objects
884                flow.eventTemplates.each() { eventTemplate ->
885                        // iterate through events
886                        eventTemplate.getValue().events.each() { eventId ->
887                                // iterate through template fields
888                                flow.events[ eventId ].giveFields().each() { eventField ->
889                                        flow.events[ eventId ].setFieldValue(eventField.name, params.get( 'event_' + eventId + '_' + eventField.escapedName() ) )
890                                }
891
892                                // validate event
893                                if (!flow.events[ eventId ].validate()) {
894                                        errors = true
895                                        this.appendErrors(flow.events[ eventId ], flash.errors, 'event_' + eventId + '_')
896                                }
897                        }
898                }
899
900                // handle event grouping
901                handleEventGrouping(flow, flash, params)
902
903                return !errors
904        }
905
906        /**
907         * re-usable code for handling event grouping in a web flow
908         * @param Map LocalAttributeMap (the flow scope)
909         * @param Map localAttributeMap (the flash scope)
910         * @param Map GrailsParameterMap (the flow parameters = form data)
911         * @returns boolean
912         */
913        def handleEventGrouping(flow, flash, params) {
914                // walk through eventGroups
915                def g = 0
916                flow.eventGroups.each() { eventGroup ->
917                        def e = 0
918
919                        // reset events
920                        eventGroup.events = new HashSet()
921
922                        // iterate through events
923                        flow.events.each() {
924                                if (params.get('event_' + e + '_group_' + g) == 'on') {
925                                        eventGroup.addToEvents(it)
926                                }
927                                e++
928                        }
929                        g++
930                }
931        }
932
933        /**
934         * re-usable code for handling subject grouping in a web flow
935         * @param Map LocalAttributeMap (the flow scope)
936         * @param Map localAttributeMap (the flash scope)
937         * @param Map GrailsParameterMap (the flow parameters = form data)
938         * @returns boolean
939         */
940        def handleSubjectGrouping(flow, flash, params) {
941                // iterate through event groups
942                def g = 0
943                flow.eventGroups.each() { eventGroup ->
944                        // reset subjects
945                        eventGroup.subjects = new HashSet()
946
947                        // iterate through subjects
948                        flow.subjects.each() { subjectId, subject ->
949                                // is this combination set?
950                                if (params.get('subject_' + subjectId + '_group_' + g) != null) {
951                                        eventGroup.addToSubjects(subject)
952                                }
953                        }
954
955                        g++
956                }
957        }
958
959        /**
960         * return the object from a map of objects by searching for a name
961         * @param String name
962         * @param Map map of objects
963         * @return Object
964         */
965        def getObjectByName(name, map) {
966                def result = null
967                map.each() {
968                        if (it.name == name) {
969                                result = it
970                        }
971                }
972
973                return result
974        }
975
976        /**
977         * transform domain class validation errors into a human readable
978         * linked hash map
979         * @param object validated domain class
980         * @returns object  linkedHashMap
981         */
982        def getHumanReadableErrors(object) {
983                def errors = [:]
984                object.errors.getAllErrors().each() {
985                        def message = it.toString()
986
987                        //errors[it.getArguments()[0]] = it.getDefaultMessage()
988                        errors[it.getArguments()[0]] = message.substring(0, message.indexOf(';'))
989                }
990
991                return errors
992        }
993
994        /**
995         * append errors of a particular object to a map
996         * @param object
997         * @param map linkedHashMap
998         * @void
999         */
1000        def appendErrors(object, map) {
1001                this.appendErrorMap(this.getHumanReadableErrors(object), map)
1002        }
1003
1004        def appendErrors(object, map, prepend) {
1005                this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend)
1006        }
1007
1008        /**
1009         * append errors of one map to another map
1010         * @param map linkedHashMap
1011         * @param map linkedHashMap
1012         * @void
1013         */
1014        def appendErrorMap(map, mapToExtend) {
1015                map.each() {key, value ->
1016                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
1017                }
1018        }
1019
1020        def appendErrorMap(map, mapToExtend, prepend) {
1021                map.each() {key, value ->
1022                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
1023                }
1024        }
1025
1026        /**
1027         * Parses a RelTime string and returns a nice human readable string
1028         *
1029         * @returns Human Readable string or a HTTP response code 400 on error
1030         */
1031        def ajaxParseRelTime = {
1032                if (params.reltime == null) {
1033                        response.status = 400;
1034                        render('reltime parameter is expected');
1035                }
1036
1037                try {
1038                        def reltime = RelTime.parseRelTime(params.reltime);
1039                        render reltime.toPrettyString();
1040                } catch (IllegalArgumentException e) {
1041                        response.status = 400;
1042                        render(e.getMessage());
1043                }
1044        }
1045}
Note: See TracBrowser for help on using the repository browser.