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

Last change on this file since 9 was 9, checked in by robert@…, 8 years ago
File size: 9.0 KB
Line 
1package nl.tno.metagenomics
2
3import org.codehaus.groovy.grails.commons.ConfigurationHolder
4
5class AssayController {
6        def synchronizationService
7        def gscfService
8        def fuzzySearchService
9
10        def fileService
11        def excelService
12        def sampleExcelService
13
14        def index = {
15                // Filter studies for the ones the user is allowed to see
16                def studies = Study.list();
17                [studies: studies.findAll { it.canRead( session.user ) },
18                        gscfAddUrl: gscfService.urlAddStudy() ]
19        }
20       
21        def show = {
22                def assay = getAssay( params.id );
23                if( !assay )
24                        return
25
26                // Make sure the newest data is available
27                synchronizationService.sessionToken = session.sessionToken
28                synchronizationService.synchronizeAssay( assay );
29
30                // Determine runs not used in this assay
31                def otherRuns = Run.list( sort: "name" ).findAll { !it.assays.contains( assay ) }
32
33                // Send the assay information to the view
34                [assay: assay, editable: assay.study.canWrite( session.user ), otherRuns: otherRuns]
35        }
36
37        def showByToken = {
38                // load study with token specified by param.id
39                def assay = Assay.findByAssayToken(params.id as String)
40
41                if (!assay) {
42                        // Initialize synchronizationService
43                        synchronizationService.sessionToken = session.sessionToken
44                        synchronizationService.user = session.user
45
46                        // If the assay is not found, synchronize studies and try again
47                        synchronizationService.synchronizeStudies();
48
49                        assay = Assay.findByAssayToken(params.id as String)
50
51                        if (!assay) {
52                                // If the assay is not found, synchronize all studies and try again, since we might be out of sync
53                                synchronizationService.eager = true
54                                synchronizationService.synchronizeStudies();
55
56                                assay = Assay.findByAssayToken(params.id as String)
57
58                                // If after synchronization still no assay is found, show an error
59                                if( !assay ) {
60                                        flash.message = "No assay found with token: $params.id"
61                                        redirect(controller: 'study')
62                                }
63                        }
64                }
65
66                redirect( action: "show", id: assay.id );
67        }
68
69        /**************************************************************************
70         *
71         * Method for handling data about samples for this assay
72         *
73         *************************************************************************/
74
75        /**
76         * Downloads an excel sheet with data about the assay samples, to enter data in excel
77         */
78        def downloadTagsExcel = {
79                // load study with id specified by param.id
80                def assay = getAssay( params.id );
81                if( !assay )
82                        return
83
84                def filename = assay.study.name + "_" + assay.name + "_tags.xls"
85                def wb = sampleExcelService.downloadSampleExcel( assay.assaySamples );
86
87                // Make file downloadable
88                log.trace( "Creation for downloading the file " + filename )
89                sampleExcelService.excelService.downloadFile( wb, filename, response )
90        }
91
92        /**
93         * Parses an uploaded excel file and shows a form to match columns
94         */
95        def parseTagExcel = {
96                def assay = getAssay( params.id );
97                if( !assay )
98                        return
99
100                def filename = params.filename
101
102                // Security check to prevent accessing files in other directories
103                if( !filename || filename.contains( '..' ) ) {
104                        response.status = 500;
105                        render "Invalid filename given";
106                        return;
107                }
108
109                // Check for existence and readability
110                File file = new File( fileService.getUploadDir(), filename)
111
112                if( !file.exists() || !file.canRead() ) {
113                        response.status = 404;
114                        render "The uploaded file doesn't exist or doesn't work as expected.";
115                        return;
116                }
117
118                // Save the filename in session for later use
119                session.filename = filename;
120                def excelData;
121                try {
122                        excelData = sampleExcelService.parseTagsExcel( file );
123                } catch( Throwable e ) { // Catch a throwable here instead of an exception, since the apache poi stuff gives an Error on failure
124                        // Couldn't create a workbook from this file.
125                        response.status = 400 // Bad request
126                        render "Uploaded file is not a valid excel file: " + e.getMessage()
127                        return
128                }
129                session.possibleFields = excelData.possibleFields
130               
131                [assay: assay, headers: excelData.headers, exampleData: excelData.exampleData, filename: filename, possibleFields: [ "Don't import" ] + excelData.possibleFields, bestMatches: excelData.bestMatches]
132        }
133
134        /**
135         * Updates the assay samples based on the given excel file and the column matches
136         */
137        def updateTagsByExcel = {
138                def assay = getAssay( params.id );
139                if( !assay ) {
140                        // Now delete the file, since we don't need it anymore
141                        _deleteUploadedFileFromSession()
142                        return;
143                }
144
145                if( !session.filename ) {
146                        // Now delete the file, since we don't need it anymore
147                        _deleteUploadedFileFromSession()
148
149                        flash.error = "No excel file found because session timed out. Please try again."
150                        redirect( action: 'show', id: params.id)
151                        return
152                }
153
154                // Determine the match-columns
155                def matchColumns = params[ 'matches'];
156
157                // Now loop through the excel sheet and update all samples with the specified data
158                File file = new File( fileService.getUploadDir(), session.filename );
159               
160                if( !file.exists() || !file.canRead() ) {
161                        flash.error = "Excel file has been removed since previous step. Please try again."
162                        redirect( action: 'show', id: params.id)
163                        return
164                }
165               
166                def excelData = sampleExcelService.updateTagsByExcel( matchColumns, session.possibleFields, file, assay.assaySamples );
167
168                // Return a message to the user
169                if( !excelData.success ) {
170                        flash.error = excelData.message
171                } else if( excelData.numSuccesful == 0 ) {
172                        flash.error = "None of the " + excelData.failedRows.size() + " row(s) could be imported, because none of the sample names matched. Have you provided the right excel file?"
173                } else {
174                        flash.message = excelData.numSuccesful + " samples have been updated. "
175
176                        if( excelData.failedRows.size() > 0 )
177                                flash.message += excelData.failedRows.size() + " row(s) could not be imported, because the sample names could not be found in the database."
178                }
179                redirect( action: 'show', id: params.id )
180        }
181
182        /**
183         * Update the properties of the assay samples manually
184         */
185        def updateTagsManually = {
186                def assay = getAssay( params.id );
187                if( !assay )
188                        return
189
190                // Loop through all assay samples and set data
191                def sampleParams = params.assaySample;
192
193                if( sampleParams ) {
194                        assay.assaySamples.each { assaySample ->
195                                def assaySampleParams = sampleParams.get( assaySample.id as String );
196                                println assaySampleParams
197                                if( assaySampleParams ) {
198                                        assaySample.tagName = assaySampleParams.tagName
199                                        assaySample.oligoNumber = assaySampleParams.oligoNumber
200                                        assaySample.tagSequence = assaySampleParams.tagSequence
201
202                                        try {
203                                                assaySample.run = Run.get( assaySampleParams.run as Long );
204                                        } catch( Exception e ) {}
205
206                                        assaySample.save()
207                                }
208                        }
209                }
210
211                flash.message = "Data about samples is saved."
212                redirect( action: 'show', id: params.id )
213        }
214
215        /**************************************************************************
216         *
217         * Methods for handling data about runs for this assay
218         *
219         *************************************************************************/
220
221        /**
222         * Adds existing runs to this assay
223         */
224        def addExistingRuns = {
225                def assay = getAssay( params.id );
226                if( !assay )
227                        return
228
229                // Add checked runs to this assay
230                def runs = params.runs
231                if( runs instanceof String ) {
232                        runs = [ runs ]
233                }
234
235                def numAdded = 0;
236                runs.each { run_id ->
237                        try {
238                                def run = Run.findById( run_id as Long )
239                                if( run.assays == null || !run.assays.contains( assay ) ) {
240                                        run.addToAssays( assay );
241                                        numAdded++;
242                                }
243                        } catch( Exception e ) {}
244                }
245
246                flash.message = numAdded + " runs are added to this assay."
247                redirect( action: 'show', id: params.id)
248        }
249
250        /**
251         * Adds existing runs to this assay
252         */
253        def removeRun = {
254                def assay = getAssay( params.id );
255                if( !assay )
256                        return
257
258                if( !params.run_id ) {
259                        flash.message = "No run id given"
260                        redirect(action: 'show', id: params.id)
261                        return
262                }
263
264                def run
265
266                try {
267                        run = Run.findById( params.run_id as Long )
268                } catch( Exception e ) {
269                        throw e
270                        flash.message = "Incorrect run id given: "
271                        redirect(action: 'show', id: params.id)
272                        return
273                }
274
275                if( assay.runs.contains( run ) ) {
276                        assay.removeFromRuns( run );
277                        flash.message = "The run has been removed from this assay."
278                } else {
279                        flash.message = "The given run was not associated with this assay."
280                }
281
282                redirect( action: 'show', id: params.id)
283        }
284
285        def errorPage = {
286                render "An error has occured. $flash.message"
287        }
288
289        /**
290         * Deletes an uploaded file for which the filename is given in the session.
291         * @return
292         */
293        def _deleteUploadedFileFromSession() {
294                if( !session.filename )
295                        return
296
297                // Now delete the file, since we don't need it anymore
298                fileService.delete( session.filename  )
299                session.filename = ''
300        }
301       
302        protected Assay getAssay(def assayId) {
303                // load study with id specified by param.id
304                def assay
305                try {
306                        assay = Assay.get(assayId as Long)
307                } catch( Exception e ) {
308                        flash.error = "Incorrect id given: " + assayId
309                        redirect(controller: 'study')
310                        return null
311                }
312
313                if (!assay) {
314                        flash.error = "No assay found with id: " + assayId
315                        redirect(controller: 'study')
316                        return null
317                }
318               
319                if (!assay.study.canRead( session.user ) ) {
320                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
321                        redirect(controller: 'study')
322                        return null
323                }
324               
325                return assay
326        }
327       
328
329}
Note: See TracBrowser for help on using the repository browser.