# -*- coding: utf-8 -*- import codecs import datetime import logging import os import pytz import re import urllib from django.apps import apps from django.contrib import messages from django.core.exceptions import PermissionDenied from django.http import FileResponse, Http404 from django.urls import reverse_lazy from django.utils import timezone from django.utils.translation import ugettext as _ from django.views import generic from .forms import UploadForm app_config = apps.get_containing_app_config(__package__) logger = logging.getLogger(__name__) class ListView(generic.ListView): template_name = 'dav_submission/list.html' def get_queryset(self): base_path = app_config.settings.upload_path metadata_file_name = app_config.settings.metadata_file_name subdirs = os.listdir(base_path) all_metadata = {} for subdir in subdirs: metadata_file_path = os.path.join(base_path, subdir, metadata_file_name) if hasattr(urllib, 'quote_plus'): pk = urllib.quote_plus(subdir) else: pk = urllib.parse.quote_plus(subdir) metadata = { 'pk': pk, 'name': None, 'email_address': None, 'title': None, 'timestamp': None, } with open(metadata_file_path) as f: for line in f: mo = re.match(r'^Absender: (.*) <(.*)>$', line) if mo is not None: metadata['name'] = mo.group(1) metadata['email_address'] = mo.group(2) continue mo = re.match(r'^Titel: (.*)$', line) if mo is not None: metadata['title'] = mo.group(1) continue mo = re.match(r'^Datum: ([0-9]{2}.[0-9]{2}.[0-9]{4}) ([0-9]{2}:[0-9]{2}:[0-9]{2}) (.*)$', line) if mo is not None: date_str = mo.group(1) time_str = mo.group(2) zone_str = mo.group(3) datetime_str = '{} {}'.format(date_str, time_str) timestamp = datetime.datetime.strptime(datetime_str, '%d.%m.%Y %H:%M:%S') tz = pytz.timezone(zone_str) metadata['timestamp'] = tz.localize(timestamp) continue all_metadata[subdir] = metadata sorted(subdirs) qs = [all_metadata[subdir] for subdir in subdirs] return qs class DownloadView(generic.DetailView): def get(self, request, *args, **kwargs): base_path = app_config.settings.upload_path pk = kwargs.get('pk') if hasattr(urllib, 'unquote_plus'): subdir = urllib.unquote_plus(pk) else: subdir = urllib.parse.unquote_plus(pk) path = os.path.join(base_path, subdir) if not os.path.isdir(path): raise Http404() file_name = subdir file_ext = '.zip' mime_type = 'application/zip' disposition_file_name = '{file_name}{file_ext}'.format( file_name=file_name, file_ext=file_ext, ) raise Exception('Not Implemented yet') file_obj = open(path, 'rb') response = FileResponse(streaming_content=file_obj, content_type=mime_type) disposition_header = 'attachment; filename="{}"'.format(disposition_file_name) response['Content-Disposition'] = disposition_header return response class UploadView(generic.edit.FormView): initial = { # 'name': u'heinzel', # 'email_address': 'heinzel@heinzelwelt.de', # 'group': 'Alte Maschinen', # 'title': u'Mein Beitrag', # 'description': 'Foobar', # 'accepted': True, } template_name = 'dav_submission/upload_form.html' form_class = UploadForm success_url = reverse_lazy('dav_submission:success') def _sanitize_filename(self, input): max_length = None discard_chars = u'' allowed_chars = (u'abcdefghijklmnopqrstuvwxyz' u'äöüß' u'ABCDEFGHIJKLMNOPQRSTUVWXYZ' u'ÄÖÜ' u'0123456789' u'._-') non_allowed_substitute = u'_' space_substitute = u'_' if space_substitute is None: space_substitute = non_allowed_substitute r = '' for c in input: if c in discard_chars: continue elif allowed_chars is not None and c in allowed_chars: r += c elif allowed_chars is None and c.isalnum(): r += c elif c.isspace(): r += space_substitute else: r += non_allowed_substitute return r[:max_length] def get_context_data(self, **kwargs): c = super(UploadView, self).get_context_data(**kwargs) c['show_upload_form'] = app_config.settings.enable_upload return c def form_valid(self, form): base_path = app_config.settings.upload_path subdir_format_str = u'{datetime}--{title}' now = timezone.now() subdir_format_kwargs = {'datetime': now.strftime('%Y-%m-%d--%H%M%S'), 'date': now.strftime('%Y-%m-%d'), 'time': now.strftime('%H-%M-%S'), 'title': form.cleaned_data['title']} subdir_name = self._sanitize_filename( subdir_format_str.format(**subdir_format_kwargs) ) subdir_path = os.path.join(base_path, subdir_name) if os.path.isdir(subdir_path): message = _(u'Es gibt bereits einen Beitrag mit dem Titel "%(title)s".') % subdir_format_kwargs messages.error(self.request, message) form.add_error('title', message) return self.render_to_response(self.get_context_data(form=form)) os.makedirs(subdir_path) try: metadata_format_str = u"""Absender: {name} <{email_address}> Gruppe: {group} Datum: {date} {time} Titel: {title} Beschreibung: {description} """ metadata_format_kwargs = { 'date': timezone.localtime(now).strftime('%d.%m.%Y'), 'time': timezone.localtime(now).strftime('%H:%M:%S %Z'), 'name': form.cleaned_data['name'], 'email_address': form.cleaned_data['email_address'], 'group': form.cleaned_data['group'], 'title': form.cleaned_data['title'], 'description': form.cleaned_data['description'], } metadata = metadata_format_str.format(**metadata_format_kwargs) metadata_file_name = app_config.settings.metadata_file_name metadata_file_path = os.path.join(subdir_path, metadata_file_name) with codecs.open(metadata_file_path, 'w', encoding='utf-8') as metadata_file: metadata_file.write(metadata) except Exception as e: message = _(u'Jetzt ist irgendwas schief gelaufen.') messages.error(self.request, message) logger.error('dav_submission.views.UploadView.form_valid(): Catched Exception #2: %s', str(e)) return super(UploadView, self).form_valid(form) try: for input_file in form.files.getlist('files'): file_name = self._sanitize_filename(input_file.name) file_path = os.path.join(subdir_path, file_name) if os.path.exists(file_path): message = _(u'Die Datei %(name)s haben wir bereits.') % {'name': input_file.name} messages.error(self.request, message) continue with open(file_path, 'wb+') as local_file: for chunk in input_file.chunks(): local_file.write(chunk) size = os.path.getsize(file_path) if size > (1024 * 1024): size_str = u'%s MiB' % ('%.3f' % (size / 1024.0 / 1024.0)).rstrip('0').rstrip('.') elif size > 1024: size_str = u'%s KiB' % ('%.3f' % (size / 1024.0)).rstrip('0').rstrip('.') else: size_str = u'%d Byte' % size message = _(u'Datei erfolgreich hochgeladen: %(name)s (%(size)s)') % {'name': input_file.name, 'size': size_str} messages.success(self.request, message) except Exception as e: message = _(u'Jetzt ist irgendwas schief gelaufen.') messages.error(self.request, message) logger.error('dav_submission.views.UploadView.form_valid(): Catched Exception #3: %s', str(e)) return super(UploadView, self).form_valid(form) return super(UploadView, self).form_valid(form) def post(self, request, *args, **kwargs): if not app_config.settings.enable_upload: raise PermissionDenied(_(u'Der Upload ist noch nicht freigeschaltet.')) return super(UploadView, self).post(request, *args, **kwargs) class SuccessView(generic.TemplateView): template_name = 'dav_submission/success.html'