-from itertools import islice
+import logging
import mimetypes
import os
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.http import JsonResponse, StreamingHttpResponse
-from django.shortcuts import get_object_or_404
+from django.shortcuts import get_object_or_404, render
from django.template.defaultfilters import filesizeformat
from django.utils.formats import date_format
+from django.utils.http import urlquote
from django.views.decorators.http import require_POST
from django.views.generic import View
from filex.forms import HostPathNameForm, RenameForm, FavoriteForm, HostPathForm, ExtractForm, HostItemsForm, \
CompressForm
-from filex.ftp import FTPOperation, FTPException
+from filex.ftp import FTPOperation, FTPError
from filex.models import Favorite
-from filex.uploadhandler import with_ftp_upload_handler
+from filex.utils import with_ftp_upload_handler, parse_ftp_error
class FTPView(View):
method = 'get'
form_class = HostPathForm
+ request = None
@classmethod
def as_view(cls, **initkwargs):
if not form.is_valid():
return JsonResponse({'error': form.errors}, status=400)
+ self.request = request
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
+ except FTPError as e:
+ msg, status = parse_ftp_error(e)
- return JsonResponse({'error': e.message}, status=status)
+ logger = logging.getLogger('gridftp')
+ logger.error(e.verbose, extra={'user': request.user, 'path': request.path, 'params': form.cleaned_data})
+
+ return JsonResponse({'error': msg}, status=status)
setattr(cls, cls.method, process)
listing = ftp.listing(make_url(params, 'path'))
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')
+ for item in listing:
+ if item['name'] not in ['.', '..']:
+ item['size'] = filesizeformat(item['size'])
+ item['date'] = date_format(item['date'], 'CUSTOM_DATETIME_FORMAT')
- data.append(item)
+ data.append(item)
return JsonResponse(data, safe=False)
class DownloadView(FTPView):
def handle(self, ftp, params):
- data = ftp.get(make_url(params, 'path'))
+ url = make_url(params, 'path')
+
+ try:
+ stats = ftp.info(url)
+ except FTPError as e:
+ msg, status = parse_ftp_error(e)
+
+ return render(self.request, 'qcg/download_error.html', {'msg': msg, 'url': url}, status=status)
+
+ data = ftp.get(url)
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 (?)
+ response['Content-Disposition'] = 'attachment; filename*={}'.format(urlquote(name))
+ response['Content-Length'] = stats['size']
if encoding:
response['Content-Encoding'] = encoding
for path in params['dirs']:
try:
- ftp.rmdir(url + path)
- except FTPException as e:
+ ftp.rmdir(url + urlquote(path))
+ except FTPError as e:
fail[path] = e.message
else:
done.append(path)
for path in params['files']:
try:
- ftp.delete(url + path)
- except FTPException as e:
+ ftp.delete(url + urlquote(path))
+ except FTPError as e:
fail[path] = e.message
else:
done.append(path)
def make_url(params, *parts):
- return 'gsiftp://{}/{}'.format(params['host'], os.path.join(*[params[part] for part in parts]) if parts else '')
+ return 'gsiftp://{}/{}'.format(params['host'],
+ urlquote(os.path.join(*[params[part] for part in parts]), safe='/~') if parts else '')
@require_POST
form = FavoriteForm(data)
- # TODO check if path exists
- if form.is_valid():
- instance = form.save()
+ if not form.is_valid():
+ return JsonResponse({'error': form.errors}, status=400)
+
+ try:
+ FTPOperation(request.session['proxy']).info(make_url(form.cleaned_data, 'path'))
+ except FTPError as e:
+ msg, status = parse_ftp_error(e)
+
+ return JsonResponse({'error': msg}, status=status)
- return JsonResponse({'group': 'usr', 'host': instance.host, 'path': instance.path,
- 'value': instance.host + '/' + instance.path})
+ instance = form.save()
- return JsonResponse({'error': form.errors}, status=400)
+ return JsonResponse({'group': 'usr', 'host': instance.host, 'path': instance.path,
+ 'value': instance.host + '/' + instance.path})
@require_POST