source: trunk/grails-app/controllers/nl/tno/metagenomics/AssayController.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: 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                excelService.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.oligoNumber = assaySampleParams.oligoNumber
199                                        assaySample.tagSequence = assaySampleParams.tagSequence
200
201                                        try {
202                                                assaySample.run = Run.get( assaySampleParams.run as Long );
203                                        } catch( Exception e ) {}
204
205                                        assaySample.save()
206                                }
207                        }
208                }
209
210                flash.message = "Data about samples is saved."
211                redirect( action: 'show', id: params.id )
212        }
213
214        /**************************************************************************
215         *
216         * Methods for handling data about runs for this assay
217         *
218         *************************************************************************/
219
220        /**
221         * Adds existing runs to this assay
222         */
223        def addExistingRuns = {
224                def assay = getAssay( params.id );
225                if( !assay )
226                        return
227
228                // Add checked runs to this assay
229                def runs = params.runs
230                if( runs instanceof String ) {
231                        runs = [ runs ]
232                }
233
234                def numAdded = 0;
235                runs.each { run_id ->
236                        try {
237                                def run = Run.findById( run_id as Long )
238                                if( run.assays == null || !run.assays.contains( assay ) ) {
239                                        run.addToAssays( assay );
240                                        numAdded++;
241                                }
242                        } catch( Exception e ) {}
243                }
244
245                flash.message = numAdded + " runs are added to this assay."
246                redirect( action: 'show', id: params.id)
247        }
248
249        /**
250         * Adds existing runs to this assay
251         */
252        def removeRun = {
253                def assay = getAssay( params.id );
254                if( !assay )
255                        return
256
257                if( !params.run_id ) {
258                        flash.message = "No run id given"
259                        redirect(action: 'show', id: params.id)
260                        return
261                }
262
263                def run
264
265                try {
266                        run = Run.findById( params.run_id as Long )
267                } catch( Exception e ) {
268                        throw e
269                        flash.message = "Incorrect run id given: "
270                        redirect(action: 'show', id: params.id)
271                        return
272                }
273
274                if( assay.runs.contains( run ) ) {
275                        assay.removeFromRuns( run );
276                        flash.message = "The run has been removed from this assay."
277                } else {
278                        flash.message = "The given run was not associated with this assay."
279                }
280
281                redirect( action: 'show', id: params.id)
282        }
283
284        def errorPage = {
285                render "An error has occured. $flash.message"
286        }
287
288        /**
289         * Deletes an uploaded file for which the filename is given in the session.
290         * @return
291         */
292        def _deleteUploadedFileFromSession() {
293                if( !session.filename )
294                        return
295
296                // Now delete the file, since we don't need it anymore
297                fileService.delete( session.filename  )
298                session.filename = ''
299        }
300       
301        protected Assay getAssay(def assayId) {
302                // load study with id specified by param.id
303                def assay
304                try {
305                        assay = Assay.get(assayId as Long)
306                } catch( Exception e ) {
307                        flash.error = "Incorrect id given: " + assayId
308                        redirect(controller: 'study')
309                        return null
310                }
311
312                if (!assay) {
313                        flash.error = "No assay found with id: " + assayId
314                        redirect(controller: 'study')
315                        return null
316                }
317               
318                if (!assay.study.canRead( session.user ) ) {
319                        flash.error = "You don't have the right authorizaton to access assay " + assay.name
320                        redirect(controller: 'study')
321                        return null
322                }
323               
324                return assay
325        }
326       
327
328}
Note: See TracBrowser for help on using the repository browser.