source: trunk/grails-app/controllers/nl/tno/metagenomics/RunController.groovy @ 7

Last change on this file since 7 was 7, checked in by robert@…, 8 years ago
  • Created tests for the synchronization and trash
  • Improved synchronizationservice and trash
  • Put authorization checks in several pages
File size: 10.6 KB
Line 
1package nl.tno.metagenomics
2
3import java.util.Date;
4
5import org.codehaus.groovy.grails.commons.ConfigurationHolder
6
7class RunController {
8        def fileService
9        def synchronizationService
10        def sampleExcelService
11
12        def index = {
13                [runs: Run.list()]
14        }
15
16        def show = {
17                // load run with id specified by param.id
18                def run = getRun( params.id );
19
20                if (!run) {
21                        redirect(controller: 'study', action: 'index')
22                        return
23                }
24
25                // Make sure the newest data is available
26                synchronizationService.sessionToken = session.sessionToken
27                synchronizationService.synchronizeStudies();
28
29                // Determine runs not used in this assay
30                def otherAssays = Assay.list( sort: "name" ).findAll { !it.runs.contains( run ) }
31
32                // Send the assay information to the view
33                [run: run, otherAssays: otherAssays, editable: true]
34        }
35
36        /**
37         * Shows a form to edit the specified run in dialog mode
38         */
39        def editForm = {
40                // load run with id specified by param.id
41                Run run = getRun( params.id );
42
43                if (!run) {
44                        render flash.error
45                        return
46                }
47
48                Assay assay = getAssay( params.id )
49
50                if( !assay ) {
51                        render flash.error;
52                        return
53                }
54
55                [assay: assay, run: run]
56        }
57
58        def create = {
59                Assay a = getAssay(params.id);
60                flash.error = "";
61
62                // Create run based on given parameters
63                Run run = new Run();
64
65                run.setPropertiesFromForm( params );
66
67                if( a )
68                        a.addToRuns( run );
69
70                if( !run.save() ) {
71                        flash.message = "Run could not be saved: " + run.getErrors();
72                } else {
73                        flash.message = "Run " + run.name + " has been added to the system."
74                }
75
76                if( a )
77                        redirect( controller: "assay", action: "show", id: a.id )
78                else
79                        redirect( controller: 'run' );
80        }
81
82        def update = {
83                if( !params.assayId ) {
84                        flash.error = "No assay id given"
85                        redirect(controller: 'study')
86                        return
87                }
88
89                Assay assay = getAssay(params.assayId);
90
91                if( !a ) {
92                        redirect( controller: 'study' );
93                }
94
95                Run run = getRun( params.id );
96
97                if( !run ) {
98                        redirect(controller: 'assay', action: 'show', id: params.assayId)
99                        return
100                }
101
102                // Set properties to the run
103                params.parameterFile = params.editParameterFile
104                run.setPropertiesFromForm( params );
105
106                if( run.save() ) {
107                        flash.message = "Run succesfully saved";
108                } else {
109                        flash.error = "Run could not be saved: " + run.getErrors();
110                }
111
112                redirect( controller: 'assay', action: 'show', id: params.assayId)
113        }
114
115        def delete = {
116                Run run = getRun( params.id );
117
118                if( !run ) {
119                        redirect(controller: 'assay', action: 'show', id: params.assayId)
120                        return
121                }
122
123                // Don't remove runs for which data exists
124                if( run.sequenceData?.size() ) {
125                        flash.message = "Run could not be deleted because samples are associated with it.";
126                        redirect( controller: "assay", action: "show", id: params.assayId )
127                }
128
129                // Remove all associations
130                run.assays.each {
131                        run.removeFromAssays( it );
132                }
133
134                def name = run.name
135                run.delete();
136                flash.message = "Run " + name + " has been deleted from the system."
137
138                redirect( controller: "assay", action: "show", id: params.assayId )
139        }
140
141        /**************************************************************************
142         *
143         * Methods for handling data about the samples in this run
144         *
145         *************************************************************************/
146
147        /**
148         * Downloads an excel sheet with data about the assay samples, to enter data in excel
149         */
150        def downloadTagsExcel = {
151                Run run = getRun( params.id );
152
153                if( !run ) {
154                        redirect(controller: 'study')
155                        return
156                }
157
158                // Make it only possible to update samples writable by the user
159                def assaySamples = run.assaySamples.findAll { it.assay.study.canWrite( session.user ) }
160
161                def filename = "Run " + run.name + "_tags.xls"
162                def wb = sampleExcelService.downloadSampleExcel( assaySamples, false );
163
164                // Make file downloadable
165                log.trace( "Creation for downloading the file " + filename )
166                sampleExcelService.excelService.downloadFile( wb, filename, response )
167        }
168
169
170        /**
171         * Parses an uploaded excel file and shows a form to match columns
172         */
173        def parseTagExcel = {
174                Run run = getRun( params.id );
175
176                if( !run ) {
177                        redirect(controller: 'study')
178                        return
179                }
180
181                def filename = params.filename
182
183                // Security check to prevent accessing files in other directories
184                if( !filename || filename.contains( '..' ) ) {
185                        response.status = 500;
186                        render "Invalid filename given";
187                        return;
188                }
189
190                // Check for existence and readability
191                File file = new File( fileService.getUploadDir(), filename)
192
193                if( !file.exists() || !file.canRead() ) {
194                        response.status = 404;
195                        render "The uploaded file doesn't exist or doesn't work as expected.";
196                        return;
197                }
198
199                // Save the filename in session for later use
200                session.filename = filename;
201                def excelData;
202                try {
203                        excelData = sampleExcelService.parseTagsExcel( file, false );
204                } catch( Throwable e ) { // Catch a throwable here instead of an exception, since the apache poi stuff gives an Error on failure
205                        // Couldn't create a workbook from this file.
206                        response.status = 400 // Bad request
207                        render "Uploaded file is not a valid excel file: " + e.getMessage()
208                        return
209                }
210                session.possibleFields = excelData.possibleFields
211
212                [run: run, headers: excelData.headers, exampleData: excelData.exampleData, filename: filename, possibleFields: [ "Don't import" ] + excelData.possibleFields, bestMatches: excelData.bestMatches]
213        }
214
215        /**
216         * Updates the assay samples based on the given excel file and the column matches
217         */
218        def updateTagsByExcel = {
219                Run run = getRun( params.id );
220
221                if( !run ) {
222                        // Now delete the file, since we don't need it anymore
223                        _deleteUploadedFileFromSession()
224
225                        redirect(controller: 'study')
226                        return
227                }
228
229                if( !session.filename ) {
230                        // Now delete the file, since we don't need it anymore
231                        _deleteUploadedFileFromSession()
232
233                        flash.error = "No excel file found because session timed out. Please try again."
234                        redirect( action: 'show', id: params.id)
235                        return
236                }
237
238                // Determine the match-columns
239                def matchColumns = params[ 'matches'];
240
241                // Now loop through the excel sheet and update all samples with the specified data
242                File file = new File( fileService.getUploadDir(), session.filename );
243
244                if( !file.exists() || !file.canRead() ) {
245                        flash.error = "Excel file has been removed since previous step. Please try again."
246                        redirect( action: 'show', id: params.id)
247                        return
248                }
249               
250                // Make it only possible to update samples writable by the user
251                def assaySamples = run.assaySamples.findAll { it.assay.study.canWrite( session.user ) }
252               
253                def excelData = sampleExcelService.updateTagsByExcel( matchColumns, session.possibleFields, file, assaySamples );
254
255                // Return a message to the user
256                if( !excelData.success ) {
257                        flash.error = excelData.message
258                } else if( excelData.numSuccesful == 0 ) {
259                        flash.error = "None of the " + excelData.failedRows.size() + " row(s) could be imported, because none of the sample names matched or no samples are writable. Have you provided the right excel file?"
260                } else {
261                        flash.message = excelData.numSuccesful + " samples have been updated. "
262
263                        if( excelData.failedRows.size() > 0 )
264                                flash.message += excelData.failedRows.size() + " row(s) could not be imported, because the sample names could not be found in the database or you don't have the proper permissions to change them."
265                }
266                redirect( action: 'show', id: params.id )
267        }
268
269
270        /**
271         * Update the properties of the assay samples manually
272         */
273        def updateTagsManually = {
274                Run run = getRun( params.id );
275
276                if( !run ) {
277                        redirect(controller: 'study')
278                        return
279                }
280
281                // Loop through all assay samples and set data
282                def sampleParams = params.assaySample;
283
284                if( sampleParams ) {
285                        run.assaySamples.each { assaySample ->
286                                def assaySampleParams = sampleParams.get( assaySample.id as String );
287                                if( assaySampleParams ) {
288                                        assaySample.oligoNumber = assaySampleParams.oligoNumber
289                                        assaySample.tagSequence = assaySampleParams.tagSequence
290
291                                        assaySample.save()
292                                }
293                        }
294                }
295
296                flash.message = "Data about samples is saved."
297                redirect( action: 'show', id: params.id )
298        }
299
300        /**************************************************************************
301         *
302         * Methods for handling data about assays for this run
303         *
304         *************************************************************************/
305
306        /**
307         * Adds existing assays to this run
308         */
309        def addAssays = {
310                Run run = getRun( params.id );
311
312                if( !run ) {
313                        redirect(controller: 'study')
314                        return
315                }
316
317                // Add checked runs to this assay
318                def assays = params.assays
319                if( assays instanceof String ) {
320                        assays = [ assays ]
321                }
322
323                def numAdded = 0;
324                assays.each { assay_id ->
325                        try {
326                                def assay = Assay.findById( assay_id as Long )
327                                if( run.assays == null || !run.assays.contains( assay ) ) {
328                                        run.addToAssays( assay );
329                                        numAdded++;
330                                }
331                        } catch( Exception e ) {}
332                }
333
334                flash.message = numAdded + " runs are added to this assay."
335                redirect( action: 'show', id: params.id)
336        }
337
338        /**
339         * Removes assay for this run
340         */
341        def removeAssay = {
342                Run run = getRun( params.id );
343
344                if( !run ) {
345                        redirect(controller: 'study')
346                        return
347                }
348               
349                if( !params.assay_id ) {
350                        flash.message = "No assay id given"
351                        redirect(action: 'show', id: params.id)
352                        return
353                }
354
355                def assay
356
357                try {
358                        assay = Assay.findById( params.assay_id as Long )
359                } catch( Exception e ) {
360                        throw e
361                        flash.message = "Incorrect assay id given: "
362                        redirect(action: 'show', id: params.id)
363                        return
364                }
365
366                if( run.assays.contains( assay ) ) {
367                        run.removeFromAssays( assay );
368                        flash.message = "The assay has been removed from this run."
369                } else {
370                        flash.message = "The given assay was not associated with this run."
371                }
372
373                redirect( action: 'show', id: params.id)
374        }
375
376
377        /**
378         * Deletes an uploaded file for which the filename is given in the session.
379         * @return
380         */
381        def _deleteUploadedFileFromSession() {
382                if( !session.filename )
383                        return
384
385                // Now delete the file, since we don't need it anymore
386                fileService.delete( session.filename  )
387                session.filename = ''
388        }
389
390        protected Run getRun(def runId) {
391                // load study with id specified by param.id
392                def run
393                try {
394                        run = Run.get(runId as Long)
395                } catch( Exception e ) {
396                        flash.error = "Incorrect id given: " + runId
397                        return null
398                }
399
400                if (!run) {
401                        flash.error = "No run found with id: " + runId
402                        return null
403                }
404
405                return run
406        }
407
408        protected Assay getAssay(def assayId) {
409                // load study with id specified by param.id
410                def assay
411                try {
412                        assay = Assay.get(assayId as Long)
413                } catch( Exception e ) {
414                        flash.error = "Incorrect id given: " + assayId
415                        return null
416                }
417
418                if (!assay) {
419                        flash.error = "No assay found with id: " + assayId
420                        return null
421                }
422
423                if (!assay.study.canRead( session.user ) ) {
424                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
425                        return null
426                }
427
428                return assay
429        }
430}
Note: See TracBrowser for help on using the repository browser.