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

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