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

Last change on this file since 862 was 862, checked in by duh, 14 years ago
  • adding assay grouping page
  • Property svn:keywords set to Date Author Rev
File size: 36.2 KB
Line 
1package dbnp.studycapturing
2
3import dbnp.data.*
4
5// Grails convertors is imported in order to create JSON objects
6import grails.converters.*
7
8
9/**
10 * Wizard Controler
11 *
12 * The wizard controller handles the handeling of pages and data flow
13 * through the study capturing wizard.
14 *
15 * @author Jeroen Wesbeek
16 * @since 20100107
17 * @package studycapturing
18 *
19 * Revision information:
20 * $Rev: 862 $
21 * $Author: duh $
22 * $Date: 2010-08-30 14:16:31 +0000 (ma, 30 aug 2010) $
23 */
24class WizardController {
25        /**
26         * index method, redirect to the webflow
27         * @void
28         */
29        def index = {
30                def jump = [:]
31
32                // allow quickjumps to:
33                //      edit a study    : /wizard?jump=edit&id=1
34                //      create a study  : /wizard?jump=create
35                if (params.get('jump')) {
36                        switch (params.get('jump')) {
37                                case 'create':
38                                        jump = [
39                                            action: 'create'
40                                        ]
41                                        break
42                                case 'edit':
43                                        jump = [
44                                            action      : 'edit',
45                                                id              : params.get('id')
46                                        ]
47                                        break
48                                default:
49                                        break
50                        }
51                }
52
53                // store in session
54                session.jump = jump
55
56                /**
57                 * Do you believe it in your head?
58                 * I can go with the flow
59                 * Don't say it doesn't matter (with the flow) matter anymore
60                 * I can go with the flow (I can go)
61                 * Do you believe it in your head?
62                 */
63                redirect(action: 'pages')
64        }
65
66        /**
67         * WebFlow definition
68         * @see http://grails.org/WebFlow
69         * @void
70         */
71        def pagesFlow = {
72                // start the flow
73                onStart {
74                        // define flow variables
75                        flow.page = 0
76                        flow.pages = [
77                                //[title: 'Templates'],                 // templates
78                                [title: 'Start'],                               // load or create a study
79                                [title: 'Study'],                               // study
80                                [title: 'Subjects'],                    // subjects
81                                [title: 'Events'],                              // events and event grouping
82                                //[title: 'Event Groups'],              // groups
83                                [title: 'Samples'],                             // samples
84                                [title: 'Assays'],                              // assays
85                                //[title: 'Assay Groups'],              // assays
86                                [title: 'Confirmation'],                // confirmation page
87                                [title: 'Done']                                 // finish page
88                        ]
89                        flow.jump = session.jump
90                        success()
91                }
92
93                // render the main wizard page which immediately
94                // triggers the 'next' action (hence, the main
95                // page dynamically renders the study template
96                // and makes the flow jump to the study logic)
97                mainPage {
98                        render(view: "/wizard/index")
99                        onRender {
100                                flow.page = 1
101                                success()
102                        }
103                        on("next").to "handleJump"
104                }
105
106                // handle the jump parameter
107                //
108                // I came to get down [2x]
109                // So get out your seats and jump around
110                // Jump around [3x]
111                // Jump up Jump up and get down
112                // Jump [18x]
113                handleJump {
114                        action {
115                                if (flow.jump && flow.jump.action == 'edit' && flow.jump.id) {
116                                        // load study
117                                        if (this.loadStudy(flow, flash, [studyid:flow.jump.id])) {
118                                                toStudyPage()
119                                        } else {
120                                                toStartPage()
121                                        }
122                                } else if (flow.jump && flow.jump.action == 'create') {
123                                        toStudyPage()
124                                } else {
125                                        toStartPage()
126                                }
127                        }
128                        on("toStartPage").to "start"
129                        on("toStudyPage").to "study"
130                }
131
132                // create or modify a study
133                start {
134                        render(view: "_start")
135                        onRender {
136                                flow.page = 1
137                                success()
138                        }
139                        on("next") {
140                                // clean the flow scope
141                                flow.remove('study')
142
143                                // set 'quicksave' variable to false
144                                flow.quickSave = false
145                        }.to "study"
146                        on("modify").to "modify"
147                        on("import").to "redirectToImport"
148                }
149
150                // redirect to the import wizard
151                redirectToImport {
152                        render(view: "_redirect")
153                        onRender {
154                                flash.uri = "/importer/index"
155                        }
156                        on("next").to "start"
157                }
158
159                // load a study to modify
160                modify {
161                        render(view: "_modify")
162                        onRender {
163                                flow.page = 1
164                                flash.cancel = true
165                                success()
166                        }
167                        on("cancel") {
168                                flow.remove('study')
169
170                                success()
171                        }.to "start"
172                        on("next") {
173                                // load study
174                                if (this.loadStudy(flow, flash, params)) {
175                                        success()
176                                } else {
177                                        error()
178                                }
179                        }.to "study"
180                }
181
182                // render and handle the study page
183                study {
184                        render(view: "_study")
185                        onRender {
186                                flow.page = 2
187                                success()
188                        }
189                        on("refresh") {
190                                // handle form data
191                                studyPage(flow, flash, params)
192
193                                // force refresh of the template
194                                if (flow.study.template && flow.study.template instanceof Template) {
195                                        flow.study.template.refresh()
196                                }
197
198                                // reset errors
199                                flash.errors = [:]
200                                success()
201                        }.to "study"
202            on("switchTemplate") {
203                                // handle form data
204                                studyPage(flow, flash, params)
205
206                                // reset errors
207                                flash.errors = [:]
208                                success()
209                        }.to "study"
210                        on("previous") {
211                                // handle form data
212                                studyPage(flow, flash, params)
213
214                                // reset errors
215                                flash.errors = [:]
216                                success()
217                        }.to "start"
218                        on("next") {
219                                studyPage(flow, flash, params) ? success() : error()
220                        }.to "subjects"
221                        on("quickSave") {
222                                studyPage(flow, flash, params) ? success() : error()
223                        }.to "waitForSave"
224                }
225
226                // render and handle subjects page
227                subjects {
228                        render(view: "_subjects")
229                        onRender {
230                                flow.page = 3
231
232                                if (!flash.values || !flash.values.addNumber) flash.values = [addNumber:1]
233
234                                success()
235                        }
236                        on("refresh") {
237                                // remember the params in the flash scope
238                                flash.values = params
239
240                                // refresh templates
241                                if (flow.study.subjects) {
242                                        flow.study.giveSubjectTemplates().each() {
243                                                it.refresh()
244                                        }
245                                }
246
247                                success()
248                        }.to "subjects"
249                        on("add") {
250                                // handle form data
251                                addSubjects(flow, flash, params) ? success() : error()
252                        }.to "subjects"
253                        on("delete") {
254                                // handle form data
255                                subjectPage(flow, flash, params)
256
257                                // reset errors
258                                flash.errors = [:]
259
260                                // remove subject
261                                def subjectToRemove = flow.study.subjects.find { it.identifier == (params.get('do') as int) }
262                                if (subjectToRemove) {
263                                        flow.study.deleteSubject( subjectToRemove )
264                                }
265                        }.to "subjects"
266                        on("previous") {
267                                // handle form data
268                                subjectPage(flow, flash, params)
269
270                                // reset errors
271                                flash.errors = [:]
272                                success()
273                        }.to "study"
274                        on("next") {
275                                // handle form data
276                                subjectPage(flow, flash, params) ? success() : error()
277                        }.to "events"
278                        on("quickSave") {                               
279                                // handle form data
280                                subjectPage(flow, flash, params) ? success() : error()
281                        }.to "waitForSave"
282                }
283
284                // render events page
285                events {
286                        render(view: "_events")
287                        onRender {
288                                flow.page = 4
289
290                                // add initial eventGroup to study
291                                if (!flow.study.eventGroups?.size()) {
292                                        flow.study.addToEventGroups(
293                                                new EventGroup(name: 'Group 1')
294                                        )
295                                }
296
297                                success()
298                        }
299                        on("clear") {
300                                // remove all events
301                                (flow.study.events + flow.study.samplingEvents).each() { event ->
302                                        if (event instanceof SamplingEvent) {
303                                                flow.study.deleteSamplingEvent( event )
304                                        } else {
305                                                flow.study.deleteEvent( event )
306                                        }
307                                }
308
309                                success()
310                        }.to "events"
311                        on("switchTemplate") {
312                                // handle form data
313                                eventPage(flow, flash, params)
314
315                                // get template
316                                def type        = params.get('eventType')
317                                def template= Template.findByName( params.get( type + 'Template' ) )
318
319                                // change template and/or instance?
320                                if (!flow.event || (flow.event instanceof Event && type == "sample") || (flow.event instanceof SamplingEvent && type == "event")) {
321                                        // create new instance
322                                        flow.event = (type == "event") ? new Event(template: template) : new SamplingEvent(template: template)
323                                } else {
324                                        flow.event.template = template
325                                }
326
327                                // reset errors
328                                flash.errors = [:]
329                                success()
330
331                        }.to "events"
332                        on("refresh") {
333                                // handle form data
334                                eventPage(flow, flash, params)
335
336                                // refresh templates
337                                flow.study.giveEventTemplates().each() {
338                                        it.refresh()
339                                }
340
341                                // refresh event template
342                                if (flow.event?.template) flow.event.template.refresh()
343
344                                // reset errors
345                                flash.errors = [:]
346                                success()
347                        }.to "events"
348                        on("add") {
349                                // handle form data
350                                eventPage(flow, flash, params)
351
352                                // reset errors
353                                flash.errors = [:]
354
355                                // add event to study
356                                if (flow.event instanceof SamplingEvent) {
357                                        flow.study.addToSamplingEvents( flow.event )
358                                } else {
359                                        flow.study.addToEvents( flow.event )
360                                }
361
362                                // validate event
363                                if (flow.event.validate()) {
364                                        // remove event from the flowscope
365                                        flow.remove('event')
366                                       
367                                        success()
368                                } else {
369                                        // event does not validate
370                                        // remove from study
371                                        if (flow.event instanceof SamplingEvent) {
372                                                flow.study.removeFromSamplingEvents( flow.event )
373                                        } else {
374                                                flow.study.removeFromEvents( flow.event )
375                                        }
376
377                                        // append errors
378                                        this.appendErrors(flow.event, flash.errors)
379                                        error()
380                                }
381                        }.to "events"
382                        on("deleteEvent") {
383                                // handle form data
384                                eventPage(flow, flash, params)
385
386                                // reset errors
387                                flash.errors = [:]
388
389                                // find matching (sampling) event
390                                def event                       = flow.study.events.find { it.getIdentifier() == (params.get('do') as int) }
391                                def samplingEvent       = flow.study.samplingEvents.find { it.getIdentifier() == (params.get('do') as int) }
392
393                                // perform delete
394                                if (event) flow.study.deleteEvent( event )
395                                if (samplingEvent) flow.study.deleteSamplingEvent( samplingEvent )
396                        }.to "events"
397                        on("addEventGroup") {
398                                // handle form data
399                                eventPage(flow, flash, params)
400
401                                // set work variables
402                                def groupName = 'Group '
403                                def tempGroupIterator = 1
404                                def tempGroupName = groupName + tempGroupIterator
405
406                                // make sure group name is unique
407                                if (flow.study.eventGroups) {
408                                        while (flow.study.eventGroups.find { it.name == tempGroupName }) {
409                                                tempGroupIterator++
410                                                tempGroupName = groupName + tempGroupIterator
411                                        }
412                                }
413                                groupName = tempGroupName
414
415                                // add a new eventGroup
416                                flow.study.addToEventGroups(
417                                        new EventGroup(
418                                                name    : groupName
419                                        )
420                                )
421
422                                // reset errors
423                                flash.errors = [:]
424                                success()
425                        }.to "events"
426                        on("deleteEventGroup") {
427                                // handle form data
428                                eventPage(flow, flash, params)
429
430                                // reset errors
431                                flash.errors = [:]
432
433                                // remove eventGroup
434                                def eventGroupToRemove = flow.study.eventGroups.find { it.getIdentifier() == (params.get('do') as int) }
435                                if (eventGroupToRemove) {
436                                        println flow.study.deleteEventGroup( eventGroupToRemove )
437                                }
438                        }.to "events"
439                        on("previous") {
440                                // handle form data
441                                eventPage(flow, flash, params)
442
443                                // reset errors
444                                flash.errors = [:]
445                                success()
446                        }.to "subjects"
447                        on("next") {
448                                // handle form data
449                                eventPage(flow, flash, params) ? success() : error()
450                        }.to "groups"
451                        on("quickSave") {
452                                // handle form data
453                                eventPage(flow, flash, params) ? success() : error()
454                        }.to "waitForSave"
455                }
456
457                // groups page
458                groups {
459                        render(view: "_groups")
460                        onRender {
461                                flow.page = 4
462                                success()
463                        }
464                        on("previous") {
465                                // handle form data
466                                groupPage(flow, flash, params) ? success() : error()
467                        }.to "events"
468                        on("next") {
469                                // handle form data
470                                groupPage(flow, flash, params) ? success() : error()
471                        }.to "samples"
472                        on("quickSave") {
473                                // handle form data
474                                groupPage(flow, flash, params) ? success() : error()
475                        }.to "waitForSave"
476                }
477
478                // sample 'previous' page with warning
479                samplePrevious {
480                        render(view: "_samples_previous_warning")
481                        onRender {
482                                flow.page = 5
483
484                                // TEMPORARY FIX TO REMOVE ALL SAMPLES AND REGENERATE THEM
485                                // THEN USER BROWSED BACK
486                                println ".removing samples from study"
487
488                                // remove samples from study
489                                flow.samples.each() {
490                                        flow.study.removeFromSamples(it.sample)
491                                }
492
493                                // remove samples from flow
494                                flow.remove('samples')
495                                // END FIX
496                        }
497                        on("next").to "samples"
498                        on("previous").to "groups"
499                }
500
501                // samples page
502                samples {
503                        render(view: "_samples")
504                        onRender {
505                                flow.page = 5
506
507                                // got samples?
508                                if (!flow.study.samples) {
509                                        // generate samples
510                                        // iterate through eventGroups
511                                        flow.study.eventGroups.each() { eventGroup ->
512                                                // iterate through samplingEvents
513                                                eventGroup.samplingEvents.each() { samplingEvent ->
514                                                        println samplingEvent
515                                                        println samplingEvent.sampleTemplate
516                                                        println samplingEvent.sampleTemplate.getClass()
517
518                                                        def samplingEventName = this.ucwords(samplingEvent.template.name)
519
520                                                        // iterate through subjects
521                                                        eventGroup.subjects.each() { subject ->
522                                                                def sampleName = (this.ucwords(subject.name) + '_' + samplingEventName + '_' + new RelTime(samplingEvent.startTime).toString()).replaceAll("([ ]{1,})", "")
523                                                                def tempSampleIterator = 0
524                                                                def tempSampleName = sampleName
525
526                                                                // make sure sampleName is unique
527                                                                if (flow.study.samples) {
528                                                                        while (flow.study.samples.find { it.name == tempSampleName }) {
529                                                                                tempSampleIterator++
530                                                                                tempSampleName = sampleName + "_" + tempSampleIterator
531                                                                        }
532                                                                        sampleName = tempSampleName
533                                                                }
534
535                                                                // instantiate a sample
536                                                                flow.study.addToSamples(
537                                                                        new Sample(
538                                                                                parentSubject: subject,
539                                                                                parentEvent: samplingEvent,
540                                                                                name: sampleName,
541                                                                                template: (samplingEvent.sampleTemplate) ? samplingEvent.sampleTemplate : ''
542                                                                        )
543                                                                )
544                                                        }
545                                                }
546
547                                        }
548                                }
549
550                                success()
551                        }
552                        on("switchTemplate") {
553                                // handle form data
554                                samplePage(flow, flash, params)
555
556                                // ignore errors
557                                flash.errors = [:]
558                               
559                                succes()
560                        }.to "samples"
561                        on("refresh") {
562                                // handle samples
563                                handleSamples(flow, flash, params)
564
565                                // refresh all sample templates
566                                flow.study.giveSampleTemplates().each() {
567                                        it.refresh()
568                                }
569
570                                // ignore errors
571                                flash.errors = [:]
572
573                                success()
574                        }.to "samples"
575                        on("regenerate") {
576                                // handle samples
577                                handleSamples(flow, flash, params)
578
579                                // remove all samples from the study
580                                flow.study.samples.findAll{true}.each() { sample ->
581                                        flow.study.removeFromSamples(sample)
582                                }
583
584                                // ignore errors
585                                flash.errors = [:]
586
587                                success()
588                        }.to "samples"
589                        on("previous") {
590                                // handle samples
591                                handleSamples(flow, flash, params)
592
593                                // ignore errors
594                                flash.errors = [:]
595
596                                success()
597                        }.to "samplePrevious"
598                        on("next") {
599                                // handle form data
600                                samplePage(flow, flash, params) ? success() : error()
601                        }.to "assays"
602                        on("quickSave") {
603                                // handle form data
604                                samplePage(flow, flash, params) ? success() : error()
605                        }.to "waitForSave"
606                }
607
608                // assays page
609                assays {
610                        render(view: "_assays")
611                        onRender {
612                                flow.page = 6
613                        }
614                        on("refresh") {
615                                // handle form data
616                                assayPage(flow, flash, params)
617
618                                // force refresh of the template
619                                if (flow.assay && flow.assay.template && flow.assay.template instanceof Template) {
620                                        flow.assay.template.refresh()
621                                }
622
623                                // reset errors
624                                flash.errors = [:]
625                                success()
626                        }.to "assays"
627            on("switchTemplate") {
628                                // handle form data
629                                assayPage(flow, flash, params)
630
631                                // find assay template
632                                def template = Template.findByName( params.get('template') )
633
634                                if (flow.assay) {
635                                        // set template
636                                        flow.assay.template = template
637                                } else {
638                                        // create a new assay instance
639                                        flow.assay = new Assay(template: template)
640                                }
641
642                                // reset errors
643                                flash.errors = [:]
644                                success()
645                        }.to "assays"
646                        on("add") {
647                                // handle form data
648                                assayPage(flow, flash, params)
649
650                                // reset errors
651                                flash.errors = [:]
652
653                                // add assay to study
654                                flow.study.addToAssays( flow.assay )
655
656                                // validate assay
657                                if (flow.assay.validate()) {
658                                        // remove assay from the flowscope
659                                        flow.remove('assay')
660                                        success()
661                                } else {
662                                        // assay does not validate
663                                        // remove from study
664                                        flow.study.removeFromAssays( flow.assay )
665
666                                        // append errors
667                                        this.appendErrors(flow.assay, flash.errors)
668                                        error()
669                                }
670                        }.to "assays"
671                        on("deleteAssay") {
672                                // handle form data
673                                assayPage(flow, flash, params)
674
675                                // reset errors
676                                flash.errors = [:]
677
678                                // find this assay
679                                def assay = flow.study.assays.find { it.getIdentifier() == (params.get('do') as int) }
680
681                                // perform delete
682                                if (assay) flow.study.deleteAssay( assay )
683                        }.to "assays"
684                        on("previous") {
685                                // handle form data
686                                assayPage(flow, flash, params)
687
688                                // ignore errors
689                                flash.errors = [:]
690
691                                success()
692                        }.to "samples"
693                        on("next") {
694                                // handle form data
695                                assayPage(flow, flash, params) ? success() : error()
696                        }.to "assayGroups"
697                        on("quickSave") {
698                                // handle form data
699                                assayPage(flow, flash, params) ? success() : error()
700                        }.to "waitForSave"
701                }
702
703                // assay grouping page
704                assayGroups {
705                        render(view: "_assay_groups")
706                        onRender {
707                                flow.page = 6
708                        }
709                        on("previous") {
710                                // handle form data
711                                assayGroupPage(flow, flash, params)
712
713                                // ignore errors
714                                flash.errors = [:]
715
716                                success()
717                        }.to "assays"
718                        on("next") {
719                                // handle form data
720                                assayGroupPage(flow, flash, params) ? success() : error()
721                        }.to "confirm"
722                        on("quickSave") {
723                                // handle form data
724                                assayGroupPage(flow, flash, params) ? success() : error()
725                        }.to "waitForSave"
726                }
727
728                // confirmation
729                confirm {
730                        render(view: "_confirmation")
731                        onRender {
732                                flow.page = 7
733                        }
734                        on("toStudy").to "study"
735                        on("toSubjects").to "subjects"
736                        on("toEvents").to "events"
737                        on("toGroups").to "groups"
738                        on("previous").to "samples"
739                        on("next").to "waitForSave"
740                        on("quickSave").to "waitForSave"
741                }
742
743                waitForSave {
744                        render(view: "_wait")
745                        onRender {
746                                flow.page = 8
747                        }
748                        on("next").to "save"
749                }
750
751                // store all study data
752                save {
753                        action {
754                                println "saving..."
755                                flash.errors = [:]
756
757                                // persist data to the database
758                                try {
759                                        // save study
760                                        println ".saving study"
761                                        if (!flow.study.save(flush:true)) {
762                                                this.appendErrors(flow.study, flash.errors)
763                                                throw new Exception('error saving study')
764                                        }
765                                        println ".saved study "+flow.study+" (id: "+flow.study.id+")"
766
767                                        success()
768                                } catch (Exception e) {
769                                        // rollback
770                                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace' ], flash.errors)
771
772                                        // stacktrace in flash scope
773                                        flash.debug = e.getStackTrace()
774
775                                        error()
776                                }
777                        }
778                        on("error").to "error"
779                        on(Exception).to "error"
780                        on("success").to "done"
781                }
782
783                // error storing data
784                error {
785                        render(view: "_error")
786                        onRender {
787                                flow.page = 7
788                        }
789                        on("next").to "waitForSave"
790                        on("previous").to "samples"
791                }
792
793                // render finish page
794                done {
795                        render(view: "_done")
796                        onRender {
797                                flow.page = 8
798                        }
799                        onEnd {
800                                // clean flow scope
801                                flow.clear()
802                        }
803                }
804        }
805
806        /**
807         * load a study
808         * @param Map LocalAttributeMap (the flow scope)
809         * @param Map localAttributeMap (the flash scope)
810         * @param Map GrailsParameterMap (the flow parameters = form data)
811         * @returns boolean
812         */
813        def loadStudy(flow, flash, params) {
814                // load study
815                try {
816                        // load study
817                        flow.study = (params.studyid) ? Study.findById( params.studyid ) : Study.findByTitle( params.study )
818
819                        // set 'quicksave' variable
820                        flow.quickSave = true
821
822                        return true
823                } catch (Exception e) {
824                        // rollback
825                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace'], flash.errors)
826
827                        return false
828                }
829        }
830
831        /**
832         * Handle the wizard study page
833         *
834         * @param Map LocalAttributeMap (the flow scope)
835         * @param Map localAttributeMap (the flash scope)
836         * @param Map GrailsParameterMap (the flow parameters = form data)
837         * @returns boolean
838         */
839        def studyPage(flow, flash, params) {
840                // remember the params in the flash scope
841                flash.values = params
842               
843                // instantiate study of it is not yet present
844                if (!flow.study) flow.study = new Study()
845
846                // did the study template change?
847                if (params.get('template').size() && flow.study.template?.name != params.get('template')) {
848                        println ".change study template!"
849
850                        // yes, was the template already set?
851                        if (flow.study.template instanceof Template) {
852                                // yes, first make sure all values are unset?
853                                println "!!! check the database fields if data of a previous template remains in the database or is deleted by GORM!"
854                        }
855
856                        // set the template
857                        flow.study.template = Template.findByName(params.remove('template'))
858                }
859
860                // does the study have a template set?
861                if (flow.study.template && flow.study.template instanceof Template) {
862                        // yes, iterate through template fields
863                        flow.study.giveFields().each() {
864                                // and set their values
865                                flow.study.setFieldValue(it.name, params.get(it.escapedName()))
866                        }
867                }
868
869                // handle publications
870                handlePublications(flow, flash, params)
871
872                // handle contacts
873                handleContacts(flow, flash, params)
874
875                // validate the study
876                if (flow.study.validate()) {
877                        // instance is okay
878                        return true
879                } else {
880                        // validation failed
881                        flash.errors = [:]
882                        this.appendErrors(flow.study, flash.errors)
883                        return false
884                }
885        }
886
887        /**
888         * re-usable code for handling publications form data in a web flow
889         * @param Map LocalAttributeMap (the flow scope)
890         * @param Map localAttributeMap (the flash scope)
891         * @param Map GrailsParameterMap (the flow parameters = form data)
892         * @returns boolean
893         */
894        def handlePublications(flow, flash, params) {
895                if (!flow.study.publications) flow.study.publications = []
896
897                // Check the ids of the pubblications that should be attached
898                // to this study. If they are already attached, keep 'm. If
899                // studies are attached that are not in the selected (i.e. the
900                // user deleted them), remove them
901                def publicationIDs = params.get('publication_ids')
902                if (publicationIDs) {
903                        // Find the individual IDs and make integers
904                        publicationIDs = publicationIDs.split(',').collect { Integer.parseInt(it, 10) }
905
906                        // First remove the publication that are not present in the array
907                        flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
908
909                        // Add those publications not yet present in the database
910                        publicationIDs.each { id ->
911                                if (!flow.study.publications.find { publication -> id == publication.id }) {
912                                        def publication = Publication.get(id)
913                                        if (publication) {
914                                                flow.study.addToPublications(publication)
915                                        } else {
916                                                println('.publication with ID ' + id + ' not found in database.')
917                                        }
918                                }
919                        }
920
921                } else {
922                        println('.no publications selected.')
923                        flow.study.publications.clear()
924                }
925
926        }
927
928        /**
929         * re-usable code for handling contacts form data in a web flow
930         * @param Map LocalAttributeMap (the flow scope)
931         * @param Map localAttributeMap (the flash scope)
932         * @param Map GrailsParameterMap (the flow parameters = form data)
933         * @return boolean
934         */
935        def handleContacts(flow, flash, params) {
936                if (!flow.study.persons) flow.study.persons = []
937
938                // Check the ids of the contacts that should be attached
939                // to this study. If they are already attached, keep 'm. If
940                // studies are attached that are not in the selected (i.e. the
941                // user deleted them), remove them
942
943                // Contacts are saved as [person_id]-[role_id]
944                def contactIDs = params.get('contacts_ids')
945                if (contactIDs) {
946                        // Find the individual IDs and make integers
947                        contactIDs = contactIDs.split(',').collect {
948                                def parts = it.split('-')
949                                return [person: Integer.parseInt(parts[0]), role: Integer.parseInt(parts[1])]
950                        }
951
952                        // First remove the contacts that are not present in the array
953                        flow.study.persons.removeAll {
954                                studyperson -> !contactIDs.find { ids -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }
955                        }
956
957                        // Add those contacts not yet present in the database
958                        contactIDs.each { ids ->
959                                if (!flow.study.persons.find { studyperson -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }) {
960                                        def person = Person.get(ids.person)
961                                        def role = PersonRole.get(ids.role)
962                                        if (person && role) {
963                                                // Find a studyperson object with these parameters
964                                                def studyPerson = StudyPerson.findAll().find { studyperson -> studyperson.person.id == person.id && studyperson.role.id == role.id }
965
966                                                // If if does not yet exist, save the example
967                                                if (!studyPerson) {
968                                                        studyPerson = new StudyPerson(
969                                                                person: person,
970                                                                role: role
971                                                        )
972                                                        studyPerson.save(flush: true)
973                                                }
974
975                                                flow.study.addToPersons(studyPerson)
976                                        } else {
977                                                println('.person ' + ids.person + ' or Role ' + ids.role + ' not found in database.')
978                                        }
979                                }
980                        }
981                } else {
982                        println('.no persons selected.')
983                        flow.study.persons.clear()
984                }
985
986        }
987                                                 
988        /**
989         * Handle the wizard subject page
990         *
991         * @param Map LocalAttributeMap (the flow scope)
992         * @param Map localAttributeMap (the flash scope)
993         * @param Map GrailsParameterMap (the flow parameters = form data)
994         * @returns boolean
995         */
996        def subjectPage(flow, flash, params) {
997                def errors = false
998                flash.errors = [:]
999
1000                // remember the params in the flash scope
1001                flash.values = params
1002
1003                // iterate through subjects
1004                flow.study.subjects.each() { subject ->
1005                        // iterate through (template and domain) fields
1006                        subject.giveFields().each() { field ->
1007                                // set field
1008                                subject.setFieldValue(
1009                                        field.name,
1010                                        params.get('subject_' + subject.getIdentifier() + '_' + field.escapedName())
1011                                )
1012                        }
1013
1014                        // validate subject
1015                        if (!subject.validate()) {
1016                                errors = true
1017                                this.appendErrors(subject, flash.errors, 'subject_' + subject.getIdentifier() + '_')
1018                        }
1019                }
1020
1021                return !errors
1022        }
1023
1024        /**
1025         * Add a number of subjects to a study
1026         *
1027         * required params entities:
1028         * -addNumber (int)
1029         * -species   (string)
1030         * -template  (string)
1031         *
1032         * @param Map LocalAttributeMap (the flow scope)
1033         * @param Map localAttributeMap (the flash scope)
1034         * @param Map GrailsParameterMap (the flow parameters = form data)
1035         * @returns boolean
1036         */
1037        def addSubjects(flow, flash, params) {
1038                // remember the params in the flash scope
1039                flash.values = params
1040
1041                // handle the subject page
1042                subjectPage(flow, flash, params)
1043
1044                // (re)set error message
1045                flash.errors = [:]
1046
1047                // set work variables
1048                def errors              = false
1049                def number              = params.get('addNumber') as int
1050                def species             = Term.findByName(params.get('species'))
1051                def template    = Template.findByName(params.get('template'))
1052
1053                // can we add subjects?
1054                if (number > 0 && species && template) {
1055                        // add subjects to study
1056                        number.times {
1057                                // work variables
1058                                def subjectName = 'Subject '
1059                                def subjectIterator = 1
1060                                def tempSubjectName = subjectName + subjectIterator
1061
1062                                // make sure subject name is unique
1063                                if (flow.study.subjects) {
1064                                        while (flow.study.subjects.find { it.name == tempSubjectName }) {
1065                                                subjectIterator++
1066                                                tempSubjectName = subjectName + subjectIterator
1067                                        }
1068                                }
1069                                subjectName = tempSubjectName
1070                               
1071                                // create a subject instance
1072                                def subject = new Subject(
1073                                        name            : subjectName,
1074                                        species         : species,
1075                                        template        : template
1076                                )
1077
1078                                // add it to the study
1079                                flow.study.addToSubjects( subject )
1080
1081                                // validate subject
1082                                if (subject.validate()) {
1083                                        println ".added subject "+subject
1084                                } else {
1085                                        // whoops?
1086                                        flow.study.removeFromSubjects( subject )
1087
1088                                        // append errors
1089                                        this.appendErrors(subject, flash.errors)
1090                                        errors = true
1091                                }
1092                        }
1093                } else {
1094                        // add feedback
1095                        errors = true
1096                        if (number < 1) this.appendErrorMap(['addNumber': 'Enter a positive number of subjects to add'], flash.errors)
1097                        if (!species)   this.appendErrorMap(['species': 'You need to select a species, or add one if it is not yet present'], flash.errors)
1098                        if (!template)  this.appendErrorMap(['template': 'You need to select a template, or add one if it is not yet present'], flash.errors)
1099                }
1100
1101                return !errors
1102        }
1103
1104        /**
1105         * Handle the wizard event page
1106         *
1107         * @param Map LocalAttributeMap (the flow scope)
1108         * @param Map localAttributeMap (the flash scope)
1109         * @param Map GrailsParameterMap (the flow parameters = form data)
1110         * @returns boolean
1111         */
1112        def eventPage(flow, flash, params) {
1113                def errors = false
1114                flash.errors = [:]
1115
1116                // remember the params in the flash scope
1117                flash.values = params
1118
1119                // handle the 'add event' form
1120                if (flow.event) {
1121                        flow.event.giveFields().each() { field ->
1122                                // set field
1123                                flow.event.setFieldValue(
1124                                        field.name,
1125                                        params.get(field.escapedName())
1126                                )
1127                        }
1128                }
1129
1130                // handle the eventGroup names and grouping
1131                def name        = ""
1132                def tempName= ""
1133                flow.study.eventGroups.each() { eventGroup ->
1134                        // iterate through templates
1135                        flow.study.giveAllEventTemplates().each() { template ->
1136                                tempName = params.get( 'eventGroup_' + eventGroup.getIdentifier() + '_' + template.getIdentifier() )
1137
1138                                // is the name different?
1139                                if (tempName != eventGroup.name) {
1140                                        name = tempName
1141                                }
1142                        }
1143
1144                        // should the name change?
1145                        if (name) {
1146                                // yes, change it
1147                                eventGroup.name = name
1148                                name = ""
1149                        }
1150
1151                        // handle eventGrouping
1152                        ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
1153                                if (params.get( 'event_' + event.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
1154                                        // add to eventGroup
1155                                        if (event instanceof SamplingEvent) {
1156                                                eventGroup.addToSamplingEvents(event)
1157                                        } else {
1158                                                eventGroup.addToEvents(event)
1159                                        }
1160                                } else {
1161                                        // remove from eventGroup
1162                                        if (event instanceof SamplingEvent) {
1163                                                eventGroup.removeFromSamplingEvents(event)
1164                                        } else {
1165                                                eventGroup.removeFromEvents(event)
1166                                        }
1167                                }
1168                        }
1169                }
1170
1171                // handle the (sampling) events
1172                ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
1173                        event.giveFields().each() { field ->
1174                                event.setFieldValue(
1175                                        field.name,
1176                                        params.get( 'event_' + event.getIdentifier() + '_' + field.escapedName() )
1177                                )
1178                        }
1179
1180                        // validate event
1181                        if (!event.validate()) {
1182                                errors = true
1183                                this.appendErrors(event, flash.errors)
1184                        }
1185                }
1186
1187                return !errors
1188        }
1189
1190        /**
1191         * Handle the wizard group page
1192         *
1193         * @param Map LocalAttributeMap (the flow scope)
1194         * @param Map localAttributeMap (the flash scope)
1195         * @param Map GrailsParameterMap (the flow parameters = form data)
1196         * @returns boolean
1197         */
1198        def groupPage(flow, flash, params) {
1199                def errors = false
1200                flash.errors = [:]
1201
1202                // remember the params in the flash scope
1203                flash.values = params
1204
1205                // iterate through groups
1206                flow.study.eventGroups.each() { eventGroup ->
1207                        // iterate through subjects
1208                        flow.study.subjects.each() { subject ->
1209                                if (params.get('subject_' + subject.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
1210                                        // add to eventGroup
1211                                        eventGroup.addToSubjects(subject)
1212                                } else {
1213                                        // remove from eventGroup
1214                                        eventGroup.removeFromSubjects(subject)
1215                                }
1216                        }
1217                }
1218        }
1219
1220        /**
1221         * Handle the wizard samples page
1222         *
1223         * @param Map LocalAttributeMap (the flow scope)
1224         * @param Map localAttributeMap (the flash scope)
1225         * @param Map GrailsParameterMap (the flow parameters = form data)
1226         * @returns boolean
1227         */
1228        def samplePage(flow, flash, params) {
1229                def errors = false
1230                flash.errors = [:]
1231
1232                // remember the params in the flash scope
1233                flash.values = params
1234
1235                // iterate through samples
1236                flow.study.samples.each() { sample ->
1237                        // iterate through sample fields
1238                        sample.giveFields().each() { field ->
1239                                def value = params.get('sample_'+sample.getIdentifier()+'_'+field.escapedName())
1240
1241                                // set field value
1242                                if (!(field.name == 'name' && !value)) {
1243                                        println "setting "+field.name+" to "+value
1244                                        sample.setFieldValue(field.name, value)
1245                                }
1246                        }
1247
1248                        // has the template changed?
1249                        def templateName = params.get('template_' + sample.getIdentifier())
1250                        if (templateName && sample.template?.name != templateName) {
1251                                sample.template = Template.findByName(templateName)
1252                        }
1253
1254                        // validate sample
1255                        if (!sample.validate()) {
1256                                errors = true
1257                                this.appendErrors(sample, flash.errors, 'sample_' + sample.getIdentifier() + '_' )
1258                                println 'error-> sample_'+sample.getIdentifier()
1259                        }
1260                }
1261
1262                return !errors
1263        }
1264
1265        /**
1266         * Handle the wizard assays page
1267         *
1268         * @param Map LocalAttributeMap (the flow scope)
1269         * @param Map localAttributeMap (the flash scope)
1270         * @param Map GrailsParameterMap (the flow parameters = form data)
1271         * @returns boolean
1272         */
1273        def assayPage(flow, flash, params) {
1274                def errors = false
1275                flash.errors = [:]
1276
1277                // remember the params in the flash scope
1278                flash.values = params
1279
1280                // handle the 'add assay' form
1281                if (flow.assay) {
1282                        flow.assay.giveFields().each() { field ->
1283                                // set field
1284                                flow.assay.setFieldValue(
1285                                        field.name,
1286                                        params.get(field.escapedName())
1287                                )
1288                        }
1289                }
1290
1291                // handle the assay data
1292                flow.study.assays.each() { assay ->
1293                        // set data
1294                        assay.giveFields().each() { field ->
1295                                assay.setFieldValue(
1296                                        field.name,
1297                                        params.get( 'assay_' + assay.getIdentifier() + '_' + field.escapedName() )
1298                                )
1299                        }
1300
1301                        // validate assay
1302                        if (!assay.validate()) {
1303                                errors = true
1304                                this.appendErrors(assay, flash.errors, 'assay_' + assay.getIdentifier() + '_')
1305                        }
1306                }
1307
1308                return !errors
1309        }
1310
1311        /**
1312         * Handle the wizard assayGroups page
1313         *
1314         * @param Map LocalAttributeMap (the flow scope)
1315         * @param Map localAttributeMap (the flash scope)
1316         * @param Map GrailsParameterMap (the flow parameters = form data)
1317         * @returns boolean
1318         */
1319        def assayGroupPage(flow, flash, params) {
1320                def errors = false
1321                flash.errors = [:]
1322
1323                // remember the params in the flash scope
1324                flash.values = params
1325
1326                // iterate through samples
1327                flow.study.samples.each() { sample ->
1328                        // iterate through assays
1329                        flow.study.assays.each() { assay ->
1330                                if (params.get( 'sample_' + sample.getIdentifier() + '_assay_' + assay.getIdentifier() )) {
1331                                        println "add sample "+sample.getIdentifier()+" to assay "+assay.getIdentifier()
1332                                        // add sample to assay
1333                                        assay.addToSamples( sample )
1334                                } else {
1335                                        // remove sample from assay
1336                                        assay.removeFromSamples( sample )
1337                                }
1338                                println assay.samples
1339                        }
1340                }
1341
1342                return !errors
1343        }
1344
1345        /**
1346         * groovy / java equivalent of php's ucwords function
1347         *
1348         * Capitalize all first letters of separate words
1349         *
1350         * @param String
1351         * @return String
1352         */
1353        def ucwords(String text) {
1354                def newText = ''
1355
1356                // change case to lowercase
1357                text = text.toLowerCase()
1358
1359                // iterate through words
1360                text.split(" ").each() {
1361                        newText += it[0].toUpperCase() + it.substring(1) + " "
1362                }
1363
1364                return newText.substring(0, newText.size()-1)
1365        }
1366
1367        /**
1368         * return the object from a map of objects by searching for a name
1369         * @param String name
1370         * @param Map map of objects
1371         * @return Object
1372         */
1373        def getObjectByName(name, map) {
1374                def result = null
1375                map.each() {
1376                        if (it.name == name) {
1377                                result = it
1378                        }
1379                }
1380
1381                return result
1382        }
1383
1384        /**
1385         * transform domain class validation errors into a human readable
1386         * linked hash map
1387         * @param object validated domain class
1388         * @return object  linkedHashMap
1389         */
1390        def getHumanReadableErrors(object) {
1391                def errors = [:]
1392                object.errors.getAllErrors().each() {
1393                        def message = it.toString()
1394
1395                        //errors[it.getArguments()[0]] = it.getDefaultMessage()
1396                        errors[it.getArguments()[0]] = message.substring(0, message.indexOf(';'))
1397                }
1398
1399                return errors
1400        }
1401
1402        /**
1403         * append errors of a particular object to a map
1404         * @param object
1405         * @param map linkedHashMap
1406         * @void
1407         */
1408        def appendErrors(object, map) {
1409                this.appendErrorMap(this.getHumanReadableErrors(object), map)
1410        }
1411
1412        def appendErrors(object, map, prepend) {
1413                this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend)
1414        }
1415
1416        /**
1417         * append errors of one map to another map
1418         * @param map linkedHashMap
1419         * @param map linkedHashMap
1420         * @void
1421         */
1422        def appendErrorMap(map, mapToExtend) {
1423                map.each() {key, value ->
1424                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
1425                }
1426        }
1427
1428        def appendErrorMap(map, mapToExtend, prepend) {
1429                map.each() {key, value ->
1430                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
1431                }
1432        }
1433
1434        /**
1435         * Parses a RelTime string and returns a nice human readable string
1436         *
1437         * @return Human Readable string or a HTTP response code 400 on error
1438         */
1439        def ajaxParseRelTime = {
1440                if (params.reltime == null) {
1441                        response.status = 400
1442                        render('reltime parameter is expected')
1443                }
1444
1445                try {
1446                        def reltime = RelTime.parseRelTime(params.reltime)
1447                        render reltime.toPrettyString()
1448                } catch (IllegalArgumentException e) {
1449                        response.status = 400
1450                        render(e.getMessage())
1451                }
1452        }
1453
1454        /**
1455         * Proxy for searching PubMed articles (or other articles from the Entrez DB).
1456         *
1457         * This proxy is needed because it is not allowed to fetch XML directly from a different
1458         * domain using javascript. So we have the javascript call a function on our own domain
1459         * and the proxy will fetch the data from Entrez
1460         *
1461         * @since       20100609
1462         * @param       _utility        The name of the utility, without the complete path. Example: 'esearch.fcgi'
1463         * @return      XML
1464         */
1465        def entrezProxy = {
1466                // Remove unnecessary parameters
1467                params.remove( "action" )
1468                params.remove( "controller" )
1469
1470                def url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils";
1471                def util = params.remove( "_utility" )
1472                def paramString = params.collect { k, v -> k + '=' + v.encodeAsURL() }.join( '&' );
1473
1474                def fullUrl = url + '/' + util + '?' + paramString;
1475
1476                // Return the output of the request
1477                // render fullUrl;
1478                render(
1479                    text:           new URL( fullUrl ).getText(),
1480                    contentType:    "text/xml",
1481                    encoding:       "UTF-8"
1482                );
1483        }
1484}
Note: See TracBrowser for help on using the repository browser.