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

Last change on this file since 527 was 527, checked in by roberth, 13 years ago

Adding of contacts is made possible in the study creation wizard.

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