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.views.decorators.http import require_POST
13 from django.views.generic import View
15 from filex.forms import HostPathNameForm, RenameForm, FavoriteForm, HostPathForm, ExtractForm, HostItemsForm, \
17 from filex.ftp import FTPOperation, FTPError
18 from filex.models import Favorite
19 from filex.utils import with_ftp_upload_handler, parse_ftp_error
24 form_class = HostPathForm
28 def as_view(cls, **initkwargs):
29 def process(self, request):
30 if not request.user.is_authenticated():
31 raise PermissionDenied("Login required!")
32 if not request.session['proxy']:
33 raise PermissionDenied("No proxy found!")
35 form = self.form_class(request.POST if self.method == 'post' else request.GET)
37 if not form.is_valid():
38 return JsonResponse({'error': form.errors}, status=400)
40 self.request = request
42 return self.handle(FTPOperation(request.session['proxy']), form.cleaned_data)
44 msg, status = parse_ftp_error(e)
46 logger = logging.getLogger('gridftp')
47 logger.error(e.verbose, extra={'user': request.user, 'path': request.path, 'params': form.cleaned_data})
49 return JsonResponse({'error': msg}, status=status)
51 setattr(cls, cls.method, process)
53 return super(FTPView, cls).as_view(**initkwargs)
55 def handle(self, ftp, params):
56 raise NotImplementedError
59 class ListView(FTPView):
60 def handle(self, ftp, params):
61 listing = ftp.listing(make_url(params, 'path'))
64 # ignore . and .. from beginning of the listing
65 for item in islice(listing, 2, None):
66 item['size'] = filesizeformat(item['size'])
67 item['date'] = date_format(item['date'], 'CUSTOM_DATETIME_FORMAT')
71 return JsonResponse(data, safe=False)
74 class DownloadView(FTPView):
75 def handle(self, ftp, params):
76 url = make_url(params, 'path')
81 msg, status = parse_ftp_error(e)
83 return render(self.request, 'qcg/download_error.html', {'msg': msg, 'url': url}, status=status)
87 name = os.path.basename(params['path'])
88 mime_type, encoding = mimetypes.guess_type(name)
90 response = StreamingHttpResponse(data, content_type=mime_type or 'application/octet-stream')
91 response['Content-Disposition'] = u'attachment; filename={}'.format(name)
92 response['Content-Length'] = stats['size']
95 response['Content-Encoding'] = encoding
100 class InfoView(FTPView):
101 def handle(self, ftp, params):
102 return JsonResponse(ftp.info(make_url(params, 'path')))
105 class DeleteView(FTPView):
107 form_class = HostItemsForm
109 def handle(self, ftp, params):
110 url = make_url(params)
113 for path in params['dirs']:
115 ftp.rmdir(url + path)
116 except FTPError as e:
117 fail[path] = e.message
121 for path in params['files']:
123 ftp.delete(url + path)
124 except FTPError as e:
125 fail[path] = e.message
129 return JsonResponse({'done': done, 'fail': fail})
132 class MkdirView(FTPView):
134 form_class = HostPathNameForm
136 def handle(self, ftp, params):
137 ftp.mkdir(make_url(params, 'path', 'name'))
139 return JsonResponse({'success': True})
142 class MoveView(FTPView):
144 form_class = RenameForm
146 def handle(self, ftp, params):
147 ftp.move(make_url(params, 'src'), make_url(params, 'dst'))
149 return JsonResponse({'success': True})
152 class CompressView(FTPView):
154 form_class = CompressForm
156 def handle(self, ftp, params):
158 # consume generator with command output
159 list(ftp.compress(make_url(params), params['path'], params['files'], params['archive']))
160 except ValueError as e:
161 return JsonResponse({'error': e.message}, status=400)
163 return JsonResponse({'success': True})
166 class ExtractView(FTPView):
168 form_class = ExtractForm
170 def handle(self, ftp, params):
172 # consume generator with command output
173 list(ftp.extract(make_url(params), params['path'], params['dst']))
174 except ValueError as e:
175 return JsonResponse({'error': e.message}, status=400)
177 return JsonResponse({'success': True})
180 def make_url(params, *parts):
181 return 'gsiftp://{}/{}'.format(params['host'], os.path.join(*[params[part] for part in parts]) if parts else '')
185 @with_ftp_upload_handler
187 return JsonResponse({'success': True})
192 def fav_add(request):
193 data = request.POST.copy()
194 data['owner'] = request.user.id
196 form = FavoriteForm(data)
198 if not form.is_valid():
199 return JsonResponse({'error': form.errors}, status=400)
202 FTPOperation(request.session['proxy']).info(make_url(form.cleaned_data, 'path'))
203 except FTPError as e:
204 msg, status = parse_ftp_error(e)
206 return JsonResponse({'error': msg}, status=status)
208 instance = form.save()
210 return JsonResponse({'group': 'usr', 'host': instance.host, 'path': instance.path,
211 'value': instance.host + '/' + instance.path})
216 def fav_delete(request):
217 fav = get_object_or_404(Favorite, owner=request.user, host=request.POST['host'], path=request.POST['path'])
220 return JsonResponse({'success': True})