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

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