1 from itertools import islice
6 from django.contrib.auth.decorators import login_required
7 from django.core.exceptions import PermissionDenied
8 from django.http import JsonResponse, StreamingHttpResponse
9 from django.shortcuts import get_object_or_404, render
10 from django.template.defaultfilters import filesizeformat
11 from django.utils.formats import date_format
12 from django.utils.http import urlquote
13 from django.views.decorators.http import require_POST
14 from django.views.generic import View
16 from filex.forms import HostPathNameForm, RenameForm, FavoriteForm, HostPathForm, ExtractForm, HostItemsForm, \
18 from filex.ftp import FTPOperation, FTPError
19 from filex.models import Favorite
20 from filex.utils import with_ftp_upload_handler, parse_ftp_error
25 form_class = HostPathForm
29 def as_view(cls, **initkwargs):
30 def process(self, request):
31 if not request.user.is_authenticated():
32 raise PermissionDenied("Login required!")
33 if not request.session['proxy']:
34 raise PermissionDenied("No proxy found!")
36 form = self.form_class(request.POST if self.method == 'post' else request.GET)
38 if not form.is_valid():
39 return JsonResponse({'error': form.errors}, status=400)
41 self.request = request
43 return self.handle(FTPOperation(request.session['proxy']), form.cleaned_data)
45 msg, status = parse_ftp_error(e)
47 logger = logging.getLogger('gridftp')
48 logger.error(e.verbose, extra={'user': request.user, 'path': request.path, 'params': form.cleaned_data})
50 return JsonResponse({'error': msg}, status=status)
52 setattr(cls, cls.method, process)
54 return super(FTPView, cls).as_view(**initkwargs)
56 def handle(self, ftp, params):
57 raise NotImplementedError
60 class ListView(FTPView):
61 def handle(self, ftp, params):
62 listing = ftp.listing(make_url(params, 'path'))
65 # ignore . and .. from beginning of the listing
66 for item in islice(listing, 2, None):
67 item['size'] = filesizeformat(item['size'])
68 item['date'] = date_format(item['date'], 'CUSTOM_DATETIME_FORMAT')
72 return JsonResponse(data, safe=False)
75 class DownloadView(FTPView):
76 def handle(self, ftp, params):
77 url = make_url(params, 'path')
82 msg, status = parse_ftp_error(e)
84 return render(self.request, 'qcg/download_error.html', {'msg': msg, 'url': url}, status=status)
88 name = os.path.basename(params['path'])
89 mime_type, encoding = mimetypes.guess_type(name)
91 response = StreamingHttpResponse(data, content_type=mime_type or 'application/octet-stream')
92 response['Content-Disposition'] = 'attachment; filename*={}'.format(urlquote(name))
93 response['Content-Length'] = stats['size']
96 response['Content-Encoding'] = encoding
101 class InfoView(FTPView):
102 def handle(self, ftp, params):
103 return JsonResponse(ftp.info(make_url(params, 'path')))
106 class DeleteView(FTPView):
108 form_class = HostItemsForm
110 def handle(self, ftp, params):
111 url = make_url(params)
114 for path in params['dirs']:
116 ftp.rmdir(url + urlquote(path))
117 except FTPError as e:
118 fail[path] = e.message
122 for path in params['files']:
124 ftp.delete(url + urlquote(path))
125 except FTPError as e:
126 fail[path] = e.message
130 return JsonResponse({'done': done, 'fail': fail})
133 class MkdirView(FTPView):
135 form_class = HostPathNameForm
137 def handle(self, ftp, params):
138 ftp.mkdir(make_url(params, 'path', 'name'))
140 return JsonResponse({'success': True})
143 class MoveView(FTPView):
145 form_class = RenameForm
147 def handle(self, ftp, params):
148 ftp.move(make_url(params, 'src'), make_url(params, 'dst'))
150 return JsonResponse({'success': True})
153 class CompressView(FTPView):
155 form_class = CompressForm
157 def handle(self, ftp, params):
159 # consume generator with command output
160 list(ftp.compress(make_url(params), params['path'], params['files'], params['archive']))
161 except ValueError as e:
162 return JsonResponse({'error': e.message}, status=400)
164 return JsonResponse({'success': True})
167 class ExtractView(FTPView):
169 form_class = ExtractForm
171 def handle(self, ftp, params):
173 # consume generator with command output
174 list(ftp.extract(make_url(params), params['path'], params['dst']))
175 except ValueError as e:
176 return JsonResponse({'error': e.message}, status=400)
178 return JsonResponse({'success': True})
181 def make_url(params, *parts):
182 return 'gsiftp://{}/{}'.format(params['host'],
183 urlquote(os.path.join(*[params[part] for part in parts]), safe='/~') if parts else '')
187 @with_ftp_upload_handler
189 return JsonResponse({'success': True})
194 def fav_add(request):
195 data = request.POST.copy()
196 data['owner'] = request.user.id
198 form = FavoriteForm(data)
200 if not form.is_valid():
201 return JsonResponse({'error': form.errors}, status=400)
204 FTPOperation(request.session['proxy']).info(make_url(form.cleaned_data, 'path'))
205 except FTPError as e:
206 msg, status = parse_ftp_error(e)
208 return JsonResponse({'error': msg}, status=status)
210 instance = form.save()
212 return JsonResponse({'group': 'usr', 'host': instance.host, 'path': instance.path,
213 'value': instance.host + '/' + instance.path})
218 def fav_delete(request):
219 fav = get_object_or_404(Favorite, owner=request.user, host=request.POST['host'], path=request.POST['path'])
222 return JsonResponse({'success': True})