root/trunk/grails-app/controllers/dbnp/studycapturing/WizardController.groovy @ 976

Revision 976, 42.8 KB (checked in by robert@…, 3 years ago)

Authentication and authorization for studies is added, according to ticket 118

  • Property svn:keywords set to Author Date Rev
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$
26 * $Author$
27 * $Date$
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                // load study
858                try {
859                        // load study
860                        def study = (params.studyid) ? Study.findById( params.studyid ) : Study.findByTitle( params.study )
861
862                        // Check whether the user is allowed to edit this study. If it is not allowed
863                        // the used should had never seen a link to this page, so he should never get
864                        // here. That's why we just return false
865                        if( !study.canWrite(AuthenticationService.getLoggedInUser()) ) {
866                            return false;
867                        }
868
869                        flow.study = study
870                        // set 'quicksave' variable
871                        flow.quickSave = true
872
873                        return true
874                } catch (Exception e) {
875                        // rollback
876                        this.appendErrorMap(['exception': e.toString() + ', see log for stacktrace'], flash.errors)
877
878                        return false
879                }
880        }
881
882        /**
883         * Handle the wizard study page
884         *
885         * @param Map LocalAttributeMap (the flow scope)
886         * @param Map localAttributeMap (the flash scope)
887         * @param Map GrailsParameterMap (the flow parameters = form data)
888         * @returns boolean
889         */
890        def studyPage(flow, flash, params) {
891                // remember the params in the flash scope
892                flash.values = params
893               
894                // instantiate study of it is not yet present
895                if (!flow.study) flow.study = new Study()
896
897                // did the study template change?
898                if (params.get('template').size() && flow.study.template?.name != params.get('template')) {
899                        println ".change study template!"
900
901                        // yes, was the template already set?
902                        if (flow.study.template instanceof Template) {
903                                // yes, first make sure all values are unset?
904                                println "!!! check the database fields if data of a previous template remains in the database or is deleted by GORM!"
905                        }
906
907                        // set the template
908                        flow.study.template = Template.findByName(params.remove('template'))
909                }
910
911                // does the study have a template set?
912                if (flow.study.template && flow.study.template instanceof Template) {
913                        // yes, iterate through template fields
914                        flow.study.giveFields().each() {
915                                // and set their values
916                                flow.study.setFieldValue(it.name, params.get(it.escapedName()))
917                        }
918                }
919
920                // handle publications
921                handlePublications(flow, flash, params)
922
923                // handle contacts
924                handleContacts(flow, flash, params)
925
926                // handle users (readers, writers)
927                handleUsers(flow, flash, params, 'readers')
928                handleUsers(flow, flash, params, 'writers')
929
930                // handle public checkbox
931                if( params.get( "publicstudy" ) ) {
932                    flow.study.publicstudy = params.get( "publicstudy" )
933                }
934
935                // validate the study
936                if (flow.study.validate()) {
937                        // instance is okay
938                        return true
939                } else {
940                        // validation failed
941                        flash.errors = [:]
942                        this.appendErrors(flow.study, flash.errors)
943                        return false
944                }
945        }
946
947        /**
948         * re-usable code for handling publications form data in a web flow
949         * @param Map LocalAttributeMap (the flow scope)
950         * @param Map localAttributeMap (the flash scope)
951         * @param Map GrailsParameterMap (the flow parameters = form data)
952         * @returns boolean
953         */
954        def handlePublications(flow, flash, params) {
955                if (!flow.study.publications) flow.study.publications = []
956
957                // Check the ids of the pubblications that should be attached
958                // to this study. If they are already attached, keep 'm. If
959                // studies are attached that are not in the selected (i.e. the
960                // user deleted them), remove them
961                def publicationIDs = params.get('publication_ids')
962                if (publicationIDs) {
963                        // Find the individual IDs and make integers
964                        publicationIDs = publicationIDs.split(',').collect { Integer.parseInt(it, 10) }
965
966                        // First remove the publication that are not present in the array
967                        flow.study.publications.removeAll { publication -> !publicationIDs.find { id -> id == publication.id } }
968
969                        // Add those publications not yet present in the database
970                        publicationIDs.each { id ->
971                                if (!flow.study.publications.find { publication -> id == publication.id }) {
972                                        def publication = Publication.get(id)
973                                        if (publication) {
974                                                flow.study.addToPublications(publication)
975                                        } else {
976                                                println('.publication with ID ' + id + ' not found in database.')
977                                        }
978                                }
979                        }
980
981                } else {
982                        println('.no publications selected.')
983                        flow.study.publications.clear()
984                }
985
986        }
987
988        /**
989         * re-usable code for handling contacts form data in a web flow
990         * @param Map LocalAttributeMap (the flow scope)
991         * @param Map localAttributeMap (the flash scope)
992         * @param Map GrailsParameterMap (the flow parameters = form data)
993         * @return boolean
994         */
995        def handleContacts(flow, flash, params) {
996                if (!flow.study.persons) flow.study.persons = []
997
998                // Check the ids of the contacts that should be attached
999                // to this study. If they are already attached, keep 'm. If
1000                // studies are attached that are not in the selected (i.e. the
1001                // user deleted them), remove them
1002
1003                // Contacts are saved as [person_id]-[role_id]
1004                def contactIDs = params.get('contacts_ids')
1005                if (contactIDs) {
1006                        // Find the individual IDs and make integers
1007                        contactIDs = contactIDs.split(',').collect {
1008                                def parts = it.split('-')
1009                                return [person: Integer.parseInt(parts[0]), role: Integer.parseInt(parts[1])]
1010                        }
1011
1012                        // First remove the contacts that are not present in the array
1013                        flow.study.persons.removeAll {
1014                                studyperson -> !contactIDs.find { ids -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }
1015                        }
1016
1017                        // Add those contacts not yet present in the database
1018                        contactIDs.each { ids ->
1019                                if (!flow.study.persons.find { studyperson -> (ids.person == studyperson.person.id) && (ids.role == studyperson.role.id) }) {
1020                                        def person = Person.get(ids.person)
1021                                        def role = PersonRole.get(ids.role)
1022                                        if (person && role) {
1023                                                // Find a studyperson object with these parameters
1024                                                def studyPerson = StudyPerson.findAll().find { studyperson -> studyperson.person.id == person.id && studyperson.role.id == role.id }
1025
1026                                                // If if does not yet exist, save the example
1027                                                if (!studyPerson) {
1028                                                        studyPerson = new StudyPerson(
1029                                                                person: person,
1030                                                                role: role
1031                                                        )
1032                                                        studyPerson.save(flush: true)
1033                                                }
1034
1035                                                flow.study.addToPersons(studyPerson)
1036                                        } else {
1037                                                println('.person ' + ids.person + ' or Role ' + ids.role + ' not found in database.')
1038                                        }
1039                                }
1040                        }
1041                } else {
1042                        println('.no persons selected.')
1043                        flow.study.persons.clear()
1044                }
1045
1046        }
1047
1048        /**
1049         * re-usable code for handling contacts form data in a web flow
1050         * @param Map LocalAttributeMap (the flow scope)
1051         * @param Map localAttributeMap (the flash scope)
1052         * @param Map GrailsParameterMap (the flow parameters = form data)
1053         * @param String    'readers' or 'writers'
1054         * @return boolean
1055         */
1056        def handleUsers(flow, flash, params, type) {
1057                def users = []
1058
1059                if( type == "readers" ) {
1060                    users = flow.study.readers ?: []
1061                } else if( type == "writers" ) {
1062                    users = flow.study.writers ?: []
1063                }
1064
1065                // Check the ids of the contacts that should be attached
1066                // to this study. If they are already attached, keep 'm. If
1067                // studies are attached that are not in the selected (i.e. the
1068                // user deleted them), remove them
1069
1070                // Users are saved as user_id
1071                def userIDs = params.get( type + '_ids')
1072                if (userIDs) {
1073                        // Find the individual IDs and make integers
1074                        userIDs = userIDs.split(',').collect { Integer.parseInt(it, 10) }
1075
1076                        // First remove the publication that are not present in the array
1077                        users.removeAll { user -> !userIDs.find { id -> id == user.id } }
1078
1079                        // Add those publications not yet present in the database
1080                        userIDs.each { id ->
1081                                if (!users.find { user -> id == user.id }) {
1082                                        def user = SecUser.get(id)
1083                                        if (user) {
1084                                            users.add(user)
1085                                        } else {
1086                                                println('.user with ID ' + id + ' not found in database.')
1087                                        }
1088                                }
1089                        }
1090
1091                } else {
1092                        println('.no users selected.')
1093                        users.clear()
1094                }
1095
1096                if( type == "readers" ) {
1097                    if( flow.study.readers )
1098                        flow.study.readers.clear()
1099                    users.each { flow.study.addToReaders( it ) }
1100                } else if( type == "writers" ) {
1101                    if( flow.study.writers )
1102                        flow.study.writers.clear()
1103                       
1104                    users.each { flow.study.addToWriters( it ) }
1105                }
1106
1107        }
1108                                                 
1109        /**
1110         * Handle the wizard subject page
1111         *
1112         * @param Map LocalAttributeMap (the flow scope)
1113         * @param Map localAttributeMap (the flash scope)
1114         * @param Map GrailsParameterMap (the flow parameters = form data)
1115         * @returns boolean
1116         */
1117        def subjectPage(flow, flash, params) {
1118                def errors = false
1119                flash.errors = [:]
1120
1121                // remember the params in the flash scope
1122                flash.values = params
1123
1124                // iterate through subjects
1125                flow.study.subjects.each() { subject ->
1126                        // iterate through (template and domain) fields
1127                        subject.giveFields().each() { field ->
1128                                // set field
1129                                subject.setFieldValue(
1130                                        field.name,
1131                                        params.get('subject_' + subject.getIdentifier() + '_' + field.escapedName())
1132                                )
1133                        }
1134
1135                        // validate subject
1136                        if (!subject.validate()) {
1137                                errors = true
1138                                this.appendErrors(subject, flash.errors, 'subject_' + subject.getIdentifier() + '_')
1139                        }
1140                }
1141
1142                return !errors
1143        }
1144
1145        /**
1146         * Add a number of subjects to a study
1147         *
1148         * required params entities:
1149         * -addNumber (int)
1150         * -species   (string)
1151         * -template  (string)
1152         *
1153         * @param Map LocalAttributeMap (the flow scope)
1154         * @param Map localAttributeMap (the flash scope)
1155         * @param Map GrailsParameterMap (the flow parameters = form data)
1156         * @returns boolean
1157         */
1158        def addSubjects(flow, flash, params) {
1159                // remember the params in the flash scope
1160                flash.values = params
1161
1162                // handle the subject page
1163                subjectPage(flow, flash, params)
1164
1165                // (re)set error message
1166                flash.errors = [:]
1167
1168                // set work variables
1169                def errors              = false
1170                def number              = params.get('addNumber') as int
1171                def species             = Term.findByName(params.get('species'))
1172                def template    = Template.findByName(params.get('template'))
1173
1174                // can we add subjects?
1175                if (number > 0 && species && template) {
1176                        // add subjects to study
1177                        number.times {
1178                                // work variables
1179                                def subjectName = 'Subject '
1180                                def subjectIterator = 1
1181                                def tempSubjectName = subjectName + subjectIterator
1182
1183                                // make sure subject name is unique
1184                                if (flow.study.subjects) {
1185                                        while (flow.study.subjects.find { it.name == tempSubjectName }) {
1186                                                subjectIterator++
1187                                                tempSubjectName = subjectName + subjectIterator
1188                                        }
1189                                }
1190                                subjectName = tempSubjectName
1191                               
1192                                // create a subject instance
1193                                def subject = new Subject(
1194                                        name            : subjectName,
1195                                        species         : species,
1196                                        template        : template
1197                                )
1198
1199                                // add it to the study
1200                                flow.study.addToSubjects( subject )
1201
1202                                // validate subject
1203                                if (subject.validate()) {
1204                                        println ".added subject "+subject
1205                                } else {
1206                                        // whoops?
1207                                        flow.study.removeFromSubjects( subject )
1208
1209                                        // append errors
1210                                        this.appendErrors(subject, flash.errors)
1211                                        errors = true
1212                                }
1213                        }
1214                } else {
1215                        // add feedback
1216                        errors = true
1217                        if (number < 1) this.appendErrorMap(['addNumber': 'Enter a positive number of subjects to add'], flash.errors)
1218                        if (!species)   this.appendErrorMap(['species': 'You need to select a species, or add one if it is not yet present'], flash.errors)
1219                        if (!template)  this.appendErrorMap(['template': 'You need to select a template, or add one if it is not yet present'], flash.errors)
1220                }
1221
1222                return !errors
1223        }
1224
1225        /**
1226         * Handle the wizard event page
1227         *
1228         * @param Map LocalAttributeMap (the flow scope)
1229         * @param Map localAttributeMap (the flash scope)
1230         * @param Map GrailsParameterMap (the flow parameters = form data)
1231         * @returns boolean
1232         */
1233        def eventPage(flow, flash, params) {
1234                def errors = false
1235                flash.errors = [:]
1236
1237                // remember the params in the flash scope
1238                flash.values = params
1239
1240                // handle the 'add event' form
1241                if (flow.event) {
1242                        flow.event.giveFields().each() { field ->
1243                                // set field
1244                                flow.event.setFieldValue(
1245                                        field.name,
1246                                        params.get(field.escapedName())
1247                                )
1248                        }
1249                }
1250
1251                // handle the eventGroup names and grouping
1252                def name        = ""
1253                def tempName= ""
1254                flow.study.eventGroups.each() { eventGroup ->
1255                        // iterate through templates
1256                        flow.study.giveAllEventTemplates().each() { template ->
1257                                tempName = params.get( 'eventGroup_' + eventGroup.getIdentifier() + '_' + template.getIdentifier() )
1258
1259                                // is the name different?
1260                                if (tempName != eventGroup.name) {
1261                                        name = tempName
1262                                }
1263                        }
1264
1265                        // should the name change?
1266                        if (name) {
1267                                // yes, change it
1268                                eventGroup.name = name
1269                                name = ""
1270                        }
1271
1272                        // handle eventGrouping
1273                        ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
1274                                if (params.get( 'event_' + event.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
1275                                        // add to eventGroup
1276                                        if (event instanceof SamplingEvent) {
1277                                                // check if we are already in this eventGroup
1278                                                if (!eventGroup.samplingEvents.find { it.equals(event) }) {
1279                                                        // no, add it
1280                                                        eventGroup.addToSamplingEvents(event)
1281
1282                                                        // iterate through subjects for this eventGroup
1283                                                        eventGroup.subjects.each() { subject ->
1284                                                                // instantiate a sample for this subject / event
1285                                                                def samplingEventName = this.ucwords(event.template.name)
1286                                                                def sampleName = (this.ucwords(subject.name) + '_' + samplingEventName + '_' + new RelTime(event.startTime).toString()).replaceAll("([ ]{1,})", "")
1287                                                                def tempSampleIterator = 0
1288                                                                def tempSampleName = sampleName
1289
1290                                                                // make sure sampleName is unique
1291                                                                if (flow.study.samples) {
1292                                                                        while (flow.study.samples.find { it.name == tempSampleName }) {
1293                                                                                tempSampleIterator++
1294                                                                                tempSampleName = sampleName + "_" + tempSampleIterator
1295                                                                        }
1296                                                                        sampleName = tempSampleName
1297                                                                }
1298
1299                                                                // instantiate a sample
1300                                                                flow.study.addToSamples(
1301                                                                        new Sample(
1302                                                                                parentSubject: subject,
1303                                                                                parentEvent: event,
1304                                                                                name: sampleName,
1305                                                                                template: (event.sampleTemplate) ? event.sampleTemplate : ''
1306                                                                        )
1307                                                                )
1308                                                        }
1309                                                }
1310                                        } else {
1311                                                eventGroup.addToEvents(event)
1312                                        }
1313                                } else {
1314                                        // remove from eventGroup
1315                                        if (event instanceof SamplingEvent) {
1316                                                // iterate through subjects (if we have them)
1317                                                eventGroup.subjects.each() { subject ->
1318                                                        // find all samples for this subject / event
1319                                                        flow.study.samples.findAll { (it.parentEvent.equals(event) && it.parentSubject.equals(subject) ) }.each() {
1320                                                                // delete this sample
1321                                                                flow.study.removeFromSamples( it )
1322                                                                it.delete()
1323                                                        }
1324                                                }
1325                                               
1326                                                eventGroup.removeFromSamplingEvents(event)
1327                                        } else {
1328                                                eventGroup.removeFromEvents(event)
1329                                        }
1330                                }
1331                        }
1332                }
1333
1334                // handle the (sampling) events
1335                ( ((flow.study.events) ? flow.study.events : []) + ((flow.study.samplingEvents) ? flow.study.samplingEvents : []) ) .each() { event ->
1336                        event.giveFields().each() { field ->
1337                                event.setFieldValue(
1338                                        field.name,
1339                                        params.get( 'event_' + event.getIdentifier() + '_' + field.escapedName() )
1340                                )
1341                        }
1342
1343                        // validate event
1344                        if (!event.validate()) {
1345                                errors = true
1346                                this.appendErrors(event, flash.errors)
1347                        }
1348                }
1349
1350                return !errors
1351        }
1352
1353        /**
1354         * Handle the wizard group page
1355         *
1356         * @param Map LocalAttributeMap (the flow scope)
1357         * @param Map localAttributeMap (the flash scope)
1358         * @param Map GrailsParameterMap (the flow parameters = form data)
1359         * @returns boolean
1360         */
1361        def groupPage(flow, flash, params) {
1362                def errors = false
1363                flash.errors = [:]
1364
1365                // remember the params in the flash scope
1366                flash.values = params
1367
1368                // iterate through groups
1369                flow.study.eventGroups.each() { eventGroup ->
1370                        // iterate through subjects
1371                        flow.study.subjects.each() { subject ->
1372                                if (params.get('subject_' + subject.getIdentifier() + '_group_' + eventGroup.getIdentifier() )) {
1373                                        // check if this subject is already part of this eventGroup
1374                                        if ( !eventGroup.subjects.find { it.equals(subject) } ) {
1375                                                // add to eventGroup
1376                                                eventGroup.addToSubjects(subject)
1377
1378                                                // iterate through samplingEvents
1379                                                eventGroup.samplingEvents.each() { samplingEvent ->
1380                                                        def samplingEventName = this.ucwords(samplingEvent.template.name)
1381                                                        def sampleName = (this.ucwords(subject.name) + '_' + samplingEventName + '_' + new RelTime(samplingEvent.startTime).toString()).replaceAll("([ ]{1,})", "")
1382                                                        def tempSampleIterator = 0
1383                                                        def tempSampleName = sampleName
1384
1385                                                        // make sure sampleName is unique
1386                                                        if (flow.study.samples) {
1387                                                                while (flow.study.samples.find { it.name == tempSampleName }) {
1388                                                                        tempSampleIterator++
1389                                                                        tempSampleName = sampleName + "_" + tempSampleIterator
1390                                                                }
1391                                                                sampleName = tempSampleName
1392                                                        }
1393
1394                                                        // instantiate a sample
1395                                                        flow.study.addToSamples(
1396                                                                new Sample(
1397                                                                        parentSubject: subject,
1398                                                                        parentEvent: samplingEvent,
1399                                                                        name: sampleName,
1400                                                                        template: (samplingEvent.sampleTemplate) ? samplingEvent.sampleTemplate : ''
1401                                                                )
1402                                                        )
1403                                                }
1404                                        }
1405                                } else {
1406                                        // remove from eventGroup
1407                                        eventGroup.removeFromSubjects(subject)
1408
1409                                        // iterate through samplingEvents
1410                                        eventGroup.samplingEvents.each() { samplingEvent ->
1411                                                flow.study.samples.findAll { ( it.parentEvent.equals(samplingEvent) && it.parentSubject.equals(subject) ) }.each() {
1412                                                        // delete this sample
1413                                                        flow.study.removeFromSamples( it )
1414                                                        it.delete()
1415                                                }
1416                                        }
1417                                }
1418                        }
1419                }
1420        }
1421
1422        /**
1423         * Handle the wizard samples page
1424         *
1425         * @param Map LocalAttributeMap (the flow scope)
1426         * @param Map localAttributeMap (the flash scope)
1427         * @param Map GrailsParameterMap (the flow parameters = form data)
1428         * @returns boolean
1429         */
1430        def samplePage(flow, flash, params) {
1431                def errors = false
1432                flash.errors = [:]
1433
1434                // remember the params in the flash scope
1435                flash.values = params
1436
1437                // iterate through samples
1438                flow.study.samples.each() { sample ->
1439                        // iterate through sample fields
1440                        sample.giveFields().each() { field ->
1441                                def value = params.get('sample_'+sample.getIdentifier()+'_'+field.escapedName())
1442
1443                                // set field value
1444                                if (!(field.name == 'name' && !value)) {
1445                                        println "setting "+field.name+" to "+value
1446                                        sample.setFieldValue(field.name, value)
1447                                }
1448                        }
1449
1450                        // has the template changed?
1451                        def templateName = params.get('template_' + sample.getIdentifier())
1452                        if (templateName && sample.template?.name != templateName) {
1453                                sample.template = Template.findByName(templateName)
1454                        }
1455
1456                        // validate sample
1457                        if (!sample.validate()) {
1458                                errors = true
1459                                this.appendErrors(sample, flash.errors, 'sample_' + sample.getIdentifier() + '_' )
1460                                println 'error-> sample_'+sample.getIdentifier()
1461                        }
1462                }
1463
1464                return !errors
1465        }
1466
1467        /**
1468         * Handle the wizard assays page
1469         *
1470         * @param Map LocalAttributeMap (the flow scope)
1471         * @param Map localAttributeMap (the flash scope)
1472         * @param Map GrailsParameterMap (the flow parameters = form data)
1473         * @returns boolean
1474         */
1475        def assayPage(flow, flash, params) {
1476                def errors = false
1477                flash.errors = [:]
1478
1479                // remember the params in the flash scope
1480                flash.values = params
1481
1482                // handle the 'add assay' form
1483                if (flow.assay) {
1484                        flow.assay.giveFields().each() { field ->
1485                                // set field
1486                                flow.assay.setFieldValue(
1487                                        field.name,
1488                                        params.get(field.escapedName())
1489                                )
1490                        }
1491                }
1492
1493                // handle the assay data
1494                flow.study.assays.each() { assay ->
1495                        // set data
1496                        assay.giveFields().each() { field ->
1497                                assay.setFieldValue(
1498                                        field.name,
1499                                        params.get( 'assay_' + assay.getIdentifier() + '_' + field.escapedName() )
1500                                )
1501                        }
1502
1503                        // validate assay
1504                        if (!assay.validate()) {
1505                                errors = true
1506                                this.appendErrors(assay, flash.errors, 'assay_' + assay.getIdentifier() + '_')
1507                        }
1508                }
1509
1510                return !errors
1511        }
1512
1513        /**
1514         * Handle the wizard assayGroups page
1515         *
1516         * @param Map LocalAttributeMap (the flow scope)
1517         * @param Map localAttributeMap (the flash scope)
1518         * @param Map GrailsParameterMap (the flow parameters = form data)
1519         * @returns boolean
1520         */
1521        def assayGroupPage(flow, flash, params) {
1522                def errors = false
1523                flash.errors = [:]
1524
1525                // remember the params in the flash scope
1526                flash.values = params
1527
1528                // iterate through samples
1529                flow.study.samples.each() { sample ->
1530                        // iterate through assays
1531                        flow.study.assays.each() { assay ->
1532                                if (params.get( 'sample_' + sample.getIdentifier() + '_assay_' + assay.getIdentifier() )) {
1533                                        println "add sample "+sample.getIdentifier()+" to assay "+assay.getIdentifier()
1534                                        // add sample to assay
1535                                        assay.addToSamples( sample )
1536                                } else {
1537                                        // remove sample from assay
1538                                        assay.removeFromSamples( sample )
1539                                }
1540                                println assay.samples
1541                        }
1542                }
1543
1544                return !errors
1545        }
1546
1547        /**
1548         * groovy / java equivalent of php's ucwords function
1549         *
1550         * Capitalize all first letters of separate words
1551         *
1552         * @param String
1553         * @return String
1554         */
1555        def ucwords(String text) {
1556                def newText = ''
1557
1558                // change case to lowercase
1559                text = text.toLowerCase()
1560
1561                // iterate through words
1562                text.split(" ").each() {
1563                        newText += it[0].toUpperCase() + it.substring(1) + " "
1564                }
1565
1566                return newText.substring(0, newText.size()-1)
1567        }
1568
1569        /**
1570         * return the object from a map of objects by searching for a name
1571         * @param String name
1572         * @param Map map of objects
1573         * @return Object
1574         */
1575        def getObjectByName(name, map) {
1576                def result = null
1577                map.each() {
1578                        if (it.name == name) {
1579                                result = it
1580                        }
1581                }
1582
1583                return result
1584        }
1585
1586        /**
1587         * transform domain class validation errors into a human readable
1588         * linked hash map
1589         * @param object validated domain class
1590         * @return object  linkedHashMap
1591         */
1592        def getHumanReadableErrors(object) {
1593                def errors = [:]
1594                object.errors.getAllErrors().each() {
1595                        def message = it.toString()
1596
1597                        //errors[it.getArguments()[0]] = it.getDefaultMessage()
1598                        errors[it.getArguments()[0]] = message.substring(0, message.indexOf(';'))
1599                }
1600
1601                return errors
1602        }
1603
1604        /**
1605         * append errors of a particular object to a map
1606         * @param object
1607         * @param map linkedHashMap
1608         * @void
1609         */
1610        def appendErrors(object, map) {
1611                this.appendErrorMap(this.getHumanReadableErrors(object), map)
1612        }
1613
1614        def appendErrors(object, map, prepend) {
1615                this.appendErrorMap(this.getHumanReadableErrors(object), map, prepend)
1616        }
1617
1618        /**
1619         * append errors of one map to another map
1620         * @param map linkedHashMap
1621         * @param map linkedHashMap
1622         * @void
1623         */
1624        def appendErrorMap(map, mapToExtend) {
1625                map.each() {key, value ->
1626                        mapToExtend[key] = ['key': key, 'value': value, 'dynamic': false]
1627                }
1628        }
1629
1630        def appendErrorMap(map, mapToExtend, prepend) {
1631                map.each() {key, value ->
1632                        mapToExtend[prepend + key] = ['key': key, 'value': value, 'dynamic': true]
1633                }
1634        }
1635
1636        /**
1637         * Parses a RelTime string and returns a nice human readable string
1638         *
1639         * @return Human Readable string or a HTTP response code 400 on error
1640         */
1641        def ajaxParseRelTime = {
1642                if (params.reltime == null) {
1643                        response.status = 400
1644                        render('reltime parameter is expected')
1645                }
1646
1647                try {
1648                        def reltime = RelTime.parseRelTime(params.reltime)
1649                        render reltime.toPrettyString()
1650                } catch (IllegalArgumentException e) {
1651                        response.status = 400
1652                        render(e.getMessage())
1653                }
1654        }
1655
1656        /**
1657         * Proxy for searching PubMed articles (or other articles from the Entrez DB).
1658         *
1659         * This proxy is needed because it is not allowed to fetch XML directly from a different
1660         * domain using javascript. So we have the javascript call a function on our own domain
1661         * and the proxy will fetch the data from Entrez
1662         *
1663         * @since       20100609
1664         * @param       _utility        The name of the utility, without the complete path. Example: 'esearch.fcgi'
1665         * @return      XML
1666         */
1667        def entrezProxy = {
1668                // Remove unnecessary parameters
1669                params.remove( "action" )
1670                params.remove( "controller" )
1671
1672                def url = "http://eutils.ncbi.nlm.nih.gov/entrez/eutils";
1673                def util = params.remove( "_utility" )
1674                def paramString = params.collect { k, v -> k + '=' + v.encodeAsURL() }.join( '&' );
1675
1676                def fullUrl = url + '/' + util + '?' + paramString;
1677
1678                // Return the output of the request
1679                // render fullUrl;
1680                render(
1681                    text:           new URL( fullUrl ).getText(),
1682                    contentType:    "text/xml",
1683                    encoding:       "UTF-8"
1684                );
1685        }
1686}
Note: See TracBrowser for help on using the browser.