redo exception handling for uploaded files
[qcg-portal.git] / filex / uploadhandler.py
1 from functools import wraps
2 import os
3
4 from django.core.files.uploadedfile import UploadedFile
5 from django.core.files.uploadhandler import FileUploadHandler, StopUpload, StopFutureHandlers
6 from django.http import JsonResponse
7 from django.views.decorators.csrf import csrf_exempt, csrf_protect
8
9 from filex.forms import HostPathForm
10 from filex.ftp import FTPOperation, FTPError
11
12
13 class FtpUploadHandler(FileUploadHandler):
14     ftp = None
15     url = None
16     tmp_url = None
17
18     def new_file(self, file_name, *args, **kwargs):
19         super(FtpUploadHandler, self).new_file(file_name, *args, **kwargs)
20
21         form = HostPathForm(self.request.GET)
22
23         if self.request.user.is_anonymous() or not form.is_valid():
24             raise StopUpload(connection_reset=True)
25
26         if self.ftp is None:
27             self.ftp = FTPOperation(self.request.session['proxy'], self.chunk_size)
28
29         self.url = 'gsiftp://{}/{}'.format(form.cleaned_data['host'],
30                                            os.path.join(form.cleaned_data['path'], self.file_name))
31         self.tmp_url = self.url + '.part'
32
33         self.ftp.put(self.tmp_url)
34
35         StopFutureHandlers()
36
37     def receive_data_chunk(self, raw_data, start):
38         self.ftp.stream.put(raw_data)
39
40     def file_complete(self, file_size):
41         # signal end of data and wait for finish
42         self.ftp.stream.put(None)
43         self.ftp.wait()
44
45         self.ftp.move(self.tmp_url, self.url)
46
47         return UploadedFile(name=self.file_name, size=file_size, charset=self.charset,
48                             content_type=self.content_type, content_type_extra=self.content_type_extra)
49
50
51 def with_ftp_upload_handler(view_func):
52     @wraps(view_func)
53     def wrapped_view(request, *args, **kwargs):
54         request.upload_handlers = [FtpUploadHandler(request)]
55
56         try:
57             return csrf_protect(view_func)(request, *args, **kwargs)
58         except FTPError as e:
59             status = 400
60             if 'No such file or directory' in e.message:
61                 status = 404
62             elif 'Permission denied' in e.message:
63                 status = 403
64
65             return JsonResponse({'error': e.message}, status=status)
66
67     return csrf_exempt(wrapped_view)