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

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

AuthenticationService? instantiated

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