source: trunk/grails-app/controllers/dbnp/studycapturing/StudyWizardController.groovy @ 1640

Last change on this file since 1640 was 1640, checked in by work@…, 10 years ago
  • added simple study support (study page)
  • Property svn:keywords set to Rev Author Date
File size: 53.7 KB
Line 
1package dbnp.studycapturing
2
3import grails.plugins.springsecurity.Secured
4
5import dbnp.authentication.SecUser
6import org.codehaus.groovy.grails.plugins.web.taglib.ValidationTagLib
7import org.dbnp.gdt.*
8
9/**
10 * ajaxflow Controller
11 *
12 * @author      Jeroen Wesbeek
13 * @since       20101220
14 *
15 * Revision information:
16 * $Rev: 1640 $
17 * $Author: work@osx.eu $
18 * $Date: 2011-03-17 14:16:24 +0000 (do, 17 mrt 2011) $
19 */
20@Secured(['IS_AUTHENTICATED_REMEMBERED'])
21class StudyWizardController {
22        def pluginManager
23        def authenticationService
24        def validationTagLib = new ValidationTagLib()
25
26        /**
27         * index method, redirect to the webflow
28         * @void
29         */
30        def index = {
31                // Grom a development message
32                if (pluginManager.getGrailsPlugin('grom')) "redirecting into the webflow".grom()
33
34                def jump = [:]
35
36                // allow quickjumps to:
37                //      edit a study    : /wizard?jump=edit&id=1
38                //      create a study  : /wizard?jump=create
39                if (params.get('jump')) {
40                        switch (params.get('jump')) {
41                                case 'create':
42                                        jump = [
43                                            action: 'create'
44                                        ]
45                                        break
46                                case 'edit':
47                                        jump = [
48                                            action      : 'edit',
49                                                id              : params.get('id')
50                                        ]
51                                        break
52                                case 'simpleedit':
53                                        jump = [
54                                            action      : 'simpleedit',
55                                                id              : params.get('id')
56                                        ]
57                                        break
58                                default:
59                                        break
60                        }
61                }
62
63                // store in session
64                session.jump = jump
65
66                /**
67                 * Do you believe it in your head?
68                 * I can go with the flow
69                 * Don't say it doesn't matter (with the flow) matter anymore
70                 * I can go with the flow (I can go)
71                 * Do you believe it in your head?
72                 */
73                redirect(action: 'pages')
74        }
75
76        /**
77         * WebFlow definition
78         * @void
79         */
80        def pagesFlow = {
81                // start the flow
82                onStart {
83                        // Grom a development message
84                        if (pluginManager.getGrailsPlugin('grom')) "entering the WebFlow".grom()
85
86                        // define variables in the flow scope which is availabe
87                        // throughout the complete webflow also have a look at
88                        // the Flow Scopes section on http://www.grails.org/WebFlow
89                        //
90                        // The following flow scope variables are used to generate
91                        // wizard tabs. Also see common/_tabs.gsp for more information
92                        // define flow variables
93                        flow.page = 0
94
95                        if (session.jump && session.jump?.action == 'simpleedit') {
96                                flow.pages = [
97                                    [title: 'Start'],
98                                        [title: 'Done']
99                                ]
100                        } else {
101                                flow.pages = [
102                                        //[title: 'Templates'],                 // templates
103                                        [title: 'Start'],                               // load or create a study
104                                        [title: 'Subjects'],                    // subjects
105                                        [title: 'Events'],                              // events and event grouping
106                                        //[title: 'Event Groups'],              // groups
107                                        [title: 'Samples'],                             // samples
108                                        [title: 'Assays'],                              // assays
109                                        //[title: 'Assay Groups'],              // assays
110                                        [title: 'Confirmation'],                // confirmation page
111                                        [title: 'Done']                                 // finish page
112                                ]
113                        }
114                        flow.jump = session.jump
115
116                        success()
117                }
118
119                // render the main wizard page which immediately
120                // triggers the 'next' action (hence, the main
121                // page dynamically renders the study template
122                // and makes the flow jump to the study logic)
123                mainPage {
124                        render(view: "/studyWizard/index")
125                        onRender {
126                                // Grom a development message
127                                if (pluginManager.getGrailsPlugin('grom')) "rendering the main Ajaxflow page (index.gsp)".grom()
128
129                                // let the view know we're in page 1
130                                flow.page = 1
131                                success()
132                        }
133                        on("next").to "handleJump"
134                }
135
136                // handle the jump parameter
137                //
138                // I came to get down [2x]
139                // So get out your seats and jump around
140                // Jump around [3x]
141                // Jump up Jump up and get down
142                // Jump [18x]
143                handleJump {
144                        action {
145                                // Grom a development message
146                                if (pluginManager.getGrailsPlugin('grom')) "entering handleJump".grom()
147
148                                if (flow.jump && flow.jump.action =~ 'edit') {
149                                        if (flow.jump.id) {
150                                                // load study
151                                                if (this.loadStudy(flow, flash, [studyid:flow.jump.id],authenticationService.getLoggedInUser())) {
152                                                        toStudyPage()
153                                                } else {
154                                                        toStartPage()
155                                                }
156                                        } else {
157                                                toModifyPage()
158                                        }
159                                } else if (flow.jump && flow.jump.action == 'create') {
160                                        if (!flow.study) flow.study = new Study()
161                                        toStudyPage()
162                                } else {
163                                        toStartPage()
164                                }
165                        }
166                        on("toStartPage").to "start"
167                        on("toStudyPage").to "study"
168                        on("toModifyPage").to "modify"
169                }
170
171                // create or modify a study
172                start {
173                        render(view: "_start")
174                        onRender {
175                                // Grom a development message
176                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_start.gsp".grom()
177
178                                flow.page = 1
179                                success()
180                        }
181                        on("next") {
182                                // clean the flow scope
183                                flow.remove('study')
184
185                                // create a new study instance
186                                if (!flow.study) flow.study = new Study()
187
188                                // set 'quicksave' variable to false
189                                flow.quickSave = false
190                        }.to "study"
191                        on("modify").to "modify"
192                        on("import").to "redirectToImport"
193                }
194
195                // redirect to the import wizard
196                redirectToImport {
197                        render(view: "_redirect")
198                        onRender {
199                                // Grom a development message
200                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_redirect.gsp".grom()
201
202                                flash.uri = "/importer/index"
203                        }
204                        on("next").to "start"
205                }
206
207                // load a study to modify
208                modify {
209                        render(view: "_modify")
210                        onRender {
211                                // Grom a development message
212                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_modify.gsp".grom()
213
214                                flow.page = 1
215                                flash.showCancel = true
216                                success()
217                        }
218                        on("cancel") {
219                                flow.remove('study')
220
221                                success()
222                        }.to "start"
223                        on("next") {
224                                // load study
225                                if (this.loadStudy(flow, flash, params, authenticationService.getLoggedInUser())) {
226                                        success()
227                                } else {
228                                        error()
229                                }
230                        }.to "study"
231                }
232
233                // render and handle the study page
234                study {
235                        render(view: "_study")
236                        onRender {
237                                // Grom a development message
238                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_study.gsp".grom()
239
240                                flow.page = 1
241
242                                // since this controller was refactored it's technically
243                                // safe to enable quicksave throughout the application.
244                                // However, we must keep an eye on the quality of the
245                                // studies as this change makes it easier to create dummy
246                                // studies which will create garbage in out database.
247                                flow.quickSave = true
248
249                                success()
250                        }
251                        on("refresh") {
252                                // handle form data
253                                studyPage(flow, flash, params)
254
255                                // force refresh of the template
256                                if (flow.study.template && flow.study.template instanceof Template) {
257                                        flow.study.template.refresh()
258                                }
259
260                                // reset errors
261                                flash.wizardErrors = [:]
262                                success()
263                        }.to "study"
264            on("switchTemplate") {
265                                // handle form data
266                                studyPage(flow, flash, params)
267
268                                // reset errors
269                                flash.wizardErrors = [:]
270                                success()
271                        }.to "study"
272                        on("previous") {
273                                // handle form data
274                                studyPage(flow, flash, params)
275
276                                // reset errors
277                                flash.wizardErrors = [:]
278                                success()
279                        }.to "start"
280                        on("next") {
281                                studyPage(flow, flash, params) ? success() : error()
282                        }.to "studyNext"
283                        on("quickSave") {
284                                studyPage(flow, flash, params) ? success() : error()
285                        }.to "save"
286                        on("toPageTwo") {
287                                studyPage(flow, flash, params) ? success() : error()
288                        }.to "studyNext"
289                        on("toPageThree") {
290                                studyPage(flow, flash, params) ? success() : error()
291                        }.to "events"
292                        on("toPageFour") {
293                                studyPage(flow, flash, params) ? success() : error()
294                        }.to "samples"
295                        on("toPageFive") {
296                                studyPage(flow, flash, params) ? success() : error()
297                        }.to "assays"
298                        on("toPageSix") {
299                                studyPage(flow, flash, params) ? success() : error()
300                        }.to "confirm"
301                        on("toPageSeven") {
302                                studyPage(flow, flash, params) ? success() : error()
303                        }.to "save"
304                }
305
306                // handle the second tab click on the study page
307                studyNext {
308                        action {
309                                if (session.jump?.action == 'simpleedit') {
310                                        toSave()
311                                } else {
312                                        toPageTwo()
313                                }
314                        }
315                        on("toSave").to "save"
316                        on("toPageTwo").to "subjects"
317                }
318
319                // render and handle subjects page
320                subjects {
321                        render(view: "_subjects")
322                        onRender {
323                                // Grom a development message
324                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_subjects.gsp".grom()
325
326                                flow.page = 2
327
328                                if (!flash.values || !flash.values.addNumber) flash.values = [addNumber:1]
329
330                                success()
331                        }
332                        on("refresh") {
333                                // remember the params in the flash scope
334                                flash.values = params
335
336                                // refresh templates
337                                if (flow.study.subjects) {
338                                        flow.study.giveSubjectTemplates().each() {
339                                                it.refresh()
340                                        }
341                                }
342
343                                success()
344                        }.to "subjects"
345                        on("add") {
346                                // handle form data
347                                addSubjects(flow, flash, params) ? success() : error()
348                        }.to "subjects"
349                        on("delete") {
350                                // handle form data
351                                subjectPage(flow, flash, params)
352
353                                // reset errors
354                                flash.wizardErrors = [:]
355
356                                // remove subject
357                                def subjectToRemove = flow.study.subjects.find { it.identifier == (params.get('do') as int) }
358                                if (subjectToRemove) {
359                                        flow.study.deleteSubject( subjectToRemove )
360                                }
361                        }.to "subjects"
362                        on("previous") {
363                                // handle form data
364                                subjectPage(flow, flash, params)
365
366                                // reset errors
367                                flash.wizardErrors = [:]
368                                success()
369                        }.to "study"
370                        on("next") {
371                                // handle form data
372                                subjectPage(flow, flash, params) ? success() : error()
373                        }.to "events"
374                        on("quickSave") {
375                                // handle form data
376                                subjectPage(flow, flash, params) ? success() : error()
377                        }.to "save"
378                        on("toPageOne") {
379                                subjectPage(flow, flash, params) ? success() : error()
380                        }.to "study"
381                        on("toPageThree") {
382                                subjectPage(flow, flash, params) ? success() : error()
383                        }.to "events"
384                        on("toPageFour") {
385                                subjectPage(flow, flash, params) ? success() : error()
386                        }.to "samples"
387                        on("toPageFive") {
388                                subjectPage(flow, flash, params) ? success() : error()
389                        }.to "assays"
390                        on("toPageSix") {
391                                subjectPage(flow, flash, params) ? success() : error()
392                        }.to "confirm"
393                        on("toPageSeven") {
394                                subjectPage(flow, flash, params) ? success() : error()
395                        }.to "save"
396                }
397
398                // render events page
399                events {
400                        render(view: "_events")
401                        onRender {
402                                // Grom a development message
403                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_events.gsp".grom()
404
405                                flow.page = 3
406
407                                // add initial eventGroup to study
408                                if (!flow.study.eventGroups?.size()) {
409                                        flow.study.addToEventGroups(
410                                                new EventGroup(name: 'Group 1')
411                                        )
412                                }
413
414                                success()
415                        }
416                        on("clear") {
417                                // remove all events
418                                (flow.study.events + flow.study.samplingEvents).each() { event ->
419                                        if (event instanceof SamplingEvent) {
420                                                flow.study.deleteSamplingEvent( event )
421                                        } else {
422                                                flow.study.deleteEvent( event )
423                                        }
424                                }
425
426                                success()
427                        }.to "events"
428                        on("switchTemplate") {
429                                // handle form data
430                                eventPage(flow, flash, params)
431
432                                // get template
433                                def type        = params.get('eventType')
434                                def template= Template.findByName( params.get( type + 'Template' ) )
435                                if (template) template.refresh()
436
437                                // change template and/or instance?
438                                if (!flow.event || (flow.event instanceof Event && type == "sample") || (flow.event instanceof SamplingEvent && type == "event")) {
439                                        // create new instance
440                                        flow.event = (type == "event") ? new Event(template: template) : new SamplingEvent(template: template)
441                                } else {
442                                        flow.event.template = template
443                                }
444
445                                // reset errors
446                                flash.wizardErrors = [:]
447                                success()
448
449                        }.to "events"
450                        on("refresh") {
451                                // handle form data
452                                eventPage(flow, flash, params)
453
454                                // refresh templates
455                                flow.study.giveEventTemplates().each() {
456                                        it.refresh()
457                                }
458
459                                // refresh event template
460                                if (flow.event?.template) {
461                                        flow.event.template.refresh()
462                                }
463
464                                // reset errors
465                                flash.wizardErrors = [:]
466                                success()
467                        }.to "events"
468                        on("add") {
469                                // handle form data
470                                eventPage(flow, flash, params)
471
472                                // reset errors
473                                flash.wizardErrors = [:]
474
475                                // add event to study
476                                if (flow.event instanceof SamplingEvent) {
477                                        flow.study.addToSamplingEvents( flow.event )
478                                } else {
479                                        flow.study.addToEvents( flow.event )
480                                }
481
482                                // validate event
483                                if (flow.event.validate()) {
484                                        // remove event from the flowscope
485                                        flow.remove('event')
486
487                                        success()
488                                } else {
489                                        // event does not validate
490                                        // remove from study
491                                        if (flow.event instanceof SamplingEvent) {
492                                                flow.study.removeFromSamplingEvents( flow.event )
493                                        } else {
494                                                flow.study.removeFromEvents( flow.event )
495                                        }
496
497                                        // append errors
498                                        this.appendErrors(flow.event, flash.wizardErrors)
499                                        error()
500                                }
501                        }.to "events"
502                        on("deleteEvent") {
503                                // handle form data
504                                eventPage(flow, flash, params)
505
506                                // reset errors
507                                flash.wizardErrors = [:]
508
509                                // find matching (sampling) event
510                                def event                       = flow.study.events.find { it.getIdentifier() == (params.get('do') as int) }
511                                def samplingEvent       = flow.study.samplingEvents.find { it.getIdentifier() == (params.get('do') as int) }
512
513                                // perform delete
514                                if (event) flow.study.deleteEvent( event )
515                                if (samplingEvent) flow.study.deleteSamplingEvent( samplingEvent )
516                        }.to "events"
517                        on("addEventGroup") {
518                                // handle form data
519                                eventPage(flow, flash, params)
520
521                                // set work variables
522                                def groupName = 'Group '
523                                def tempGroupIterator = 1
524                                def tempGroupName = groupName + tempGroupIterator
525
526                                // make sure group name is unique
527                                if (flow.study.eventGroups) {
528                                        while (flow.study.eventGroups.find { it.name == tempGroupName }) {
529                                                tempGroupIterator++
530                                                tempGroupName = groupName + tempGroupIterator
531                                        }
532                                }
533                                groupName = tempGroupName
534
535                                // add a new eventGroup
536                                flow.study.addToEventGroups(
537                                        new EventGroup(
538                                                name    : groupName
539                                        )
540                                )
541
542                                // reset errors
543                                flash.wizardErrors = [:]
544                                success()
545                        }.to "events"
546                        on("deleteEventGroup") {
547                                // handle form data
548                                eventPage(flow, flash, params)
549
550                                // reset errors
551                                flash.wizardErrors = [:]
552
553                                // remove eventGroup
554                                def eventGroupToRemove = flow.study.eventGroups.find { it.getIdentifier() == (params.get('do') as int) }
555                                if (eventGroupToRemove) {
556                                        flow.study.deleteEventGroup( eventGroupToRemove )
557                                }
558                        }.to "events"
559                        on("duplicate") {
560                                // handle form data
561                                eventPage(flow, flash, params)
562
563                                // reset errors
564                                flash.wizardErrors = [:]
565
566                                // clone event
567                                def event = null
568                                (((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : [])).find { it.getIdentifier() == (params.get('do') as int) }.each {
569                                        event = (it instanceof SamplingEvent) ? new SamplingEvent() : new Event()
570
571                                        // set template
572                                        event.template = it.template
573
574                                        // copy data
575                                        it.giveFields().each() { field ->
576                                                event.setFieldValue(
577                                                        field.name,
578                                                        it.getFieldValue(field.name)
579                                                )
580                                        }
581
582                                        // assign duplicate event to study
583                                        if (event instanceof SamplingEvent) {
584                                                flow.study.addToSamplingEvents(event)
585                                        } else {
586                                                flow.study.addToEvents(event)
587                                        }
588                                }
589
590                                success()
591                        }.to "events"
592                        on("previous") {
593                                // handle form data
594                                eventPage(flow, flash, params)
595
596                                // reset errors
597                                flash.wizardErrors = [:]
598                                success()
599                        }.to "subjects"
600                        on("next") {
601                                // handle form data
602                                eventPage(flow, flash, params) ? success() : error()
603                        }.to "eventsNext"
604                        on("quickSave") {
605                                // handle form data
606                                eventPage(flow, flash, params) ? success() : error()
607                        }.to "save"
608                        on("toPageOne") {
609                                eventPage(flow, flash, params) ? success() : error()
610                        }.to "study"
611                        on("toPageTwo") {
612                                eventPage(flow, flash, params) ? success() : error()
613                        }.to "subjects"
614                        on("toPageFour") {
615                                eventPage(flow, flash, params) ? success() : error()
616                        }.to "samples"
617                        on("toPageFive") {
618                                eventPage(flow, flash, params) ? success() : error()
619                        }.to "assays"
620                        on("toPageSix") {
621                                eventPage(flow, flash, params) ? success() : error()
622                        }.to "confirm"
623                        on("toPageSeven") {
624                                eventPage(flow, flash, params) ? success() : error()
625                        }.to "save"
626                }
627
628                // decide to show a warning page or not
629                eventsNext {
630                        action {
631                                // Grom a development message
632                                if (pluginManager.getGrailsPlugin('grom')) ".entering eventsNext".grom()
633
634                                def assigned = false
635
636                                // check if all sampling events are in an eventGroup
637                                flow.study.samplingEvents.each() { samplingEvent ->
638                                        // iterate through eventGroups
639                                        flow.study.eventGroups.each() { eventGroup ->
640                                                if ( eventGroup.samplingEvents.find { it.equals(samplingEvent) } ) {
641                                                        assigned = true
642                                                }
643                                        }
644                                }
645
646                                if (assigned) {
647                                        toGroupsPage()
648                                } else {
649                                        toWarningPage()
650                                }
651                        }
652                        on("toWarningPage").to "unassignedSamplingEventWarning"
653                        on("toGroupsPage").to "groups"
654                }
655
656                // warning page for unassigned samplingEvent
657                unassignedSamplingEventWarning {
658                        render(view: "_unassigned_samplingEvent_warning")
659                        onRender {
660                                // Grom a development message
661                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_unnassigned_samplingEvent_warning.gsp".grom()
662
663                                flow.page = 3
664                                success()
665                        }
666                        on("next").to "groups"
667                        on("previous").to "events"
668                        on("toPageOne") {
669                                eventPage(flow, flash, params) ? success() : error()
670                        }.to "study"
671                        on("toPageTwo") {
672                                eventPage(flow, flash, params) ? success() : error()
673                        }.to "subjects"
674                        on("toPageFour") {
675                                eventPage(flow, flash, params) ? success() : error()
676                        }.to "samples"
677                        on("toPageFive") {
678                                eventPage(flow, flash, params) ? success() : error()
679                        }.to "assays"
680                        on("toPageSix") {
681                                eventPage(flow, flash, params) ? success() : error()
682                        }.to "confirm"
683                        on("toPageSeven") {
684                                eventPage(flow, flash, params) ? success() : error()
685                        }.to "save"
686                }
687
688                // groups page
689                groups {
690                        render(view: "_groups")
691                        onRender {
692                                // Grom a development message
693                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_groups.gsp".grom()
694
695                                flow.page = 3
696                                success()
697                        }
698                        on("previous") {
699                                // handle form data
700                                groupPage(flow, flash, params) ? success() : error()
701                        }.to "events"
702                        on("next") {
703                                // handle form data
704                                groupPage(flow, flash, params) ? success() : error()
705                        }.to "samples"
706                        on("quickSave") {
707                                // handle form data
708                                groupPage(flow, flash, params) ? success() : error()
709                        }.to "save"
710                        on("toPageOne") {
711                                groupPage(flow, flash, params) ? success() : error()
712                        }.to "study"
713                        on("toPageTwo") {
714                                groupPage(flow, flash, params) ? success() : error()
715                        }.to "subjects"
716                        on("toPageFour") {
717                                groupPage(flow, flash, params) ? success() : error()
718                        }.to "samples"
719                        on("toPageFive") {
720                                groupPage(flow, flash, params) ? success() : error()
721                        }.to "assays"
722                        on("toPageSix") {
723                                groupPage(flow, flash, params) ? success() : error()
724                        }.to "confirm"
725                        on("toPageSeven") {
726                                groupPage(flow, flash, params) ? success() : error()
727                        }.to "save"
728                }
729
730                // sample 'previous' page with warning
731                samplePrevious {
732                        render(view: "_samples_previous_warning")
733                        onRender {
734                                // Grom a development message
735                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_samples_previous_warning.gsp".grom()
736
737                                flow.page = 4
738                        }
739                        on("next").to "samples"
740                        on("previous").to "groups"
741                        on("toPageOne").to "study"
742                        on("toPageTwo").to "subjects"
743                        on("toPageThree").to "events"
744                        on("toPageFive").to "assays"
745                        on("toPageSix").to "confirm"
746                        on("toPageSeven").to "save"
747                }
748
749                // samples page
750                samples {
751                        render(view: "_samples")
752                        onRender {
753                                // Grom a development message
754                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_samples.gsp".grom()
755
756                                flow.page = 4
757                                success()
758                        }
759                        on("switchTemplate") {
760                                // handle form data
761                                samplePage(flow, flash, params)
762
763                                // ignore errors
764                                flash.wizardErrors = [:]
765
766                                succes()
767                        }.to "samples"
768                        on("refresh") {
769                                // handle samples
770                                samplePage(flow, flash, params)
771
772                                // refresh all sample templates
773                                flow.study.giveSampleTemplates().each() {
774                                        it.refresh()
775                                }
776
777                                // ignore errors
778                                flash.wizardErrors = [:]
779
780                                success()
781                        }.to "samples"
782                        on("regenerate") {
783                                // handle samples
784                                samplePage(flow, flash, params)
785
786                                // remove all samples from the study
787                                flow.study.samples.findAll{true}.each() { sample ->
788                                        flow.study.deleteSample( sample )
789                                }
790
791                                // ignore errors
792                                flash.wizardErrors = [:]
793
794                                success()
795                        }.to "samples"
796                        on("previous") {
797                                // handle samples
798                                samplePage(flow, flash, params)
799
800                                // ignore errors
801                                flash.wizardErrors = [:]
802
803                                success()
804                        }.to "samplePrevious"
805                        on("next") {
806                                // handle form data
807                                samplePage(flow, flash, params) ? success() : error()
808                        }.to "assays"
809                        on("quickSave") {
810                                // handle form data
811                                samplePage(flow, flash, params) ? success() : error()
812                        }.to "save"
813                        on("toPageOne") {
814                                samplePage(flow, flash, params) ? success() : error()
815                        }.to "study"
816                        on("toPageTwo") {
817                                samplePage(flow, flash, params) ? success() : error()
818                        }.to "subjects"
819                        on("toPageThree") {
820                                samplePage(flow, flash, params) ? success() : error()
821                        }.to "events"
822                        on("toPageFive") {
823                                samplePage(flow, flash, params) ? success() : error()
824                        }.to "assays"
825                        on("toPageSix") {
826                                samplePage(flow, flash, params) ? success() : error()
827                        }.to "confirm"
828                        on("toPageSeven") {
829                                samplePage(flow, flash, params) ? success() : error()
830                        }.to "save"
831                }
832
833                // assays page
834                assays {
835                        render(view: "_assays")
836                        onRender {
837                                // Grom a development message
838                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_assays.gsp".grom()
839
840                                flow.page = 5
841                        }
842                        on("refresh") {
843                                // handle form data
844                                assayPage(flow, flash, params)
845
846                                // force refresh of the template
847                                if (flow.assay && flow.assay.template && flow.assay.template instanceof Template) {
848                                        flow.assay.template.refresh()
849                                }
850
851                                // reset errors
852                                flash.wizardErrors = [:]
853                                success()
854                        }.to "assays"
855            on("switchTemplate") {
856                                // handle form data
857                    assayPage(flow, flash, params)
858
859                    // find assay template
860                    def template = Template.findByName(params.get('template'))
861                    if (flow.assay) {
862                            // set template
863                            flow.assay.template = template
864                    } else {
865                            // create a new assay instance
866                            flow.assay = new Assay(template: template)
867                    }
868
869                                // reset errors
870                                flash.wizardErrors = [:]
871                                success()
872                        }.to "assays"
873                        on("add") {
874                                // handle form data
875                                assayPage(flow, flash, params)
876
877                                // reset errors
878                                flash.wizardErrors = [:]
879
880                                // add assay to study
881                                flow.study.addToAssays( flow.assay )
882
883                                // validate assay
884                                if (flow.assay.validate()) {
885                                        // remove assay from the flowscope
886                                        flow.remove('assay')
887                                        success()
888                                } else {
889                                        // assay does not validate
890                                        // remove from study
891                                        flow.study.deleteAssay( flow.assay )
892
893                                        // append errors
894                                        this.appendErrors(flow.assay, flash.wizardErrors)
895                                        error()
896                                }
897                        }.to "assays"
898                        on("deleteAssay") {
899                                // handle form data
900                                assayPage(flow, flash, params)
901
902                                // reset errors
903                                flash.wizardErrors = [:]
904
905                                // find this assay
906                                def assay = flow.study.assays.find { it.getIdentifier() == (params.get('do') as int) }
907
908                                // perform delete
909                                if (assay) flow.study.deleteAssay( assay )
910                        }.to "assays"
911                        on("previous") {
912                                // handle form data
913                                assayPage(flow, flash, params)
914
915                                // ignore errors
916                                flash.wizardErrors = [:]
917
918                                success()
919                        }.to "samples"
920                        on("next") {
921                                // handle form data
922                                assayPage(flow, flash, params) ? success() : error()
923                        }.to "assayNext"
924                        on("quickSave") {
925                                // handle form data
926                                assayPage(flow, flash, params) ? success() : error()
927                        }.to "save"
928                        on("toPageOne") {
929                                assayPage(flow, flash, params) ? success() : error()
930                        }.to "study"
931                        on("toPageTwo") {
932                                assayPage(flow, flash, params) ? success() : error()
933                        }.to "subjects"
934                        on("toPageThree") {
935                                assayPage(flow, flash, params) ? success() : error()
936                        }.to "events"
937                        on("toPageFour") {
938                                assayPage(flow, flash, params) ? success() : error()
939                        }.to "samples"
940                        on("toPageSix") {
941                                assayPage(flow, flash, params) ? success() : error()
942                        }.to "confirm"
943                        on("toPageSeven") {
944                                assayPage(flow, flash, params) ? success() : error()
945                        }.to "save"
946                }
947
948                // assayNext
949                assayNext {
950                        action {
951                                // Grom a development message
952                                if (pluginManager.getGrailsPlugin('grom')) "entering assayNext".grom()
953
954                                // have we got samples and assays?
955                                if (flow.study.assays && flow.study.samples) {
956                                        // yes, go to the group page
957                                        toAssayGroups()
958                                } else {
959                                        // no need to show the group page as
960                                        // there's nothing to group
961                                        toConfirm()
962                                }
963                        }
964                        on("toAssayGroups").to "assayGroups"
965                        on("toConfirm").to "confirm"
966                }
967
968                // assay grouping page
969                assayGroups {
970                        render(view: "_assay_groups")
971                        onRender {
972                                // Grom a development message
973                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_assay_groups.gsp".grom()
974
975                                flow.page = 5
976                        }
977                        on("previous") {
978                                // handle form data
979                                assayGroupPage(flow, flash, params)
980
981                                // ignore errors
982                                flash.wizardErrors = [:]
983
984                                success()
985                        }.to "assays"
986                        on("next") {
987                                // handle form data
988                                assayGroupPage(flow, flash, params) ? success() : error()
989                        }.to "confirm"
990                        on("quickSave") {
991                                // handle form data
992                                assayGroupPage(flow, flash, params) ? success() : error()
993                        }.to "save"
994                        on("toPageOne") {
995                                assayGroupPage(flow, flash, params) ? success() : error()
996                        }.to "study"
997                        on("toPageTwo") {
998                                assayGroupPage(flow, flash, params) ? success() : error()
999                        }.to "subjects"
1000                        on("toPageThree") {
1001                                assayGroupPage(flow, flash, params) ? success() : error()
1002                        }.to "events"
1003                        on("toPageFour") {
1004                                assayGroupPage(flow, flash, params) ? success() : error()
1005                        }.to "samples"
1006                        on("toPageSix") {
1007                                assayGroupPage(flow, flash, params) ? success() : error()
1008                        }.to "confirm"
1009                        on("toPageSeven") {
1010                                assayGroupPage(flow, flash, params) ? success() : error()
1011                        }.to "save"
1012                }
1013
1014                // confirm Previous
1015                confirmPrevious {
1016                        action {
1017                                // Grom a development message
1018                                if (pluginManager.getGrailsPlugin('grom')) "entering confirmPrevious".grom()
1019
1020                                // have we got samples and assays?
1021                                if (flow.study.assays && flow.study.samples) {
1022                                        // yes, go to the group page
1023                                        toAssayGroups()
1024                                } else {
1025                                        // no need to show the group page as
1026                                        // there's nothing to group
1027                                        toAssays()
1028                                }
1029                        }
1030                        on("toAssayGroups").to "assayGroups"
1031                        on("toAssays").to "assays"
1032                }
1033
1034                // confirmation
1035                confirm {
1036                        render(view: "_confirmation")
1037                        onRender {
1038                                // Grom a development message
1039                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_confirmation.gsp".grom()
1040
1041                                flow.page = 6
1042                        }
1043                        on("toStudy").to "study"
1044                        on("toSubjects").to "subjects"
1045                        on("toEvents").to "events"
1046                        on("toGroups").to "groups"
1047                        on("toSamples").to "samples"
1048                        on("toAssays").to "assays"
1049                        on("toAssayGroups").to "assayGroups"
1050                        on("previous").to "confirmPrevious"
1051                        on("next").to "save"
1052                        on("quickSave").to "save"
1053                        on("toPageOne").to "study"
1054                        on("toPageTwo").to "subjects"
1055                        on("toPageThree").to "events"
1056                        on("toPageFour").to "samples"
1057                        on("toPageFive").to "assays"
1058                        on("toPageSeven").to "save"
1059                }
1060
1061                // store all study data
1062                save {
1063                        action {
1064                                // Grom a development message
1065                                if (pluginManager.getGrailsPlugin('grom')) "entering save".grom()
1066
1067                                flow.page = 7
1068                                flash.wizardErrors = [:]
1069
1070                                // persist data to the database
1071                                try {
1072                                        // save study
1073                                        // Grom a development message
1074                                        if (pluginManager.getGrailsPlugin('grom')) "saving study".grom()
1075
1076                                        // Make sure the owner of the study is set right
1077                                        if (!flow.study.owner) {
1078                                                flow.study.owner = authenticationService.getLoggedInUser()
1079                                        }
1080
1081                                        if (!flow.study.save(flush:true)) {
1082                                                this.appendErrors(flow.study, flash.wizardErrors)
1083                                                throw new Exception('error saving study')
1084                                        }
1085                                        log.info ".saved study "+flow.study+" (id: "+flow.study.id+")"
1086
1087                                        success()
1088                                } catch (Exception e) {
1089                                        // rollback
1090                                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace' ], flash.wizardErrors)
1091
1092                                        // stacktrace in flash scope
1093                                        flash.debug = e.getStackTrace()
1094
1095                                        error()
1096                                }
1097                        }
1098                        on("error").to "error"
1099                        on(Exception).to "error"
1100                        on("success").to "done"
1101                }
1102
1103                // error storing data
1104                error {
1105                        render(view: "_error")
1106                        onRender {
1107                                // Grom a development message
1108                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_error.gsp".grom()
1109
1110                                flow.page = 6
1111                        }
1112                        on("next").to "save"
1113                        on("previous").to "samples"
1114                        on("toPageOne").to "study"
1115                        on("toPageTwo").to "subjects"
1116                        on("toPageThree").to "events"
1117                        on("toPageFour").to "samples"
1118                        on("toPageFive").to "assays"
1119                        on("toPageSix").to "confirm"
1120                        on("toPageSeven").to "save"
1121                }
1122
1123                // render finish page
1124                done {
1125                        render(view: "_done")
1126                        onRender {
1127                                // Grom a development message
1128                                if (pluginManager.getGrailsPlugin('grom')) "rendering the partial: pages/_done.gsp".grom()
1129
1130                                flow.page = 7
1131                        }
1132                        onEnd {
1133                                // clean flow scope
1134                                flow.clear()
1135                        }
1136                }
1137        }
1138
1139        /**
1140         * load a study
1141         * @param Map LocalAttributeMap (the flow scope)
1142         * @param Map localAttributeMap (the flash scope)
1143         * @param Map GrailsParameterMap (the flow parameters = form data)
1144         * @returns boolean
1145         */
1146        def loadStudy(flow, flash, params, user) {
1147                flash.wizardErrors      = [:]
1148
1149                // load study
1150                try {
1151                        // load study
1152                        def study = (params.studyid) ? Study.findById( params.studyid ) : Study.findByTitle( params.study )
1153
1154                        // Check whether the user is allowed to edit this study. If it is not allowed
1155                        // the used should had never seen a link to this page, so he should never get
1156                        // here. That's why we just return false
1157            if (!study.canWrite(user)){
1158                                return false
1159                        }
1160
1161                        // store study in the flowscope
1162                        flow.study = study
1163
1164                        // set 'quicksave' variable
1165                        flow.quickSave = true
1166
1167                        return true
1168                } catch (Exception e) {
1169                        // rollback
1170                        this.appendErrorMap(['exception': e.getMessage() + ', see log for stacktrace'], flash.wizardErrors)
1171
1172                        return false
1173                }
1174        }
1175
1176        /**
1177         * Handle the wizard study page
1178         *
1179         * @param Map LocalAttributeMap (the flow scope)
1180         * @param Map localAttributeMap (the flash scope)
1181         * @param Map GrailsParameterMap (the flow parameters = form data)
1182         * @returns boolean
1183         */
1184        def studyPage(flow, flash, params) {
1185                flash.values            = params
1186                flash.wizardErrors      = [:]
1187
1188                // instantiate study of it is not yet present
1189                if (!flow.study) flow.study = new Study()
1190
1191                // did the study template change?
1192                if (params.get('template').size() && flow.study.template?.name != params.get('template')) {
1193                        // set the template
1194                        flow.study.template = Template.findByName(params.remove('template'))
1195                }
1196
1197                // does the study have a template set?
1198                if (flow.study.template && flow.study.template instanceof Template) {
1199                        // yes, iterate through template fields
1200                        flow.study.giveFields().each() {
1201                                // and set their values
1202                                flow.study.setFieldValue(it.name, params.get(it.escapedName()))
1203                        }
1204                }
1205
1206                // handle publications
1207                handlePublications(flow, flash, params)
1208
1209                // handle contacts
1210                handleContacts(flow, flash, params)
1211
1212                // handle users (readers, writers)
1213                handleUsers(flow, flash, params, 'readers')
1214                handleUsers(flow, flash, params, 'writers')
1215
1216                // handle public checkbox
1217                if (params.get("publicstudy")) {
1218                        flow.study.publicstudy = params.get("publicstudy")
1219                }
1220
1221                // have we got a template?
1222                if (flow.study.template && flow.study.template instanceof Template) {
1223                        // validate the study
1224                        if (flow.study.validate()) {
1225                                // instance is okay
1226                                return true
1227                        } else {
1228                                // validation failed
1229                                this.appendErrors(flow.study, flash.wizardErrors)
1230                                return false
1231                        }
1232                } else {
1233                        // no, return an error that the template is not set
1234                        this.appendErrorMap(['template': g.message(code: 'select.not.selected.or.add', args: ['template'])], flash.wizardErrors)
1235                        return false
1236                }
1237        }
1238
1239        /**
1240         * re-usable code for handling publications form data in a web flow
1241         * @param Map LocalAttributeMap (the flow scope)
1242         * @param Map localAttributeMap (the flash scope)
1243         * @param Map GrailsParameterMap (the flow parameters = form data)
1244         * @returns boolean
1245         */
1246        def handlePublications(flow, flash, params) {
1247                flash.wizardErrors      = [:]
1248                handleStudyPublications( flow.study, params );
1249        }
1250
1251        /**
1252         * re-usable code for handling contacts form data in a web flow
1253         * @param Map LocalAttributeMap (the flow scope)
1254         * @param Map localAttributeMap (the flash scope)
1255         * @param Map GrailsParameterMap (the flow parameters = form data)
1256         * @return boolean
1257         */
1258        def handleContacts(flow, flash, params) {
1259                flash.wizardErrors      = [:]
1260
1261                handleStudyContacts( flow.study, params );
1262        }
1263
1264        /**
1265         * re-usable code for handling contacts form data in a web flow
1266         * @param Map LocalAttributeMap (the flow scope)
1267         * @param Map localAttributeMap (the flash scope)
1268         * @param Map GrailsParameterMap (the flow parameters = form data)
1269     * @param String    'readers' or 'writers'
1270         * @return boolean
1271         */
1272        def handleUsers(flow, flash, params, type) {
1273                flash.wizardErrors = [:]
1274                handleStudyUsers( flow.study, params, type );
1275        }
1276       
1277        /**
1278        * re-usable code for handling publications form data
1279        * @param study  Study object to update
1280        * @param params GrailsParameterMap (the flow parameters = form data)
1281        * @returns boolean
1282        */
1283   def handleStudyPublications(Study study,  params) {
1284           if (study.publications) study.publications = []
1285
1286           // Check the ids of the pubblications that should be attached
1287           // to this study. If they are already attached, keep 'm. If
1288           // studies are attached that are not in the selected (i.e. the
1289           // user deleted them), remove them
1290           def publicationIDs = params.get('publication_ids')
1291           if (publicationIDs) {
1292                   // Find the individual IDs and make integers
1293                   publicationIDs = publicationIDs.split(',').collect { Integer.parseInt(it, 10) }
1294
1295                   // First remove the publication that are not present in the array
1296                   if( study.publications )
1297                           study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
1298
1299                   // Add those publications not yet present in the database
1300                   publicationIDs.each { id ->
1301                           if (!study.publications.find { publication -> id == publication.id }) {
1302                                   def publication = Publication.get(id)
1303                                   if (publication) {
1304                                           study.addToPublications(publication)
1305                                   } else {
1306                                           log.info('.publication with ID ' + id + ' not found in database.')
1307                                   }
1308                           }
1309                   }
1310
1311           } else {
1312                   log.info('.no publications selected.')
1313                   if( study.publications )
1314                           study.publications.clear()
1315           }
1316   }
1317
1318   /**
1319        * re-usable code for handling contacts form data
1320        * @param study  Study object to update
1321        * @param Map GrailsParameterMap (the flow parameters = form data)
1322        * @return boolean
1323        */
1324   def handleStudyContacts(Study study, params) {
1325           if (!study.persons) study.persons = []
1326
1327           // Check the ids of the contacts that should be attached
1328           // to this study. If they are already attached, keep 'm. If
1329           // studies are attached that are not in the selected (i.e. the
1330           // user deleted them), remove them
1331
1332           // Contacts are saved as [person_id]-[role_id]
1333           def contactIDs = params.get('contacts_ids')
1334           if (contactIDs) {
1335                   // Find the individual IDs and make integers
1336                   contactIDs = contactIDs.split(',').collect {
1337                           def parts = it.split('-')
1338                           return [person: Integer.parseInt(parts[0]), role: Integer.parseInt(parts[1])]
1339                   }
1340
1341                   // First remove the contacts that are not present in the array
1342                   if( study.persons ) {
1343                           study.persons.removeAll {
1344                                   studyperson -> !contactIDs.find { ids -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }
1345                           }
1346                   }
1347
1348                   // Add those contacts not yet present in the database
1349                   contactIDs.each { ids ->
1350                           if (!study.persons.find { studyperson -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }) {
1351                                   def person = Person.get(ids.person)
1352                                   def role = PersonRole.get(ids.role)
1353                                   if (person && role) {
1354                                           // Find a studyperson object with these parameters
1355                                           def studyPerson = StudyPerson.findAll().find { studyperson -> studyperson.person.id == person.id && studyperson.role.id == role.id }
1356
1357                                           // If if does not yet exist, save the example
1358                                           if (!studyPerson) {
1359                                                   studyPerson = new StudyPerson(
1360                                                                   person: person,
1361                                                                   role: role
1362                                                                   )
1363                                                   studyPerson.save(flush: true)
1364                                           }
1365
1366                                           study.addToPersons(studyPerson)
1367                                   } else {
1368                                           log.info('.person ' + ids.person + ' or Role ' + ids.role + ' not found in database.')
1369                                   }
1370                           }
1371                   }
1372           } else {
1373                   log.info('.no persons selected.')
1374                   if( study.persons )
1375                           study.persons.clear()
1376           }
1377   }
1378
1379   /**
1380        * re-usable code for handling contacts form data
1381        * @param study  Study object to update
1382        * @param Map GrailsParameterMap (the flow parameters = form data)
1383        * @param String    'readers' or 'writers'
1384        * @return boolean
1385        */
1386   def handleStudyUsers(Study study, params, type) {
1387           def users = []
1388
1389           if (type == "readers" && study.readers ) {
1390                   users += study.readers
1391           } else if (type == "writers" && study.writers ) {
1392                   users += study.writers
1393           }
1394
1395           // Check the ids of the contacts that should be attached
1396           // to this study. If they are already attached, keep 'm. If
1397           // studies are attached that are not in the selected (i.e. the
1398           // user deleted them), remove them
1399
1400           // Users are saved as user_id
1401           def userIDs = params.get(type + '_ids')
1402           
1403           if (userIDs) {
1404                   // Find the individual IDs and make integers
1405                   userIDs = userIDs.split(',').collect { Long.valueOf(it, 10) }
1406                   
1407                   // First remove the publication that are not present in the array
1408                   users.removeAll { user -> !userIDs.find { id -> id == user.id } }
1409
1410                   // Add those publications not yet present in the database
1411                   userIDs.each { id ->
1412                           if (!users.find { user -> id == user.id }) {
1413                                   def user = SecUser.get(id)
1414                                   if (user) {
1415                                           users.add(user)
1416                                   } else {
1417                                           log.info('.user with ID ' + id + ' not found in database.')
1418                                   }
1419                           }
1420                   }
1421                   
1422           } else {
1423                   log.info('.no users selected.')
1424                   users.clear()
1425           }
1426           
1427           if (type == "readers") {
1428                   if (study.readers)
1429                           study.readers.clear()
1430                           
1431                   users.each { study.addToReaders(it) }
1432           } else if (type == "writers") {
1433                   if (study.writers)
1434                           study.writers.clear()
1435
1436                   users.each { study.addToWriters(it) }
1437                   
1438           }
1439   }
1440       
1441       
1442               
1443
1444        /**
1445         * Handle the wizard subject page
1446         *
1447         * @param Map LocalAttributeMap (the flow scope)
1448         * @param Map localAttributeMap (the flash scope)
1449         * @param Map GrailsParameterMap (the flow parameters = form data)
1450         * @returns boolean
1451         */
1452        def subjectPage(flow, flash, params) {
1453                def errors = false
1454                flash.wizardErrors = [:]
1455
1456                // remember the params in the flash scope
1457                flash.values = params
1458
1459                // iterate through subjects
1460                flow.study.subjects.each() { subject ->
1461                        // iterate through (template and domain) fields
1462                        subject.giveFields().each() { field ->
1463                                // set field
1464                                subject.setFieldValue(
1465                                        field.name,
1466                                        params.get('subject_' + subject.getIdentifier() + '_' + field.escapedName())
1467                                )
1468                        }
1469
1470                        // validate subject
1471                        if (!subject.validate()) {
1472                                errors = true
1473                                this.appendErrors(subject, flash.wizardErrors, 'subject_' + subject.getIdentifier() + '_')
1474                        }
1475                }
1476
1477                return !errors
1478        }
1479
1480        /**
1481         * Add a number of subjects to a study
1482         *
1483         * required params entities:
1484         * -addNumber (int)
1485         * -species   (string)
1486         * -template  (string)
1487         *
1488         * @param Map LocalAttributeMap (the flow scope)
1489         * @param Map localAttributeMap (the flash scope)
1490         * @param Map GrailsParameterMap (the flow parameters = form data)
1491         * @returns boolean
1492         */
1493        def addSubjects(flow, flash, params) {
1494                // remember the params in the flash scope
1495                flash.values = params
1496
1497                // handle the subject page
1498                subjectPage(flow, flash, params)
1499
1500                // (re)set error message
1501                flash.wizardErrors = [:]
1502
1503                // set work variables
1504                def errors              = false
1505                def number              = params.get('addNumber') as int
1506                def species             = Term.findByName(params.get('species'))
1507                def template    = Template.findByName(params.get('template'))
1508
1509                // can we add subjects?
1510                if (number > 0 && species && template) {
1511                        // add subjects to study
1512                        number.times {
1513                                // work variables
1514                                def subjectName = 'Subject '
1515                                def subjectIterator = 1
1516                                def tempSubjectName = subjectName + subjectIterator
1517
1518                                // make sure subject name is unique
1519                                if (flow.study.subjects) {
1520                                        while (flow.study.subjects.find { it.name == tempSubjectName }) {
1521                                                subjectIterator++
1522                                                tempSubjectName = subjectName + subjectIterator
1523                                        }
1524                                }
1525                                subjectName = tempSubjectName
1526
1527                                // create a subject instance
1528                                def subject = new Subject(
1529                                        name            : subjectName,
1530                                        species         : species,
1531                                        template        : template
1532                                )
1533
1534                                // add it to the study
1535                                flow.study.addToSubjects( subject )
1536                        }
1537                } else {
1538                        // add feedback
1539                        errors = true
1540                        if (number < 1) this.appendErrorMap(['addNumber': 'Enter a positive number of subjects to add'], flash.wizardErrors)
1541                        if (!species)   this.appendErrorMap(['species': g.message(code: 'select.not.selected.or.add', args: ['species'])], flash.wizardErrors)
1542                        if (!template)  this.appendErrorMap(['template': g.message(code: 'select.not.selected.or.add', args: ['template'])], flash.wizardErrors)
1543                }
1544
1545                return !errors
1546        }
1547
1548        /**
1549         * Handle the wizard event page
1550         *
1551         * @param Map LocalAttributeMap (the flow scope)
1552         * @param Map localAttributeMap (the flash scope)
1553         * @param Map GrailsParameterMap (the flow parameters = form data)
1554         * @returns boolean
1555         */
1556        def eventPage(flow, flash, params) {
1557                def errors = false
1558                flash.wizardErrors = [:]
1559
1560                // remember the params in the flash scope
1561                flash.values = params
1562
1563                // handle the 'add event' form
1564                if (flow.event) {
1565                        flow.event.giveFields().each() { field ->
1566                                // set field
1567                                flow.event.setFieldValue(
1568                                        field.name,
1569                                        params.get(field.escapedName())
1570                                )
1571                        }
1572                }
1573
1574                // handle the eventGroup names and grouping
1575                def name        = ""
1576                def tempName= ""
1577                flow.study.eventGroups.each() { eventGroup ->
1578                        // iterate through templates
1579                        flow.study.giveAllEventTemplates().each() { template ->
1580                                tempName = params.get( 'eventGroup_' + eventGroup.getIdentifier() + '_' + template.getIdentifier() )
1581
1582                                // is the name different?
1583                                if (tempName != eventGroup.name) {
1584                                        name = tempName
1585                                }
1586                        }
1587
1588                        // should the name change?
1589                        if (name) {
1590                                // yes, change it
1591                                eventGroup.name = name
1592                                name = ""
1593                        }
1594
1595                        // handle eventGrouping
1596                        ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
1597                                if (params.get( 'event_' + event.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
1598                                        // add to eventGroup
1599                                        if (event instanceof SamplingEvent) {
1600                                                // check if we are already in this eventGroup
1601                                                if (!eventGroup.samplingEvents.find { it.equals(event) }) {
1602                                                        // no, add it
1603                                                        eventGroup.addToSamplingEvents(event)
1604
1605                                                        // iterate through subjects for this eventGroup
1606                                                        eventGroup.subjects.each() { subject ->
1607                                                                // instantiate a sample for this subject / event
1608                                                                def samplingEventName = ucwords(event.template.name)
1609                                                                def eventGroupName = ucwords(eventGroup.name).replaceAll("([ ]{1,})", "")
1610                                                                def sampleName = (ucwords(subject.name) + '_' + samplingEventName + '_' + eventGroupName + '_' + new RelTime(event.startTime).toString()).replaceAll("([ ]{1,})", "")
1611                                                                def tempSampleIterator = 0
1612                                                                def tempSampleName = sampleName
1613
1614                                                                // make sure sampleName is unique
1615                                                                if (flow.study.samples) {
1616                                                                        while (flow.study.samples.find { it.name == tempSampleName }) {
1617                                                                                tempSampleIterator++
1618                                                                                tempSampleName = sampleName + "_" + tempSampleIterator
1619                                                                        }
1620                                                                        sampleName = tempSampleName
1621                                                                }
1622
1623                                                                // instantiate a sample
1624                                                                flow.study.addToSamples(
1625                                                                        new Sample(
1626                                                                                parentSubject   : subject,
1627                                                                                parentEvent             : event,
1628                                                                                parentEventGroup: eventGroup,
1629                                                                                name                    : sampleName,
1630                                                                                template                : (event.sampleTemplate) ? event.sampleTemplate : ''
1631                                                                        )
1632                                                                )
1633                                                        }
1634                                                }
1635                                        } else {
1636                                                eventGroup.addToEvents(event)
1637                                        }
1638                                } else {
1639                                        // remove from eventGroup
1640                                        if (event instanceof SamplingEvent) {
1641                                                // iterate through subjects (if we have them)
1642                                                eventGroup.subjects.each() { subject ->
1643                                                        // find all samples for this subject / event
1644                                                        flow.study.samples.findAll { (it.parentEvent.equals(event) && it.parentSubject.equals(subject) ) }.each() {
1645                                                                // delete this sample
1646                                                                flow.study.deleteSample( it )
1647                                                        }
1648                                                }
1649
1650                                                eventGroup.removeFromSamplingEvents(event)
1651                                        } else {
1652                                                eventGroup.removeFromEvents(event)
1653                                        }
1654                                }
1655                        }
1656                }
1657
1658                // handle the (sampling) events
1659                ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
1660                        event.giveFields().each() { field ->
1661                                event.setFieldValue(
1662                                        field.name,
1663                                        params.get( 'event_' + event.getIdentifier() + '_' + field.escapedName() )
1664                                )
1665                        }
1666
1667                        // validate event
1668                        if (!event.validate()) {
1669                                errors = true
1670                                this.appendErrors(event, flash.wizardErrors)
1671                        }
1672                }
1673
1674                return !errors
1675        }
1676
1677        /**
1678         * Handle the wizard group page
1679         *
1680         * @param Map LocalAttributeMap (the flow scope)
1681         * @param Map localAttributeMap (the flash scope)
1682         * @param Map GrailsParameterMap (the flow parameters = form data)
1683         * @returns boolean
1684         */
1685        def groupPage(flow, flash, params) {
1686                def errors = false
1687                flash.wizardErrors = [:]
1688
1689                // remember the params in the flash scope
1690                flash.values = params
1691
1692                // iterate through groups
1693                flow.study.eventGroups.each() { eventGroup ->
1694                        // iterate through subjects
1695                        flow.study.subjects.each() { subject ->
1696                                if (params.get('subject_' + subject.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
1697                                        // check if this subject is already part of this eventGroup
1698                                        if ( !eventGroup.subjects.find { it.equals(subject) } ) {
1699                                                // add to eventGroup
1700                                                eventGroup.addToSubjects(subject)
1701
1702                                                // iterate through samplingEvents
1703                                                eventGroup.samplingEvents.each() { samplingEvent ->
1704                                                        def samplingEventName = ucwords(samplingEvent.template.name)
1705                                                        def eventGroupName = ucwords(eventGroup.name)
1706                                                        def sampleName = (ucwords(subject.name) + '_' + samplingEventName + '_' + eventGroupName + '_' + new RelTime(samplingEvent.startTime).toString()).replaceAll("([ ]{1,})", "")
1707                                                        def tempSampleIterator = 0
1708                                                        def tempSampleName = sampleName
1709
1710                                                        // make sure sampleName is unique
1711                                                        if (flow.study.samples) {
1712                                                                while (flow.study.samples.find { it.name == tempSampleName }) {
1713                                                                        tempSampleIterator++
1714                                                                        tempSampleName = sampleName + "_" + tempSampleIterator
1715                                                                }
1716                                                                sampleName = tempSampleName
1717                                                        }
1718
1719                                                        // instantiate a sample
1720                                                        flow.study.addToSamples(
1721                                                                new Sample(
1722                                                                        parentSubject   : subject,
1723                                                                        parentEvent             : samplingEvent,
1724                                                                        parentEventGroup: eventGroup,
1725                                                                        name                    : sampleName,
1726                                                                        template                : (samplingEvent.sampleTemplate) ? samplingEvent.sampleTemplate : ''
1727                                                                )
1728                                                        )
1729                                                }
1730                                        } else {
1731                                        }
1732                                } else {
1733                                        // check if this subject is a member of this eventGroup
1734                                        if (eventGroup.subjects.find { it.equals(subject) }) {
1735                                                // remove from eventGroup
1736                                                eventGroup.removeFromSubjects(subject)
1737
1738                                                // iterate through samplingEvents
1739                                                eventGroup.samplingEvents.each() { samplingEvent ->
1740                                                        flow.study.samples.findAll { (it.parentEvent.equals(samplingEvent) && it.parentSubject.equals(subject) && it.parentEventGroup.equals(eventGroup)) }.each() {
1741                                                                // delete this sample
1742                                                                flow.study.deleteSample( it )
1743                                                        }
1744                                                }
1745                                        }
1746                                }
1747                        }
1748                }
1749        }
1750
1751        /**
1752         * Handle the wizard samples page
1753         *
1754         * @param Map LocalAttributeMap (the flow scope)
1755         * @param Map localAttributeMap (the flash scope)
1756         * @param Map GrailsParameterMap (the flow parameters = form data)
1757         * @returns boolean
1758         */
1759        def samplePage(flow, flash, params) {
1760                def errors = false
1761                flash.wizardErrors = [:]
1762
1763                // remember the params in the flash scope
1764                flash.values = params
1765
1766                // iterate through samples
1767                flow.study.samples.each() { sample ->
1768                        // iterate through sample fields
1769                        sample.giveFields().each() { field ->
1770                                def value = params.get('sample_'+sample.getIdentifier()+'_'+field.escapedName())
1771
1772                                // set field value
1773                                if (!(field.name == 'name' && !value)) {
1774                                        log.info "setting "+field.name+" to "+value
1775                                        sample.setFieldValue(field.name, value)
1776                                }
1777                        }
1778
1779                        // has the template changed?
1780                        def templateName = params.get('template_' + sample.getIdentifier())
1781                        if (templateName && sample.template?.name != templateName) {
1782                                sample.template = Template.findByName(templateName)
1783                        }
1784
1785                        // validate sample
1786                        if (!sample.validate()) {
1787                                errors = true
1788                                this.appendErrors(sample, flash.wizardErrors, 'sample_' + sample.getIdentifier() + '_' )
1789                                log.info 'error-> sample_'+sample.getIdentifier()
1790                        }
1791                }
1792
1793                return !errors
1794        }
1795
1796        /**
1797         * Handle the wizard assays page
1798         *
1799         * @param Map LocalAttributeMap (the flow scope)
1800         * @param Map localAttributeMap (the flash scope)
1801         * @param Map GrailsParameterMap (the flow parameters = form data)
1802         * @returns boolean
1803         */
1804        def assayPage(flow, flash, params) {
1805                def errors = false
1806                flash.wizardErrors = [:]
1807
1808                // remember the params in the flash scope
1809                flash.values = params
1810
1811                // handle the 'add assay' form
1812                if (flow.assay) {
1813                        flow.assay.giveFields().each() { field ->
1814                                // set field
1815                                flow.assay.setFieldValue(
1816                                        field.name,
1817                                        params.get(field.escapedName())
1818                                )
1819                        }
1820                }
1821
1822                // handle the assay data
1823                flow.study.assays.each() { assay ->
1824                        // set data
1825                        assay.giveFields().each() { field ->
1826                                assay.setFieldValue(
1827                                        field.name,
1828                                        params.get( 'assay_' + assay.getIdentifier() + '_' + field.escapedName() )
1829                                )
1830                        }
1831
1832                        // validate assay
1833                        if (!assay.validate()) {
1834                                errors = true
1835                                this.appendErrors(assay, flash.wizardErrors, 'assay_' + assay.getIdentifier() + '_')
1836                        }
1837                }
1838
1839                return !errors
1840        }
1841
1842        /**
1843         * Handle the wizard assayGroups page
1844         *
1845         * @param Map LocalAttributeMap (the flow scope)
1846         * @param Map localAttributeMap (the flash scope)
1847         * @param Map GrailsParameterMap (the flow parameters = form data)
1848         * @returns boolean
1849         */
1850        def assayGroupPage(flow, flash, params) {
1851                def errors = false
1852                flash.wizardErrors = [:]
1853
1854                // remember the params in the flash scope
1855                flash.values = params
1856
1857                // iterate through samples
1858                flow.study.samples.each() { sample ->
1859                        // iterate through assays
1860                        flow.study.assays.each() { assay ->
1861                                if (params.get( 'sample_' + sample.getIdentifier() + '_assay_' + assay.getIdentifier() )) {
1862                                        // add sample to assay
1863                                        assay.addToSamples( sample )
1864                                } else {
1865                                        // remove sample from assay
1866                                        assay.removeFromSamples( sample )
1867                                }
1868                        }
1869                }
1870
1871                return !errors
1872        }
1873
1874        /**
1875         * groovy / java equivalent of php's ucwords function
1876         *
1877         * Capitalize all first letters of separate words
1878         *
1879         * @param String
1880         * @return String
1881         */
1882        public static ucwords(String text) {
1883                def newText = ''
1884
1885                // change case to lowercase
1886                text = text.toLowerCase()
1887
1888                // iterate through words
1889                text.split(" ").each() {
1890                        newText += it[0].toUpperCase() + it.substring(1) + " "
1891                }
1892
1893                return newText.substring(0, newText.size()-1)
1894        }
1895
1896        /**
1897         * return the object from a map of objects by searching for a name
1898         * @param String name
1899         * @param Map map of objects
1900         * @return Object
1901         */
1902        def getObjectByName(name, map) {
1903                def result = null
1904                map.each() {
1905                        if (it.name == name) {
1906                                result = it
1907                        }
1908                }
1909
1910                return result
1911        }
1912
1913        /**
1914         * transform domain class validation errors into a human readable
1915         * linked hash map
1916         * @param object validated domain class
1917         * @return object  linkedHashMap
1918         */
1919        def getHumanReadableErrors(object) {
1920                def errors = [:]
1921                object.errors.getAllErrors().each() { error ->
1922                        // error.codes.each() { code -> println code }
1923
1924                        // generally speaking g.message(...) should work,
1925                        // however it fails in some steps of the wizard
1926                        // (add event, add assay, etc) so g is not always
1927                        // availably. Using our own instance of the
1928                        // validationTagLib instead so it is always
1929                        // available to us
1930                        errors[ error.getArguments()[0] ] = validationTagLib.message(error: error)
1931                }
1932
1933                return errors
1934        }
1935
1936        /**
1937         * append errors of a particular object to a map
1938         * @param object
1939         * @param map linkedHashMap
1940         * @void
1941         */
1942        def appendErrors(object, map) {
1943                this.appendErrorMap(getHumanReadableErrors(object), map)
1944        }
1945
1946        def appendErrors(object, map, prepend) {
1947                this.appendErrorMap(getHumanReadableErrors(object), map, prepend)
1948        }
1949
1950        /**
1951         * append errors of one map to another map
1952         * @param map linkedHashMap
1953         * @param map linkedHashMap
1954         * @void
1955         */
1956        def appendErrorMap(map, mapToExtend) {
1957                map.each() {key, value ->
1958                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
1959                }
1960        }
1961
1962        def appendErrorMap(map, mapToExtend, prepend) {
1963                map.each() {key, value ->
1964                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
1965                }
1966        }
1967
1968        /**
1969         * Parses a RelTime string and returns a nice human readable string
1970         *
1971         * @return Human Readable string or a HTTP response code 400 on error
1972         */
1973        def ajaxParseRelTime = {
1974                if (params.reltime == null) {
1975                        response.status = 400
1976                        render('reltime parameter is expected')
1977                }
1978
1979                try {
1980                        def reltime = RelTime.parseRelTime(params.reltime)
1981                        render reltime.toPrettyString()
1982                } catch (IllegalArgumentException e) {
1983                        response.status = 400
1984                        render(e.getMessage())
1985                }
1986        }
1987
1988        /**
1989         * Proxy for searching PubMed articles (or other articles from the Entrez DB).
1990         *
1991         * This proxy is needed because it is not allowed to fetch XML directly from a different
1992         * domain using javascript. So we have the javascript call a function on our own domain
1993         * and the proxy will fetch the data from Entrez
1994         *
1995         * @since       20100609
1996         * @param       _utility        The name of the utility, without the complete path. Example: 'esearch.fcgi'
1997         * @return      XML
1998         */
1999        def entrezProxy = {
2000                // Remove unnecessary parameters
2001                params.remove( "action" )
2002                params.remove( "controller" )
2003
2004                def url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils";
2005                def util = params.remove( "_utility" )
2006                def paramString = params.collect { k, v -> k + '=' + v.encodeAsURL() }.join( '&' );
2007
2008                def fullUrl = url + '/' + util + '?' + paramString;
2009
2010                // Return the output of the request
2011                // render fullUrl;
2012                render(
2013                    text:           new URL( fullUrl ).getText(),
2014                    contentType:    "text/xml",
2015                    encoding:       "UTF-8"
2016                );
2017        }
2018}
Note: See TracBrowser for help on using the repository browser.