+from itertools import islice
import mimetypes
+import os
from django.contrib.auth.decorators import login_required
-from django.core.exceptions import PermissionDenied, SuspiciousOperation
+from django.core.exceptions import PermissionDenied
from django.http import JsonResponse, StreamingHttpResponse
from django.shortcuts import get_object_or_404
from django.template.defaultfilters import filesizeformat
from django.utils.formats import date_format
from django.views.decorators.http import require_POST
+from django.views.generic import View
-from filex.forms import NewDirForm, RenameForm, FavoriteForm
+from filex.forms import HostPathNameForm, RenameForm, FavoriteForm, HostPathForm, ExtractForm, HostItemsForm, \
+ CompressForm
from filex.ftp import FTPOperation, FTPException
from filex.models import Favorite
from filex.uploadhandler import with_ftp_upload_handler
-def check_auth(request):
- if not request.user.is_authenticated():
- raise PermissionDenied("Login required!")
- if not request.session['proxy']:
- raise PermissionDenied("No proxy found!")
+class FTPView(View):
+ method = 'get'
+ form_class = HostPathForm
+ @classmethod
+ def as_view(cls, **initkwargs):
+ def process(self, request):
+ if not request.user.is_authenticated():
+ raise PermissionDenied("Login required!")
+ if not request.session['proxy']:
+ raise PermissionDenied("No proxy found!")
-def list_content(request):
- check_auth(request)
+ form = self.form_class(request.POST if self.method == 'post' else request.GET)
- # TODO data validation
- host = request.GET.get('host')
- path = request.GET.get('path')
- if not host or not path:
- raise SuspiciousOperation("No path or host given!")
+ if not form.is_valid():
+ return JsonResponse({'error': form.errors}, status=400)
- url = 'gsiftp://' + host + path
+ try:
+ return self.handle(FTPOperation(request.session['proxy']), form.cleaned_data)
+ except FTPException as e:
+ status = 400
+ if 'No such file or directory' in e.message:
+ status = 404
+ elif 'Permission denied' in e.message:
+ status = 403
- try:
- listing = FTPOperation(request.session['proxy']).listing(url)
- except FTPException as e:
- return JsonResponse({'msg': e.message}, status=400)
+ return JsonResponse({'error': e.message}, status=status)
- data = []
- for item in listing:
- item['size'] = filesizeformat(item['size'])
- item['date'] = date_format(item['date'], 'CUSTOM_DATETIME_FORMAT')
+ setattr(cls, cls.method, process)
- data.append(item)
+ return super(FTPView, cls).as_view(**initkwargs)
- return JsonResponse(data, safe=False)
+ def handle(self, ftp, params):
+ raise NotImplementedError
-def download(request):
- check_auth(request)
+class ListView(FTPView):
+ def handle(self, ftp, params):
+ listing = ftp.listing(make_url(params, 'path'))
- # TODO data validation
- host = request.GET.get('host')
- path = request.GET.get('path')
- name = request.GET.get('name')
- if not host or not path or not name:
- raise SuspiciousOperation("No path or host or name given!")
+ data = []
+ # ignore . and .. from beginning of the listing
+ for item in islice(listing, 2, None):
+ item['size'] = filesizeformat(item['size'])
+ item['date'] = date_format(item['date'], 'CUSTOM_DATETIME_FORMAT')
- url = 'gsiftp://' + host + path + '/' + name
+ data.append(item)
- mime_type, encoding = mimetypes.guess_type(name)
+ return JsonResponse(data, safe=False)
- response = StreamingHttpResponse(FTPOperation(request.session['proxy']).get(url),
- content_type=mime_type or 'application/octet-stream')
- response['Content-Disposition'] = 'attachment; filename={}'.format(name)
- # TODO Content-Length (?)
- if encoding:
- response['Content-Encoding'] = encoding
+class DownloadView(FTPView):
+ def handle(self, ftp, params):
+ data = ftp.get(make_url(params, 'path'))
- return response
+ name = os.path.basename(params['path'])
+ mime_type, encoding = mimetypes.guess_type(name)
+ response = StreamingHttpResponse(data, content_type=mime_type or 'application/octet-stream')
+ response['Content-Disposition'] = u'attachment; filename={}'.format(name)
+ # TODO Content-Length (?)
-@with_ftp_upload_handler
-def upload(request):
- # TODO error handling
- return JsonResponse({'success': True})
+ if encoding:
+ response['Content-Encoding'] = encoding
+ return response
-def info(request):
- check_auth(request)
- # TODO data validation
- host = request.GET.get('host')
- path = request.GET.get('path')
- if not host or not path:
- raise SuspiciousOperation("No path or host given!")
+class InfoView(FTPView):
+ def handle(self, ftp, params):
+ return JsonResponse(ftp.info(make_url(params, 'path')))
- url = 'gsiftp://' + host + path
- try:
- return JsonResponse(FTPOperation(request.session['proxy']).info(url))
- except FTPException as e:
- status = 400
- if 'No such file or directory' in e.message:
- status = 404
- elif 'Permission denied' in e.message:
- status = 403
+class DeleteView(FTPView):
+ method = 'post'
+ form_class = HostItemsForm
- return JsonResponse({'msg': e.message}, status=status)
+ def handle(self, ftp, params):
+ url = make_url(params)
+ done, fail = [], {}
+ for path in params['dirs']:
+ try:
+ ftp.rmdir(url + path)
+ except FTPException as e:
+ fail[path] = e.message
+ else:
+ done.append(path)
-@require_POST
-def delete(request):
- check_auth(request)
+ for path in params['files']:
+ try:
+ ftp.delete(url + path)
+ except FTPException as e:
+ fail[path] = e.message
+ else:
+ done.append(path)
- # TODO data validation
- host = request.POST.get('host')
- path = request.POST.get('path')
- dirs = request.POST.getlist('dirs')
- files = request.POST.getlist('files')
- if not host or not path or not (files or dirs):
- raise SuspiciousOperation("No path or host or files given!")
+ return JsonResponse({'done': done, 'fail': fail})
- url = 'gsiftp://' + host + path + '/'
- ftp = FTPOperation(request.session['proxy'])
- done, fail = [], {}
+class MkdirView(FTPView):
+ method = 'post'
+ form_class = HostPathNameForm
- for name in dirs:
- try:
- ftp.rmdir(url + name)
- except FTPException as e:
- fail[name] = e.message
- else:
- done.append(name)
+ def handle(self, ftp, params):
+ ftp.mkdir(make_url(params, 'path', 'name'))
- for name in files:
- try:
- ftp.delete(url + name)
- except FTPException as e:
- fail[name] = e.message
- else:
- done.append(name)
+ return JsonResponse({'success': True})
- return JsonResponse({'done': done, 'fail': fail})
+class MoveView(FTPView):
+ method = 'post'
+ form_class = RenameForm
-@require_POST
-def mkdir(request):
- check_auth(request)
+ def handle(self, ftp, params):
+ print params
+ ftp.move(make_url(params, 'src'), make_url(params, 'dst'))
- # TODO actual data validation
- form = NewDirForm(request.POST)
+ return JsonResponse({'success': True})
- if form.is_valid():
- host = form.cleaned_data['host']
- path = form.cleaned_data['path']
- name = form.cleaned_data['name']
- url = 'gsiftp://' + host + path + '/' + name
+class CompressView(FTPView):
+ method = 'post'
+ form_class = CompressForm
+ def handle(self, ftp, params):
try:
- FTPOperation(request.session['proxy']).mkdir(url)
- except FTPException as e:
- msg = e.message
- else:
- return JsonResponse({'success': True})
- else:
- msg = form.errors
-
- return JsonResponse({'msg': msg}, status=400)
-
+ # consume generator with command output
+ list(ftp.compress(make_url(params), params['path'], params['files'], params['archive']))
+ except ValueError as e:
+ return JsonResponse({'error': e.message}, status=400)
-@require_POST
-def move(request):
- check_auth(request)
-
- # TODO actual data validation
- form = RenameForm(request.POST)
+ return JsonResponse({'success': True})
- if form.is_valid():
- host = form.cleaned_data['host']
- path = form.cleaned_data['path']
- src = form.cleaned_data['src']
- dst = form.cleaned_data['dst']
- src_url = 'gsiftp://' + host + path + '/' + src
- dst_url = 'gsiftp://' + host + path + '/' + dst
+class ExtractView(FTPView):
+ method = 'post'
+ form_class = ExtractForm
+ def handle(self, ftp, params):
try:
- FTPOperation(request.session['proxy']).move(src_url, dst_url)
- except FTPException as e:
- msg = e.message
- else:
- return JsonResponse({'success': True})
- else:
- msg = form.errors
+ # consume generator with command output
+ list(ftp.extract(make_url(params), params['path'], params['dst']))
+ except ValueError as e:
+ return JsonResponse({'error': e.message}, status=400)
- return JsonResponse({'msg': msg}, status=400)
+ return JsonResponse({'success': True})
-@require_POST
-def compress(request):
- check_auth(request)
-
- # TODO data validation
- host = request.POST.get('host')
- path = request.POST.get('path')
- files = request.POST.getlist('files')
- archive = request.POST.get('archive')
- if not host or not path or not files or not archive:
- raise SuspiciousOperation("No path or host or files or archive given!")
-
- server = 'gsiftp://' + host
-
- try:
- # consume generator with command output
- list(FTPOperation(request.session['proxy']).compress(server, path, files, archive))
- except FTPException as e:
- return JsonResponse({'msg': e.message}, status=400)
- else:
- return JsonResponse({'success': True})
+def make_url(params, *parts):
+ return 'gsiftp://' + params['host'] + (os.path.join(*[params[part] for part in parts]) if parts else '')
@require_POST
-def extract(request):
- check_auth(request)
-
- # TODO data validation
- host = request.POST.get('host')
- archive = request.POST.get('archive')
- dst = request.POST.get('dst')
- if not host or not archive or not dst:
- raise SuspiciousOperation("No path or host or files or archive given!")
-
- server = 'gsiftp://' + host
-
- try:
- # consume generator with command output
- list(FTPOperation(request.session['proxy']).extract(server, archive, dst))
- except FTPException as e:
- return JsonResponse({'msg': e.message}, status=400)
- else:
- return JsonResponse({'success': True})
+@with_ftp_upload_handler
+def upload(request):
+ return JsonResponse({'success': True})
@require_POST
return JsonResponse({'group': 'usr', 'host': instance.host, 'path': instance.path,
'value': instance.host + instance.path})
- return JsonResponse({'msg': form.errors}, status=400)
+ return JsonResponse({'error': form.errors}, status=400)
@require_POST