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

Last change on this file since 7 was 7, checked in by robert@…, 9 years ago
  • Created tests for the synchronization and trash
  • Improved synchronizationservice and trash
  • Put authorization checks in several pages
File size: 9.2 KB
Line 
1package nl.tno.metagenomics
2
3import org.codehaus.groovy.grails.commons.ConfigurationHolder
4import grails.converters.*;
5
6class FastaController {
7        def fileService
8        def fastaService
9       
10        /**************************************************************************
11         *
12         * Methods for handling uploaded sequence and quality files
13         *
14         *************************************************************************/
15
16        /**
17         * Shows a screen that processing is done
18         */
19        def showProcessScreen = {
20                def entityType = params.entityType
21
22                // Check whether files are given
23                def names = params.sequencefiles
24
25                if( !names ) {
26                        flash.message = "No files uploaded for processing"
27                        redirect( controller: params.entityType, action: 'show', 'id': params.id)
28                        return
29                }
30               
31                // If only 1 file is uploaded, it is given as String
32                ArrayList filenames = []
33                if( names instanceof String )
34                        filenames << names
35                else
36                        names.each { filenames << it }
37                       
38                // Save filenames in session
39                session.processFilenames = names;
40               
41                // Check for total size of the files in order to be able
42                // to show a progress bar
43                long filesize = 0;
44                names.each {
45                        filesize += fileService.get( it )?.length()
46                }
47                session.processProgress = [
48                        numFiles: names.size(),
49                        numBytes: filesize,
50                        filesProcessed: 0,
51                        bytesProcessed: 0
52                ]
53                       
54                [entityId: params.id, entityType: params.entityType, filenames: names, url: createLink( action: 'showProcessResult', id: params.id, params: [entityType: entityType] ) ]
55        }
56       
57        /**
58         * Processes uploaded files and tries to combine them with samples
59         */
60        def process = {
61                def entity
62                def assaySamples
63               
64                switch( params.entityType ) {
65                        case "run":
66                                entity = getRun( params.id );
67                                assaySamples = entity.assaySamples;
68                                break;
69                        case "assay":
70                                entity = getAssay( params.id );
71                                assaySamples = entity.assaySamples;
72                                break;
73                        default:
74                                response.setStatus( 404, "No controller found" );
75                                render "";
76                                return;
77                }
78
79                if (!entity) {
80                        response.setStatus( 404, flash.error )
81                        render "";
82                        return
83                }
84
85                // Check whether files are given
86                def names = session.processFilenames
87
88                if( !names ) {
89                        response.setStatus( 500, "No files uploaded for processing" )
90                        render "";
91                        return
92                }
93
94                // If only 1 file is uploaded, it is given as String
95                ArrayList filenames = []
96                if( names instanceof String )
97                        filenames << names
98                else
99                        names.each { filenames << it }
100
101                /* Parses uploaded files, discards files we can not handle
102                 *
103                 * [
104                 *              success: [
105                 *                      [filename: 'abc.fasta', type: FASTA, numSequences: 190]
106                 *                      [filename: 'cde.fasta', type: FASTA, numSequences: 140]
107                 *                      [filename: 'abc.qual', type: QUAL, numSequences: 190, avgQuality: 38]
108                 *                      [filename: 'cde.qual', type: QUAL, numSequences: 140, avgQuality: 29]
109                 *              ],
110                 *              failure: [
111                 *                      [filename: 'testing.xls', message: 'Type not recognized']
112                 *              ]
113                 * ]
114                 *
115                 * The second parameter is a callback function to update progress indicators
116                 */
117                def parsedFiles = fastaService.parseFiles( filenames, { files, bytes, totalFiles, totalBytes -> 
118                        session.processProgress.numFiles += totalFiles;
119                        session.processProgress.numBytes += totalBytes;
120                        session.processProgress.filesProcessed = files; 
121                        session.processProgress.bytesProcessed = bytes; 
122                } );
123       
124                // Check which assaySamples to use (only the ones visible to the user)
125                assaySamples = assaySamples.findAll { it.assay.study.canWrite( session.user ) }
126
127                // Match files with samples in the database
128                def matchedFiles = fastaService.matchFiles( parsedFiles.success, assaySamples );
129
130                // Sort files on filename
131                matchedFiles.sort { a,b -> a.fasta?.originalfilename <=> b.fasta?.originalfilename }
132
133                // Saved file matches in session to use them later on
134                session.processedFiles = [ parsed: parsedFiles, matched: matchedFiles ];
135
136                render ""
137        }
138       
139        def getProgress = {
140                if( !session.processProgress ) {
141                        response.setStatus( 500, "No progress information found" );
142                        render ""
143                        return
144                }
145               
146                render session.processProgress as JSON
147        }
148       
149        /**
150         * Show result of processing
151         */
152        def showProcessResult = {
153                // load study with id specified by param.id
154                def entity
155               
156                switch( params.entityType ) {
157                        case "run":
158                                entity = getRun( params.id )
159                                break;
160                        case "assay":
161                                entity = getAssay( params.id )
162                                break;
163                        default:
164                                response.setStatus( 404, "No entity found" );
165                                render "";
166                                return;
167                }
168
169                if (!entity) {
170                        response.setStatus( 404, flash.error )
171                        render "";
172                        return
173                }
174               
175                if( !session.processedFiles ) {
176                        flash.error = "Processing of files failed. Maybe the session timed out."
177                        redirect( controller: 'assay', action: 'show', 'id': params.id)
178                        return
179                }
180               
181                [entityType: params.entityType, entity: entity, id: params.id, parsedFiles: session.processedFiles.parsed, matchedFiles: session.processedFiles.matched, selectedRun: params.selectedRun ]
182        }
183
184        /**
185         * Saves processed files to the database, based on the selections made by the user
186         */
187        def saveProcessedFiles = {
188                // load entity with id specified by param.id
189                def entity
190               
191                switch( params.entityType ) {
192                        case "run":
193                                entity = getRun( params.id );
194                                break;
195                        case "assay":
196                                entity = getAssay( params.id );
197                                break;
198                        default:
199                                response.setStatus( 404, "No entity found" );
200                                render "";
201                                return;
202                }
203
204                if (!entity) {
205                        response.setStatus( 404, flash.error )
206                        render "";
207                        return
208                }
209
210                // Check whether files are given
211                def files = params.file
212
213                if( !files ) {
214                        flash.message = "No files were selected."
215                        redirect( controller: params.entityType, action: 'show', 'id': params.id)
216                        return
217                }
218
219                File permanentDir = fileService.absolutePath( ConfigurationHolder.config.metagenomics.fileDir )
220                int numSuccesful = 0;
221                def errors = [];
222               
223                // Loop through all files Those are the numeric elements in the 'files' array
224                def digitRE = ~/^\d+$/;
225                files.findAll { it.key.matches( digitRE ) }.each { file ->
226                        def filevalue = file.value;
227                       
228                        // Check if the file is selected
229                        if( filevalue.include == "on" ) {
230                                if( fileService.fileExists( filevalue.fasta ) ) {
231                                        try {
232                                                def permanent = fastaService.savePermanent( filevalue.fasta, filevalue.qual, session.processedFiles );
233                                               
234                                                // Save the data into the database
235                                                SequenceData sd = new SequenceData();
236                                               
237                                                sd.sequenceFile = permanent.fasta
238                                                sd.qualityFile = permanent.qual
239                                                sd.numSequences = permanent.numSequences
240                                                sd.averageQuality = permanent.avgQuality
241                                                       
242                                                def sample = AssaySample.get( filevalue.assaySample );
243                                                if( sample )
244                                                        sample.addToSequenceData( sd );
245                                               
246                                                if( !sd.validate() ) {
247                                                        errors << "an error occurred while saving " + filevalue.fasta + ": validation of SequenceData failed.";
248                                                } else {
249                                                        sd.save(flush:true);
250                                                }
251                                               
252                                                numSuccesful++;
253                                        } catch( Exception e ) {
254                                                errors << "an error occurred while saving " + filevalue.fasta + ": " + e.getMessage()
255                                        }
256                                }
257                        } else {
258                                // File doesn't need to be included in the system. Delete it also from disk
259                                fileService.delete( filevalue.fasta );
260                        }
261                }
262
263                // Return a message to the user
264                if( numSuccesful == 0 ) {
265                        flash.error = "None of the files were imported, because "
266                       
267                        if( errors.size() > 0 ) {
268                                errors.each {
269                                        flash.error += "<br />- " + it
270                                }
271                        } else {
272                                flash.error = "none of the files were selected for import."
273                        }
274                } else {
275                        flash.message = numSuccesful + " files have been added to the system. "
276
277                        if( errors.size() > 0 ) {
278                                flash.error += errors.size() + " errors occurred during import: "
279                                errors.each {
280                                        flash.error += "<br />- " + it
281                                }
282                        }
283                }
284               
285                redirect( controller: params.entityType, action: "show", id: params.id )
286        }
287       
288        def deleteData = { 
289                // load study with id specified by param.id
290                def sequenceData
291               
292                try {
293                        sequenceData = SequenceData.get(params.id as Long)
294                } catch( Exception e ) {}
295
296                if (!sequenceData) {
297                        flash.error = "No sequencedata found with id: $params.id"
298                        redirect( controller: 'study' )
299                        return
300                }
301
302                def entityId
303                def entityType
304               
305                switch( params.entityType ) {
306                        case "run":
307                                entityId = sequenceData.sample.run?.id;
308                                entityType = "run"
309                                break;
310                        case "assay":
311                        default:
312                                entityType = "assay";
313                                entityId = sequenceData.sample.assay.id;
314                                break;
315                }
316                 
317                def numFiles = sequenceData.numFiles();
318                sequenceData.delete();
319
320                flash.message = numFiles + " file" + (numFiles != 1 ? "s have" : " has" ) + " been deleted from this sample"
321
322                redirect( controller: entityType, action: 'show', id: entityId )
323        }
324       
325        protected Assay getAssay(def assayId) {
326                // load assay with id specified by param.id
327                def assay
328                try {
329                        assay = Assay.get(assayId as Long)
330                } catch( Exception e ) {
331                        flash.error = "Incorrect id given: " + assayId
332                        return null
333                }
334
335                if (!assay) {
336                        flash.error = "No assay found with id: " + assayId
337                        return null
338                }
339               
340                if (!assay.study.canRead( session.user ) ) {
341                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
342                        return null
343                }
344               
345                return assay
346        }
347       
348        protected Run getRun(def runId) {
349                // load run with id specified by param.id
350                def run
351                try {
352                        run = Run.get(runId as Long)
353                } catch( Exception e ) {
354                        flash.error = "Incorrect id given: " + runId
355                        return null
356                }
357
358                if (!run) {
359                        flash.error = "No run found with id: " + runId
360                        return null
361                }
362
363                return run
364        }
365}
Note: See TracBrowser for help on using the repository browser.