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

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