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

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