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

Revision 959, 39.5 KB (checked in by j.a.m.wesbeek@…, 3 years ago)

- set keyword expansion

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