ADD: added sub module dav_submission for supporting Manuel Hark with

his 150 Jahre DAV submission process.
This commit is contained in:
2019-03-07 11:36:40 +01:00
parent 6870aeafdd
commit 4a2411c705
10 changed files with 382 additions and 0 deletions

View File

@@ -0,0 +1 @@
default_app_config = 'dav_submission.apps.AppConfig'

20
dav_submission/apps.py Normal file
View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from dav_base.config.apps import AppConfig as _AppConfig, DefaultSetting
DEFAULT_SETTINGS = (
DefaultSetting('upload_path', os.path.join(settings.BASE_VAR_DIR, 'lib', 'dav_submission', 'submissions')),
DefaultSetting('max_files', 100),
DefaultSetting('max_file_size_mib', 50),
DefaultSetting('max_total_size_mib', 100),
DefaultSetting('metadata_file_name', 'metadata.txt'),
)
class AppConfig(_AppConfig):
name = 'dav_submission'
verbose_name = u'DAV Beitragsupload (150 Jahre DAV)'
default_settings = DEFAULT_SETTINGS

View File

@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
import os
from django.conf import settings
# UPLOAD_PATH = os.path.join(settings.BASE_VAR_DIR, 'lib', 'dav_submission', 'submissions')
# MAX_FILES = 100
# MAX_FILE_SIZE_MIB = 50
# MAX_TOTAL_SIZE_MIB = 100
# METADATA_FILE_NAME = 'metadata.txt'

108
dav_submission/forms.py Normal file
View File

@@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
from django import forms
from django.apps import apps
from django.utils.translation import ugettext, ugettext_lazy as _
app_config = apps.get_containing_app_config(__package__)
class UploadForm(forms.Form):
name = forms.CharField(max_length=1024,
label=_(u'Dein Name'),
help_text=_(u'Wenn wir wissen, wie du heißt, wird uns das echt weiter helfen'))
email_address = forms.EmailField(label=_(u'Deine E-Mail-Adresse'),
help_text=_(u'Lorem'))
title = forms.CharField(max_length=60,
label=_(u'Titel deines Beitrags / Stichwort'),
help_text=u'%s<br />%s' % (
_(u'Lorem'),
_(u'Maximal 60 Zeichen')
))
description = forms.CharField(label=_(u'Beschreibung'),
help_text=_(u'Lorem'),
widget=forms.Textarea(attrs={'rows': 2}))
files = forms.FileField(label=_(u'Dateien'),
help_text=_(u'Lorem'),
widget=forms.ClearableFileInput(attrs={'multiple': True}))
accepted = forms.BooleanField(required=False,
label=_(u'Ja, lorem!'))
def __init__(self, *args, **kwargs):
super(UploadForm, self).__init__(*args, **kwargs)
self.fields['title'].widget.attrs['placeholder'] = \
u'Climb & Bold - Nacktbesteigung der Nose'[:self.fields['title'].max_length]
help_text = self.fields['files'].help_text
if app_config.settings.max_files:
help_text += u'<br />%s' % (ugettext(u'Lade bis zu %d Dateien hoch')
% app_config.settings.max_files)
if app_config.settings.max_file_size_mib:
help_text += u'<br />%s' % (ugettext(u'Einzelne Dateien dürfen maximal %d MiB groß sein')
% app_config.settings.max_file_size_mib)
if app_config.settings.max_total_size_mib:
help_text += u'<br />%s' % (ugettext(u'Alle Dateien zusammen dürfen maximal %d MiB groß sein')
% app_config.settings.max_total_size_mib)
self.fields['files'].help_text = help_text
def clean_files(self):
not_allowed_file_names = (app_config.settings.metadata_file_name,)
max_files = app_config.settings.max_files
max_file_size_mib = app_config.settings.max_file_size_mib
max_total_size_mib = app_config.settings.max_total_size_mib
validation_errors = []
files = self.files.getlist('files')
max_file_size = max_file_size_mib * 1024 * 1024
size_total = 0
n_files = 0
for file in files:
if file.name in not_allowed_file_names:
ve = forms.ValidationError(
ugettext(u'Dateiname nicht erlaubt: %s') % file.name,
code='filename_not_allowed',
)
validation_errors.append(ve)
if max_file_size and file.size > max_file_size:
ve = forms.ValidationError(
ugettext(u'Die Datei ist insgesamt zu groß:'
u' %(name)s (> %(max_mib)s MiB)') % {'name': file.name, 'max_mib': max_file_size_mib},
code='file_to_big',
)
validation_errors.append(ve)
size_total += file.size
n_files += 1
max_total_size = max_total_size_mib * 1024 * 1024
if max_total_size and size_total > max_total_size:
ve = forms.ValidationError(
ugettext(u'Dein Beitrag ist zu groß (%s MiB)') % max_total_size_mib,
code='files_to_big',
)
validation_errors.append(ve)
if max_files and n_files > max_files:
ve = forms.ValidationError(
ugettext(u'Dein Beitrag enthält mehr als %d Dateien') % max_files,
code='files_to_big',
)
validation_errors.append(ve)
if validation_errors:
raise forms.ValidationError(validation_errors)
return files
def clean_accepted(self):
val = self.cleaned_data.get('accepted')
if not val:
raise forms.ValidationError(
ugettext(u'Sag ja! Du musst!'),
code='not_accepted',
)
return val

View File

@@ -0,0 +1,3 @@
{
"url_prefix": "150"
}

View File

@@ -0,0 +1,11 @@
{% extends "dav_base/base.html" %}
{% load bootstrap3 %}
{% block project-name %}150 Jahre DAV - Einreichung{% endblock %}
{% block messages %}
<div class="container">
{% bootstrap_messages %}
</div>
{% endblock %}

View File

@@ -0,0 +1,8 @@
{% extends 'dav_submission/base.html' %}
{% block page-container %}
<h3>Lorem!</h3>
<div class="well">
{% lorem %}
</div>
{% endblock %}

View File

@@ -0,0 +1,70 @@
{% extends 'dav_submission/base.html' %}
{% load bootstrap3 %}
{% block page-container %}
<h3>Lorem</h3>
<div class="well">
<p class="lead">Lorem ipsum dolor</p>
{% lorem %}
</div>
{% bootstrap_form_errors form %}
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
{% csrf_token %}
<div class="row">
<div class="col-md-10">
{% bootstrap_field form.name layout='horizontal' %}
{% bootstrap_field form.email_address layout='horizontal' %}
{% bootstrap_field form.title layout='horizontal' %}
</div>
</div>
<div class="row">
<div class="col-md-10">
{% bootstrap_field form.files layout='horizontal' %}
</div>
</div>
<div class="row">
<div class="col-md-10">
{% bootstrap_field form.description layout='horizontal' %}
</div>
</div>
<div class="row">
<div class="col-md-10">
<div class="row">
<div class="col-md-3">
<label class="pull-right {% if form.accepted.errors %}text-danger{% elif form.errors %}text-success{% endif %}">
Rechtliches
</label>
</div>
<div class="col-md-9">
<div class="well">
Kaufvertrag über eine Seele<br />
Verkäufer: du<br />
Käufer: Teufel<br />
<span style="font-size: 50%; line-height: 50%;">{% lorem %}<br/>{% lorem %}</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-10">
{% bootstrap_field form.accepted layout='horizontal' %}
</div>
</div>
<div class="row">
<div class="col-md-10">
<div class="col-md-3">
</div>
<div class="col-md-9">
{% buttons %}
<button class="btn btn-success" type="submit">Hochladen {% bootstrap_icon 'cloud-upload' %}</button>
<a href="{% url 'dav_submission:root' %}" class="btn btn-danger">Abbrechen {% bootstrap_icon 'remove' %}</a>
{% endbuttons %}
</div>
</div>
</div>
</form>
{% endblock page-container %}

8
dav_submission/urls.py Normal file
View File

@@ -0,0 +1,8 @@
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.UploadView.as_view(), name='root'),
url(r'danke', views.SuccessView.as_view(), name='success'),
]

144
dav_submission/views.py Normal file
View File

@@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
import codecs
import datetime
import logging
import os
from django.apps import apps
from django.contrib import messages
from django.urls import reverse_lazy
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 UploadView(generic.edit.FormView):
initial = {
# 'name': u'heinzel',
# 'email_address': 'heinzel@heinzelwelt.de',
# '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 form_valid(self, form):
base_path = app_config.settings.upload_path
subdir_format_str = u'{datetime}--{title}'
now = datetime.datetime.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}>
Datum: {date} {time}
Titel: {title}
Beschreibung:
{description}
"""
metadata_format_kwargs = {
'date': now.strftime('%d.%m.%Y'),
'time': now.strftime('%H:%M:%S'),
'name': form.cleaned_data['name'],
'email_address': form.cleaned_data['email_address'],
'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)
class SuccessView(generic.TemplateView):
template_name = 'dav_submission/success.html'