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

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