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

Last change on this file since 9 was 9, checked in by robert@…, 12 years ago
File size: 10.7 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, allRuns: Run.list(), 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 = null
49                if( params.assayId ) {
50                        assay = getAssay( params.assayId )
51       
52                        if( !assay ) {
53                                render flash.error;
54                                return
55                        }
56                }
57
58                [assay: assay, run: run]
59        }
60
61        def create = {
62                Assay a = getAssay(params.id);
63                flash.error = "";
64
65                // Create run based on given parameters
66                Run run = new Run();
67
68                run.setPropertiesFromForm( params );
69
70                if( a )
71                        a.addToRuns( run );
72
73                if( !run.save() ) {
74                        flash.message = "Run could not be saved: " + run.getErrors();
75                } else {
76                        flash.message = "Run " + run.name + " has been added to the system."
77                }
78
79                if( a )
80                        redirect( controller: "assay", action: "show", id: a.id )
81                else
82                        redirect( controller: 'run' );
83        }
84
85        def update = {
86                Run run = getRun( params.id );
87
88                if( !run ) {
89                        redirect(controller: 'assay', action: 'show', id: params.assayId)
90                        return
91                }
92
93                // Set properties to the run
94                params.parameterFile = params.editParameterFile
95               
96                println "Edit run: " + params
97                run.setPropertiesFromForm( params );
98
99                if( run.save() ) {
100                        flash.message = "Run succesfully saved";
101                } else {
102                        flash.error = "Run could not be saved: " + run.getErrors();
103                }
104               
105                Assay assay = getAssay(params.assayId);
106                flash.error = "";
107               
108                if( assay ) {
109                        redirect( controller: 'assay', action: 'show', id: assay.id)
110                } else {
111                        redirect( controller: 'run', action: 'show', id: run.id )
112                }
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.tagName = assaySampleParams.tagName
289                                        assaySample.oligoNumber = assaySampleParams.oligoNumber
290                                        assaySample.tagSequence = assaySampleParams.tagSequence
291
292                                        assaySample.save()
293                                }
294                        }
295                }
296
297                flash.message = "Data about samples is saved."
298                redirect( action: 'show', id: params.id )
299        }
300
301        /**************************************************************************
302         *
303         * Methods for handling data about assays for this run
304         *
305         *************************************************************************/
306
307        /**
308         * Adds existing assays to this run
309         */
310        def addAssays = {
311                Run run = getRun( params.id );
312
313                if( !run ) {
314                        redirect(controller: 'study')
315                        return
316                }
317
318                // Add checked runs to this assay
319                def assays = params.assays
320                if( assays instanceof String ) {
321                        assays = [ assays ]
322                }
323
324                def numAdded = 0;
325                assays.each { assay_id ->
326                        try {
327                                def assay = Assay.findById( assay_id as Long )
328                                if( run.assays == null || !run.assays.contains( assay ) ) {
329                                        run.addToAssays( assay );
330                                        numAdded++;
331                                }
332                        } catch( Exception e ) {}
333                }
334
335                flash.message = numAdded + " runs are added to this assay."
336                redirect( action: 'show', id: params.id)
337        }
338
339        /**
340         * Removes assay for this run
341         */
342        def removeAssay = {
343                Run run = getRun( params.id );
344
345                if( !run ) {
346                        redirect(controller: 'study')
347                        return
348                }
349               
350                if( !params.assay_id ) {
351                        flash.message = "No assay id given"
352                        redirect(action: 'show', id: params.id)
353                        return
354                }
355
356                def assay
357
358                try {
359                        assay = Assay.findById( params.assay_id as Long )
360                } catch( Exception e ) {
361                        throw e
362                        flash.message = "Incorrect assay id given: "
363                        redirect(action: 'show', id: params.id)
364                        return
365                }
366
367                if( run.assays.contains( assay ) ) {
368                        run.removeFromAssays( assay );
369                        flash.message = "The assay has been removed from this run."
370                } else {
371                        flash.message = "The given assay was not associated with this run."
372                }
373
374                redirect( action: 'show', id: params.id)
375        }
376
377
378        /**
379         * Deletes an uploaded file for which the filename is given in the session.
380         * @return
381         */
382        def _deleteUploadedFileFromSession() {
383                if( !session.filename )
384                        return
385
386                // Now delete the file, since we don't need it anymore
387                fileService.delete( session.filename  )
388                session.filename = ''
389        }
390
391        protected Run getRun(def runId) {
392                // load study with id specified by param.id
393                def run
394                try {
395                        run = Run.get(runId as Long)
396                } catch( Exception e ) {
397                        flash.error = "Incorrect id given: " + runId
398                        return null
399                }
400
401                if (!run) {
402                        flash.error = "No run found with id: " + runId
403                        return null
404                }
405
406                return run
407        }
408
409        protected Assay getAssay(def assayId) {
410                // load study with id specified by param.id
411                def assay
412                try {
413                        assay = Assay.get(assayId as Long)
414                } catch( Exception e ) {
415                        flash.error = "Incorrect id given: " + assayId
416                        return null
417                }
418
419                if (!assay) {
420                        flash.error = "No assay found with id: " + assayId
421                        return null
422                }
423
424                if (!assay.study.canRead( session.user ) ) {
425                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
426                        return null
427                }
428
429                return assay
430        }
431}
Note: See TracBrowser for help on using the repository browser.