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

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