source: trunk/grails-app/controllers/dbnp/studycapturing/StudyController.groovy

Last change on this file was 2132, checked in by tjeerd@…, 9 years ago

Timeline final commit

  • Property svn:keywords set to Rev Author Date
File size: 13.8 KB
Line 
1package dbnp.studycapturing
2
3import grails.plugins.springsecurity.Secured
4import org.dbnp.gdt.TemplateFieldType
5import org.dbnp.gdt.RelTime
6import grails.converters.JSON
7
8/**
9 * Controller class for studies
10 */
11class StudyController {
12    def authenticationService
13   
14    //static allowedMethods = [save: "POST", update: "POST", delete: "POST"]
15
16    def index = {
17        redirect(action: "list", params: params)
18    }
19
20    /**
21     * Shows all studies where the user has access to
22     */
23    def list = {
24
25        def user = authenticationService.getLoggedInUser()
26        def max = Math.min(params.max ? params.int('max') : 10, 100)
27                def offset = params.offset ? params.int( 'offset' ) : 0
28        def studies = Study.giveReadableStudies( user, max, offset );
29        [studyInstanceList: studies, studyInstanceTotal: Study.countReadableStudies( user ), loggedInUser: user]
30
31    }
32
33    /**
34     * Shows studies for which the logged in user is the owner
35     */
36    @Secured(['IS_AUTHENTICATED_REMEMBERED'])
37    def myStudies = {
38        def user = authenticationService.getLoggedInUser()
39        def max = Math.min(params.max ? params.int('max') : 10, 100)
40                def offset = params.offset ? params.int( 'offset' ) : 0
41               
42        def studies = Study.findAllByOwner(user, [max:max,offset: offset]);
43        render( view: "list", model: [studyInstanceList: studies, studyInstanceTotal: Study.countByOwner(user), loggedInUser: user] )
44    }
45
46    /**
47     * Shows a comparison of multiple studies using the show view
48     *
49     */
50    def list_extended = {
51                // If nothing has been selected, redirect the user
52                if( !params.id ) 
53                        redirect( action: 'list' )
54
55                // Check whether one id has been selected or multiple.
56                def ids = params.id
57                if( ids instanceof String )
58                        redirect( action: 'show', id: ids )
59
60                // Parse strings to a long
61                def long_ids = []
62                ids.each { long_ids.add( Long.parseLong( it ) ) }
63
64                //println( long_ids )
65
66        def startTime = System.currentTimeMillis()
67                def c = Study.createCriteria()
68
69        def studyList = c {
70                        maxResults( Math.min(params.max ? params.int('max') : 10, 100) )
71                        'in'( "id", long_ids )
72                }
73        render(view:'show',model:[studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ) ] )
74    }
75
76    /**
77     * Shows one or more studies
78     */
79    def show = {
80        def startTime = System.currentTimeMillis()
81
82
83
84        def studyInstance = Study.get( params.long( "id" ) )
85        if (!studyInstance) {
86            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'study.label', default: 'Study'), params.id])}"
87            redirect(action: "list")
88        }
89        else {
90            // Check whether the user may see this study
91            def loggedInUser = authenticationService.getLoggedInUser()
92            if( !studyInstance.canRead(loggedInUser) ) {
93                flash.message = "You have no access to this study"
94                redirect(action: "list")
95            }
96
97            // The study instance is packed into an array, to be able to
98            // use the same view for showing the study and comparing multiple
99            // studies
100            [studyList: [ studyInstance ], multipleStudies: false, loggedInUser: loggedInUser, facebookLikeUrl: studyInstance.getFieldValue('published') ? "/study/show/${studyInstance?.id}" : '' ]
101        }
102    }
103
104        /**
105     * Shows the subjects tab of one or more studies. Is called when opening the subjects-tab
106         * on the study overview screen.
107     */
108    def show_subjects = {
109                def studyList = readStudies( params.id );
110
111                if( !studyList )
112                        return
113
114                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
115    }
116
117        /**
118     * Shows the events timeline tab of one or more studies. Is called when opening the events timeline-tab
119         * on the study overview screen.
120     */
121    def show_events_timeline = {
122                def studyList = readStudies( params.id );
123
124                if( !studyList )
125                        return
126
127                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
128    }
129
130        /**
131     * Shows the events table tab of one or more studies. Is called when opening the events table-tab
132         * on the study overview screen.
133     */
134    def show_events_table = {
135                def studyList = readStudies( params.id );
136
137                if( !studyList )
138                        return
139
140                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
141    }
142
143        /**
144     * Shows the assays tab of one or more studies. Is called when opening the assays tab
145         * on the study overview screen.
146     */
147    def show_assays = {
148                def studyList = readStudies( params.id );
149
150                if( !studyList )
151                        return
152
153                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
154    }
155
156        /**
157     * Shows the samples tab of one or more studies. Is called when opening the samples-tab
158         * on the study overview screen.
159     */
160    def show_samples = {
161                def studyList = readStudies( params.id );
162
163                if( !studyList )
164                        return
165
166                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
167    }
168
169        /**
170     * Shows the persons tab of one or more studies. Is called when opening the persons tab
171         * on the study overview screen.
172     */
173    def show_persons = {
174                def studyList = readStudies( params.id );
175
176                if( !studyList )
177                        return
178
179                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
180    }
181
182        /**
183     * Shows the publications tab of one or more studies. Is called when opening the publications tab
184         * on the study overview screen.
185     */
186    def show_publications = {
187                def studyList = readStudies( params.id );
188
189                if( !studyList )
190                        return
191
192                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ), loggedInUser: authenticationService.getLoggedInUser() ]
193    }
194
195        /**
196         * Creates the javascript for showing the timeline of one or more studies
197         */
198        def createTimelineBandsJs = {
199                def studyList = readStudies( params.id );
200
201                if( !studyList )
202                        return
203
204                [studyList: studyList, studyInstanceTotal: Study.count(), multipleStudies: ( studyList.size() > 1 ) ]
205        }
206
207    /**
208         * Reads one or more studies from the database and checks whether the logged
209         * in user is allowed to access them.
210         *
211         * Is used by several show_-methods
212         *
213         * @return List with Study objects or false if an error occurred.
214         */
215        private def readStudies( id ) {
216                // If nothing has been selected, redirect the user
217                if( !id || !( id instanceof String)) {
218            response.status = 500;
219            render 'No study selected';
220            return false
221                }
222
223                // Check whether one id has been selected or multiple.
224                def ids = URLDecoder.decode( id ).split( "," );
225
226                // Parse strings to a long
227                def long_ids = []
228                ids.each { long_ids.add( Long.parseLong( it ) ) }
229
230                def c = Study.createCriteria()
231
232        def studyList = c {
233                        maxResults( Math.min(params.max ? params.int('max') : 10, 100) )
234                        'in'( "id", long_ids )
235                }
236
237                // Check whether the user may see these studies
238                def studiesAllowed = []
239        def loggedInUser = authenticationService.getLoggedInUser()
240
241                studyList.each { studyInstance ->
242            if( studyInstance.canRead(loggedInUser) ) {
243                                studiesAllowed << studyInstance
244            }
245                }
246
247                // If the user is not allowed to see any of the studies, return 404
248                if( studiesAllowed.size() == 0 ) {
249            response.status = 404;
250            render 'Selected studies not found';
251            return false
252                }
253               
254                return studyList
255        }
256
257    def showByToken = {
258        def studyInstance = Study.findByStudyUUID(params.id)
259        if (!studyInstance) {
260            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'study.label', default: 'Study'), params.id])}"
261            redirect(action: "list")
262        }
263        else {
264            // Check whether the user may see this study
265            def loggedInUser = authenticationService.getLoggedInUser()
266            if( !studyInstance.canRead(loggedInUser) ) {
267                flash.message = "You have no access to this study"
268                redirect(action: "list")
269            }
270
271            redirect(action: "show", id: studyInstance.id)
272        }
273    }
274
275    /**
276     * Gives the events for one eventgroup in JSON format
277     *
278     */
279    def events = {
280        def eventGroupId = Integer.parseInt( params.id );
281        def studyId      = Integer.parseInt( params.study );
282        def eventGroup;
283
284        // eventGroupId == -1 means that the orphaned events should be given
285        if( eventGroupId == -1 ) {
286            def studyInstance = Study.get( studyId )
287           
288            if (studyInstance == null) {
289                flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'study.label', default: 'Study'), studyId])}"
290                redirect(action: "list");
291                return;
292            }
293
294            events = studyInstance.getOrphanEvents();
295        } else {
296            eventGroup = EventGroup.get(params.id)
297
298            if (eventGroup == null) {
299                flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'eventgroup.label', default: 'Eventgroup'), params.id])}"
300                redirect(action: "list");
301                return;
302            }
303            events = eventGroup?.events + eventGroup?.samplingEvents;
304        }
305
306        // This parameter should give the startdate of the study in milliseconds
307        // since 1-1-1970
308        long startDate  = Long.parseLong( params.startDate )
309
310        // Create JSON object
311        def json = [ 'dateTimeFormat': 'iso8601', events: [] ];
312
313        // Add all other events
314        for( event in events ) {
315            def parameters = []
316            for( templateField in event.giveTemplateFields() ) {
317                def value = event.getFieldValue( templateField.name );
318                                if( value ) {
319                                        if( templateField.type == TemplateFieldType.RELTIME )
320                                                value = new RelTime( value ).toString();
321
322                        def param = templateField.name + " = " + value;
323
324                                        if( templateField.unit )
325                                                param += templateField.unit;
326
327                    parameters << param ;
328                }
329            }
330
331                        def description = parameters.join( '<br />\n' );
332
333                        if( event instanceof SamplingEvent ) {
334                                 json.events << [
335                                        'start':    new Date( startDate + event.startTime * 1000 ),
336                                        'end':      new Date( startDate + event.startTime * 1000 ),
337                                        'durationEvent': false,
338                                        'title': event.template?.name,
339                                        'description': "SampleTemplate = " + event.sampleTemplate + "<br />\n" + description
340                                ]
341                        } else {
342                                 json.events << [
343                                        'start':    new Date( startDate + event.startTime * 1000 ),
344                                        'end':      new Date( startDate + event.endTime * 1000 ),
345                                        'durationEvent': true,
346                                        'title': event.template?.name,
347                                        'description': description
348                                ]
349                               
350                        }
351        }
352
353                // set output header to json
354                response.contentType = 'application/json'
355
356        render json as JSON
357    }
358
359    def delete = {
360        def studyInstance = Study.get(params.id)
361        if (studyInstance) {
362            try {
363                studyInstance.delete(flush: true)
364                flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'study.label', default: 'Study'), params.id])}"
365                redirect(action: "list")
366            }
367            catch (org.springframework.dao.DataIntegrityViolationException e) {
368                flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'study.label', default: 'Study'), params.id])}"
369                redirect(action: "show", id: params.id)
370            }
371        }
372        else {
373            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'study.label', default: 'Study'), params.id])}"
374            redirect(action: "list")
375        }
376    }
377
378    /**
379     * Renders assay names and id's as JSON
380     */
381    def ajaxGetAssays = {
382        def study = Study.read(params.id)
383
384                // set output header to json
385                response.contentType = 'application/json'
386
387        render ((study?.assays?.collect{[name: it.name, id: it.id]} ?: []) as JSON)
388    }
389       
390        /**
391         * Exports all data from the given studies to excel. This is done using a redirect to the
392         * assay controller
393         *
394         * @param       ids                             ids of the studies to export
395         * @param       params.format   "list" in order to export all assays in one big excel sheet
396         *                                                      "sheets" in order to export every assay on its own sheet (default)
397         * @see         AssayController.exportToExcel
398         */
399        def exportToExcel = {
400                def ids = params.list( 'ids' ).findAll { it.isLong() }.collect { Long.valueOf( it ) };
401                def tokens = params.list( 'tokens' );
402
403                if( !ids && !tokens ) {
404                        flash.errorMessage = "No study ids given";
405                        redirect( controller: "assay", action: "errorPage" );
406                        return;
407                }
408               
409                // Find all assay ids for these studies
410                def assayIds = [];
411                ids.each { id ->
412                        def study = Study.get( id );
413                        if( study ) {
414                                assayIds += study.assays.collect { assay -> assay.id }
415                        }
416                }
417               
418                // Also accept tokens for defining studies
419                tokens.each { token ->
420                        def study = Study.findByStudyUUID( token );
421                        if( study )
422                                assayIds += study.assays.collect { assay -> assay.id }
423                }
424                 
425                if( !assayIds ) {
426                        flash.errorMessage = "No assays found for the given studies";
427                        redirect( controller: "assay", action: "errorPage" );
428                        return;
429                }
430               
431                // Create url to redirect to
432                def format = params.get( "format", "sheets" )
433                redirect( controller: "assay", action: "exportToExcel", params: [ "format": format, "ids": assayIds ] );
434        }
435}
Note: See TracBrowser for help on using the repository browser.