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

Last change on this file since 1659 was 1659, checked in by s.h.sikkema@…, 10 years ago

Measurements are selected by default in assay excel exporter

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