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

Last change on this file since 1798 was 1798, checked in by robert@…, 9 years ago

After searching, several actions can be performed on search results. These actions are called by sending data to a URL. This was done using the HTTP GET method, but that resulted in error with the length of the query string (see #422). This is solved by sending all data using the HTTP POST method.

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