1 | /** |
---|
2 | * FileController |
---|
3 | * |
---|
4 | * Handles file uploads and downloads |
---|
5 | * |
---|
6 | * @author Robert Horlings |
---|
7 | * @since 20100601 |
---|
8 | * @package dbnp.studycapturing |
---|
9 | * |
---|
10 | * Revision information: |
---|
11 | * $Rev: 1182 $ |
---|
12 | * $Author: robert@isdat.nl $ |
---|
13 | * $Date: 2010-11-22 17:27:23 +0100 (Mon, 22 Nov 2010) $ |
---|
14 | */ |
---|
15 | package nl.tno.metagenomics.files |
---|
16 | |
---|
17 | import nl.tno.metagenomics.*; |
---|
18 | |
---|
19 | import org.codehaus.groovy.grails.commons.ConfigurationHolder |
---|
20 | import org.springframework.web.multipart.MultipartHttpServletRequest |
---|
21 | import grails.converters.* |
---|
22 | import org.apache.commons.io.IOUtils; |
---|
23 | |
---|
24 | class FileController { |
---|
25 | |
---|
26 | def fileService; |
---|
27 | |
---|
28 | /** |
---|
29 | * Returns the file that is asked for from the temporary upload directory |
---|
30 | * or a 404 error if the file doesn't exist |
---|
31 | */ |
---|
32 | def get = { |
---|
33 | // Remove all old files from the upload directory, so the user |
---|
34 | // can't retrieve any old file that were left behind |
---|
35 | fileService.cleanDirectory(); |
---|
36 | |
---|
37 | retrieveFile( params, fileService.getUploadDir() ); |
---|
38 | } |
---|
39 | |
---|
40 | /** |
---|
41 | * Deletes the file that is asked for from the temporary upload directory |
---|
42 | * or a 404 error if the file doesn't exist |
---|
43 | */ |
---|
44 | def delete = { |
---|
45 | File directory = fileService.getUploadDir() |
---|
46 | String filename = checkFile( params, directory ); |
---|
47 | |
---|
48 | response.contentType = "text/plain" |
---|
49 | |
---|
50 | try { |
---|
51 | fileService.delete( filename, directory ); |
---|
52 | render '' |
---|
53 | } catch( Exception e ) { |
---|
54 | response.status = 500; |
---|
55 | render e.getMessage(); |
---|
56 | } |
---|
57 | } |
---|
58 | |
---|
59 | /** |
---|
60 | * Returns the file that is asked for from the temporary upload directory |
---|
61 | * or a 404 error if the file doesn't exist |
---|
62 | */ |
---|
63 | def getPermanent = { |
---|
64 | if( checkPermissions( params, fileService.absolutePath( ConfigurationHolder.config.metagenomics.fileDir ) ) ) { |
---|
65 | retrieveFile( params, fileService.absolutePath( ConfigurationHolder.config.metagenomics.fileDir ) ); |
---|
66 | } else { |
---|
67 | render 'No access'; |
---|
68 | } |
---|
69 | } |
---|
70 | |
---|
71 | /** |
---|
72 | * Checks whether the user is allowed to access this file. He is only allowed to |
---|
73 | * if he has access to the study this file belongs to. |
---|
74 | * |
---|
75 | * The file could be pointed to in several locations: |
---|
76 | * - SequenceData.sequenceFile |
---|
77 | * - SequenceData.qualityFile |
---|
78 | * - Run.parameterFile |
---|
79 | * |
---|
80 | * If the file is not mentioned in any of these locations, it should not be returned by this system and |
---|
81 | * a 404 error is given. If the user doesn't have access to the file, a 403 is given. |
---|
82 | * |
---|
83 | * @param params HTTP request parameters |
---|
84 | * @param directory File object representing the directory to search in |
---|
85 | */ |
---|
86 | private boolean checkPermissions( params, directory ) { |
---|
87 | String filename = checkFile( params, directory ); |
---|
88 | |
---|
89 | if( !filename ) |
---|
90 | return; |
---|
91 | |
---|
92 | // Search for the file in the sequenceData file fields |
---|
93 | def sd = SequenceData.findBySequenceFileOrQualityFile( filename, filename ); |
---|
94 | if( sd ) { |
---|
95 | if( sd.sample?.sample?.study?.canRead( session.user ) ) { |
---|
96 | return true; |
---|
97 | } else { |
---|
98 | response.setStatus( 403, "Not authorized to access this file" ); |
---|
99 | return false; |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | // Search for the file in run file fields. If the file is found in that spot |
---|
104 | // it is freely accessible by any logged in user |
---|
105 | def run = Run.findByParameterFile( filename ); |
---|
106 | if( run ) { |
---|
107 | if( session.user ) { |
---|
108 | return true; |
---|
109 | } else { |
---|
110 | response.setStatus( 403, "Not authorized to access this file" ); |
---|
111 | return false; |
---|
112 | } |
---|
113 | } |
---|
114 | |
---|
115 | // Otherwise, the file should not be accessed this way |
---|
116 | response.setStatus( 404, "File not found" ); |
---|
117 | return false; |
---|
118 | } |
---|
119 | |
---|
120 | private void retrieveFile( params, directory ) { |
---|
121 | String filename = checkFile( params, directory ); |
---|
122 | def file = fileService.get( filename, directory ); |
---|
123 | |
---|
124 | //response.setContentType("application/octet-stream") |
---|
125 | //response.setContentType( "image/jpeg" ); |
---|
126 | |
---|
127 | // Return the file |
---|
128 | response.setHeader "Content-disposition", "attachment; filename=${filename}" |
---|
129 | response.outputStream << file.newInputStream() |
---|
130 | response.outputStream.flush() |
---|
131 | } |
---|
132 | |
---|
133 | private String checkFile( params, directory ) { |
---|
134 | def fileExists; |
---|
135 | |
---|
136 | // Filename is not url decoded for some reason |
---|
137 | def coder = new org.apache.commons.codec.net.URLCodec() |
---|
138 | def filename = coder.decode(params.id) |
---|
139 | |
---|
140 | if( !filename ) { |
---|
141 | response.contentType = "text/plain" |
---|
142 | response.status = 404; |
---|
143 | render( "File not found" ); |
---|
144 | return; |
---|
145 | } |
---|
146 | |
---|
147 | // Security check to prevent accessing files in other directories |
---|
148 | if( filename.contains( '..' ) ) { |
---|
149 | response.contentType = "text/plain" |
---|
150 | response.status = 500; |
---|
151 | render "Invalid filename given"; |
---|
152 | return; |
---|
153 | } |
---|
154 | |
---|
155 | try { |
---|
156 | fileExists = fileService.fileExists( filename, directory ) |
---|
157 | } catch( FileNotFoundException e ) { |
---|
158 | fileExists = false; |
---|
159 | } |
---|
160 | if( !filename || !fileExists ) { |
---|
161 | response.contentType = "text/plain" |
---|
162 | response.status = 404; |
---|
163 | render( "File not found" ); |
---|
164 | return; |
---|
165 | } |
---|
166 | |
---|
167 | return filename; |
---|
168 | } |
---|
169 | |
---|
170 | /** |
---|
171 | * Uploads a file and returns the filename under which the file is saved |
---|
172 | */ |
---|
173 | def upload = { |
---|
174 | // If an old file exists, delete it |
---|
175 | if( params.get( 'oldFile' ) ) { |
---|
176 | fileService.delete( params.get( 'oldFile' ) ); |
---|
177 | } |
---|
178 | |
---|
179 | render moveUploadedFile( fileService. getUploadDir() ) as JSON |
---|
180 | } |
---|
181 | |
---|
182 | protected def moveUploadedFile(File absolutePath ) { |
---|
183 | if( !( request instanceof MultipartHttpServletRequest ) ) { |
---|
184 | response.setStatus( response.SC_BAD_REQUEST ); |
---|
185 | log.error( "Request for file upload is not multipart: " + params ); |
---|
186 | return []; |
---|
187 | } |
---|
188 | |
---|
189 | MultipartHttpServletRequest mpr = (MultipartHttpServletRequest) request; |
---|
190 | def uploadedFile = mpr.getFile( 'Filedata' ) |
---|
191 | |
---|
192 | String filename = uploadedFile.getOriginalFilename(); |
---|
193 | |
---|
194 | // URL decode the filename |
---|
195 | def coder = new org.apache.commons.codec.net.URLCodec() |
---|
196 | filename = coder.decode(filename) |
---|
197 | |
---|
198 | String newFilename = fileService.getUniqueFilename( filename, absolutePath ); |
---|
199 | try { |
---|
200 | uploadedFile.transferTo( new File( absolutePath, newFilename ) ); |
---|
201 | |
---|
202 | response.setStatus(response.SC_OK); |
---|
203 | |
---|
204 | return [ 'success': true, 'filename': newFilename ] |
---|
205 | } catch (Exception ex) { |
---|
206 | log.error( "Fileupload has thrown an exception: " + ex.getMessage()); |
---|
207 | |
---|
208 | response.setStatus(response.SC_INTERNAL_SERVER_ERROR); |
---|
209 | return [ 'success': false ] |
---|
210 | } |
---|
211 | } |
---|
212 | |
---|
213 | |
---|
214 | } |
---|