Merge pull request 'Release new stuff from stage' (#87) from stage into production
All checks were successful
Run tests / Execute tox to run the test suite (push) Successful in 3m24s
All checks were successful
Run tests / Execute tox to run the test suite (push) Successful in 3m24s
Reviewed-on: #87
This commit was merged in pull request #87.
This commit is contained in:
@@ -19,7 +19,3 @@ recursive-include dav_registration/templates *
|
||||
include dav_event_office/module.json
|
||||
recursive-include dav_event_office/django_project_config *.py
|
||||
recursive-include dav_event_office/templates *
|
||||
# dav_submission
|
||||
include dav_submission/module.json
|
||||
recursive-include dav_submission/django_project_config *.py
|
||||
recursive-include dav_submission/templates *
|
||||
|
||||
@@ -579,6 +579,8 @@ class Event(models.Model):
|
||||
'registration_required': self.registration_required,
|
||||
'registration_howto': self.registration_howto,
|
||||
'deadline': self.deadline,
|
||||
'deadline_expired': self.is_deadline_expired(),
|
||||
'canceled': self.is_canceled(),
|
||||
'registration_closed': self.registration_closed,
|
||||
|
||||
'charge': self.charge,
|
||||
|
||||
@@ -6,10 +6,10 @@ app_name = 'dav_registration'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.RootView.as_view(), name='root'),
|
||||
url(r'^home$', views.HomeView.as_view(), name='home'),
|
||||
url(r'^finished', views.RegistrationSuccessView.as_view(), name='registered'),
|
||||
url(r'^event/(?P<pk>\d+)/registration', views.RegistrationView.as_view(), name='register'),
|
||||
url(r'^event/(?P<pk>\d+)/', views.EventDetailView.as_view(), name='event'),
|
||||
url(r'^event', views.EventListView.as_view(), name='events'),
|
||||
url(r'^api/v1/event', views.EventListAsJSONView, name='api_events'),
|
||||
url(r'^home/$', views.HomeView.as_view(), name='home'),
|
||||
url(r'^event/$', views.EventListView.as_view(), name='events'),
|
||||
url(r'^event/(?P<pk>\d+)/$', views.EventDetailView.as_view(), name='event'),
|
||||
url(r'^event/(?P<pk>\d+)/registration/$', views.RegistrationView.as_view(), name='register'),
|
||||
url(r'^finished/$', views.RegistrationSuccessView.as_view(), name='registered'),
|
||||
url(r'^api/v1/event/$', views.EventListAsJSONView, name='api_events'),
|
||||
]
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
default_app_config = 'dav_submission.apps.AppConfig' # pylint: disable=invalid-name
|
||||
@@ -1,23 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
from django.conf import settings
|
||||
|
||||
from dav_base.config.apps import AppConfig as _AppConfig, DefaultSetting
|
||||
|
||||
DEFAULT_SETTINGS = (
|
||||
DefaultSetting('notify_address', 'webmaster@alpenverein-karlsruhe.de'),
|
||||
DefaultSetting('enable_upload', True),
|
||||
DefaultSetting('upload_path', os.path.join(settings.BASE_VAR_DIR, 'lib', 'dav_submission', 'submissions')),
|
||||
DefaultSetting('max_files', 5),
|
||||
DefaultSetting('max_file_size_mib', 50),
|
||||
DefaultSetting('max_total_size_mib', 100),
|
||||
DefaultSetting('metadata_file_name', 'metadata.txt'),
|
||||
DefaultSetting('cached_zip_file_name', '.cache.zip'),
|
||||
DefaultSetting('download_group', 'downloaders'),
|
||||
)
|
||||
|
||||
|
||||
class AppConfig(_AppConfig):
|
||||
name = 'dav_submission'
|
||||
verbose_name = 'DAV Beitragsupload (150 Jahre DAV)'
|
||||
default_settings = DEFAULT_SETTINGS
|
||||
@@ -1,12 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
from django.conf import settings
|
||||
|
||||
# NOTIFY_ADDRESS = 'webmaster@alpenverein-karlsruhe.de'
|
||||
# UPLOAD_PATH = os.path.join(settings.BASE_VAR_DIR, 'lib', 'dav_submission', 'submissions')
|
||||
# MAX_FILES = 5
|
||||
# MAX_FILE_SIZE_MIB = 50
|
||||
# MAX_TOTAL_SIZE_MIB = 100
|
||||
# METADATA_FILE_NAME = 'metadata.txt'
|
||||
# CACHED_ZIP_FILE_NAME = '.cache.zip'
|
||||
# DOWNLOAD_GROUP = 'downloaders'
|
||||
@@ -1,32 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from django.apps import apps
|
||||
|
||||
from dav_base.emails import AbstractMail
|
||||
|
||||
app_config = apps.get_containing_app_config(__package__)
|
||||
|
||||
|
||||
class NewSubmissionMail(AbstractMail): # pylint: disable=too-few-public-methods
|
||||
_subject = 'Neuer Beitrag: {title}'
|
||||
_template_name = 'dav_submission/emails/new_submission.txt'
|
||||
|
||||
def __init__(self, metadata):
|
||||
self._metadata = metadata
|
||||
|
||||
def _get_subject(self, subject_fmt=None, **kwargs):
|
||||
kwargs['title'] = self._metadata['title']
|
||||
return super()._get_subject(subject_fmt=subject_fmt, **kwargs)
|
||||
|
||||
def _get_reply_to(self):
|
||||
reply_to = '"{fullname}" <{email}>'.format(fullname=self._metadata['name'],
|
||||
email=self._metadata['email_address'])
|
||||
return [reply_to]
|
||||
|
||||
def _get_recipients(self):
|
||||
r = app_config.settings.notify_address
|
||||
return [r]
|
||||
|
||||
def _get_context_data(self, extra_context=None):
|
||||
context = super()._get_context_data(extra_context=extra_context)
|
||||
context['metadata'] = self._metadata
|
||||
return context
|
||||
@@ -1,124 +0,0 @@
|
||||
# -*- 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=_('Dein Name'),
|
||||
help_text=_('Wenn wir wissen, wie du heißt, wird uns das echt weiter helfen'))
|
||||
email_address = forms.EmailField(label=_('Deine E-Mail-Adresse'),
|
||||
help_text=_('Damit wir dich für Rückfragen kontaktieren können'))
|
||||
|
||||
group = forms.CharField(max_length=1024,
|
||||
required=False,
|
||||
label=_('DAV Gruppe'),
|
||||
help_text=_('Optional, falls du aktiv in einer der Sektionsgruppen bist'))
|
||||
|
||||
title = forms.CharField(max_length=60,
|
||||
label=_('Titel deines Beitrags / Stichwort'),
|
||||
help_text='%s<br />\n%s' % (
|
||||
_('Kommt zum Bild, falls es veröffentlicht wird'),
|
||||
_('Maximal 60 Zeichen')
|
||||
))
|
||||
|
||||
description = forms.CharField(max_length=300,
|
||||
label=_('Beschreibung'),
|
||||
help_text='%s<br />\n%s' % (
|
||||
_('Wo warst du? Was hast du gemacht? Worum ging es bei der Aktion?'),
|
||||
_('Maximal 300 Zeichen')
|
||||
),
|
||||
widget=forms.Textarea(attrs={'rows': 2}))
|
||||
|
||||
files = forms.FileField(label=_('Dateien'),
|
||||
help_text=_('Wenn du auf den Button klickst, kannst du mehrere Dateien auswählen'
|
||||
' (nötigenfalls Strg- oder Command-Taste benutzen)'),
|
||||
widget=forms.ClearableFileInput(attrs={'multiple': True}))
|
||||
|
||||
accepted = forms.BooleanField(required=False,
|
||||
label=_('Ja, ich stimme den Teilnahmebedingungen zu!'))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.fields['title'].widget.attrs['placeholder'] = \
|
||||
'z.B. Nacktbesteigung der Nose' \
|
||||
' oder Juma jümart Jung-Mann-Weg'[:self.fields['title'].max_length]
|
||||
|
||||
self.fields['group'].widget.attrs['placeholder'] = \
|
||||
ugettext('Kann frei gelassen werden')[:self.fields['title'].max_length]
|
||||
|
||||
help_text = self.fields['files'].help_text
|
||||
if app_config.settings.max_files:
|
||||
help_text += '<br />\n%s' % (ugettext('Wähle bis zu %d Dateien aus')
|
||||
% app_config.settings.max_files)
|
||||
if app_config.settings.max_file_size_mib:
|
||||
help_text += '<br />\n%s' % (ugettext('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 += '<br />\n%s' % (ugettext('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:
|
||||
e = forms.ValidationError(
|
||||
ugettext('Dateiname nicht erlaubt: %s') % file.name,
|
||||
code='filename_not_allowed',
|
||||
)
|
||||
validation_errors.append(e)
|
||||
if max_file_size and file.size > max_file_size:
|
||||
e = forms.ValidationError(
|
||||
ugettext('Die Datei ist insgesamt zu groß:'
|
||||
' %(name)s (> %(max_mib)s MiB)') % {'name': file.name, 'max_mib': max_file_size_mib},
|
||||
code='file_to_big',
|
||||
)
|
||||
validation_errors.append(e)
|
||||
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:
|
||||
e = forms.ValidationError(
|
||||
ugettext('Dein Beitrag ist zu groß (%s MiB)') % max_total_size_mib,
|
||||
code='files_to_big',
|
||||
)
|
||||
validation_errors.append(e)
|
||||
|
||||
if max_files and n_files > max_files:
|
||||
e = forms.ValidationError(
|
||||
ugettext('Dein Beitrag enthält mehr als %d Dateien') % max_files,
|
||||
code='files_to_big',
|
||||
)
|
||||
validation_errors.append(e)
|
||||
|
||||
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('Um deinen Beitrag hochladen zu können,'
|
||||
' musst du den Teilnahmebedingungen zustimmen.'
|
||||
' Dazu musst du das Kästchen ankreuzen!'),
|
||||
code='not_accepted',
|
||||
)
|
||||
return val
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"url_prefix": "einreichung"
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{% extends "dav_base/base.html" %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block project-name %}150 Jahre Sektion Karlsruhe des Deutschen Alpenvereins{% endblock %}
|
||||
|
||||
{% block messages %}
|
||||
<div class="container">
|
||||
{% bootstrap_messages %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
Hallo Mein-DAV-Team,
|
||||
|
||||
jemand hat einen neuen Beitrag eingereicht.
|
||||
|
||||
Ihr könnt den Beitrag unter
|
||||
{{ base_url }}{% url 'dav_submission:list' %}
|
||||
herunterladen.
|
||||
|
||||
Absender: {{ metadata.name }} <{{ metadata.email_address }}>
|
||||
Gruppe: {{ metadata.group }}
|
||||
Datum: {{ metadata.date }} {{ metadata.time }}
|
||||
Titel: {{ metadata.title }}
|
||||
Beschreibung:
|
||||
{{ metadata.description }}
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
{% extends 'dav_submission/base.html' %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block page-container-fluid %}
|
||||
<h3 class="top-most">Einreichungen</h3>
|
||||
<div>
|
||||
<table id="objects_table" class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans 'Titel' %}</th>
|
||||
<th>{% trans 'Absender' %}</th>
|
||||
<th>{% trans 'Gruppe' %}</th>
|
||||
<th>{% trans 'Datum' %}</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><input type="text" placeholder="{% trans 'Filter' %}" /></th>
|
||||
<th><input type="text" placeholder="{% trans 'Filter' %}" /></th>
|
||||
<th><input type="text" placeholder="{% trans 'Filter' %}" /></th>
|
||||
<th><input type="text" placeholder="{% trans 'Filter' %}" /></th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for object in object_list %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ object.title }}
|
||||
</td>
|
||||
<td>
|
||||
{{ object.name }} (<a href="mailto:{{ object.email_address }}">{{ object.email_address }}</a>)
|
||||
</td>
|
||||
<td>
|
||||
{% if object.group %}
|
||||
{{ object.group }}
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td data-order="{{ object.timestamp|date:'U' }}">
|
||||
{{ object.timestamp|date:'l, d. F Y H:i:s e' }}
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'dav_submission:download' object.pk %}"
|
||||
class="btn btn-xs btn-primary"
|
||||
title="Download">{% bootstrap_icon 'download-alt' %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/javascript">
|
||||
$(document).ready( function () {
|
||||
var table = $("#objects_table").DataTable( {
|
||||
orderCellsTop: true,
|
||||
order: [[3, "asc"]],
|
||||
paging: false,
|
||||
language: {
|
||||
search: "{% trans 'Filter' %}:",
|
||||
info: "{% trans 'Zeige _TOTAL_ Einträge' %}",
|
||||
infoFiltered: "{% trans 'aus insgesamt _MAX_ Einträgen' %}",
|
||||
infoEmpty: "{% trans 'Zeige 0 Einträge' %}",
|
||||
infoPostFix: ".",
|
||||
emptyTable: "{% trans 'Keine Daten vorhanden.' %}",
|
||||
zeroRecords: "{% trans 'Keine passenden Einträge.' %}",
|
||||
|
||||
}
|
||||
} );
|
||||
$("#objects_table thead input").on( "keyup change", function() {
|
||||
table
|
||||
.column( $(this).parent().index() )
|
||||
.search( this.value )
|
||||
.draw();
|
||||
} );
|
||||
$("#objects_table_filter").hide();
|
||||
} );
|
||||
</script>
|
||||
</div>
|
||||
{% endblock page-container-fluid %}
|
||||
@@ -1,23 +0,0 @@
|
||||
{% extends 'dav_submission/base.html' %}
|
||||
|
||||
{% block page-container %}
|
||||
<h3 class="top-most">Geschafft!</h3>
|
||||
<div class="well">
|
||||
<p class="lead">
|
||||
Vielen Dank für deine Teilnahme.
|
||||
</p>
|
||||
<p>
|
||||
Wir haben deinen Beitrag erhalten und sind schon gespannt, dein Material sichten zu können.
|
||||
Falls wir noch Fragen haben, melden wir uns bei dir.
|
||||
</p>
|
||||
<p>
|
||||
Wir werden Fotos und Videos digital im Bistro und auf unserer Homepage präsentieren, das
|
||||
»Karlsruhe Alpin« damit bereichern, die schönsten Teilnahmen ab dem Sektionsfest 2020
|
||||
ausstellen und die besten ebenfalls am Sektionsfest 2020 prämieren.
|
||||
</p>
|
||||
<p>
|
||||
Falls du noch Fragen hast, erreichst du uns weiterhin über
|
||||
<a href="mailto:mein-dav@alpenverein-karlsruhe.de">mein-dav@alpenverein-karlsruhe.de</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,134 +0,0 @@
|
||||
{% extends 'dav_submission/base.html' %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block page-container %}
|
||||
<h3 class="top-most">150 Jahre DAV Karlsruhe - Einreichung</h3>
|
||||
<div class="well">
|
||||
<p class="lead"><i>Zeig uns Deinen DAV!</i></p>
|
||||
<p>
|
||||
Wir wünschen uns Fotos und Videos (am besten mit sichtbarem Jubiläumsbanner), Berichte, Anekdoten,
|
||||
Momente, Augenblicke, Foto-(Love-)Stories, Gipfeljubel, Alpen-Tänze, Hüttenlyrik, Biwakabenteuer,
|
||||
Naturgewaltentrotzgesichter, Schneegestöberkämpfe, Rote Nasen – blaue Zehen, Leidensromantik,
|
||||
Muskelspiele, Schweißperlen, Grenzerfahrungen, Chalkfinger, Sunset-Panoramas, Blumenmädchen,
|
||||
Adrenalinaugen, Knotenpunkte, Bunsenbrenner-Menüs, … alles, was uns euren DAV zeigt.
|
||||
</p>
|
||||
<p>
|
||||
Am besten digital als *.jpg oder *.pptx im Format 16:9.
|
||||
Wenn du deinen Beitrag hier absolut nicht rein bekommst
|
||||
(z.B. weil du nur ein einziges Dia-Positiv hast),
|
||||
dann melde dich per <a href="mailto:mein-dav@alpenverein-karlsruhe.de">E-Mail</a>
|
||||
und wir schauen, wie wir zu einer guten Lösung kommen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if show_upload_form %}
|
||||
{% 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.group 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 %}">
|
||||
Teilnahmebedingungen
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="well">
|
||||
<ul>
|
||||
<li>
|
||||
Die Teilnahme erfolgt über das Hochladen einer Datei bis zu einer Größe von 50 MB.
|
||||
</li>
|
||||
<li>
|
||||
Mehrere hochgeladene Dateien (bis zu 5 pro Aktion) werden als eine einzelne
|
||||
Teilnahme gewertet. Die Auswahl erfolgt durch das Organisationskomitee.
|
||||
</li>
|
||||
<li>
|
||||
Die Teilnahmen, die ausgestellt und prämiert werden, werden unter subjektiven
|
||||
Gesichtspunkten ausgewählt.
|
||||
</li>
|
||||
<li>
|
||||
Die Bekanntgabe der Prämierungen erfolgt am Sektionsfest 2020.
|
||||
</li>
|
||||
<li>
|
||||
Es werden Namen und E-Mail-Adresse der Teilnehmer/innen erfasst und gespeichert.
|
||||
Alle Daten werden spätestens 30 Tage nach dem Sektionsfest 2020 gelöscht,
|
||||
mit Ausnahme der Daten zu den Teilnahmen die ausgestellt werden. Adressdaten
|
||||
(v.a. E-Mail-Adressen) werden nicht veröffentlicht.
|
||||
Es werden keine Daten an Dritte weitergeben.
|
||||
Den Teilnehmern stehen gesetzliche Auskunfts-, Änderungs- und Widerrufsrechte zu.
|
||||
</li>
|
||||
<li>Indem du deine Datei (z.B. Foto oder Video) hochlädst, erklärst du mit der Teilnahme,
|
||||
dass du der/die alleinige Urheber/-in des Werkes bist und dieses frei von Rechten
|
||||
Dritter ist.
|
||||
Ferner räumst du der Sektion Karlsruhe des Deutschen Alpenverein (DAV) e.V.
|
||||
durch die Teilnahme das Recht ein, das Werk zeitlich und räumlich unbeschränkt in
|
||||
allen eigenen Medien, inbesondere in digitaler und gedruckter Form (vor allem in der
|
||||
Mitgliederzeitschrift »Karlsruhe Alpin«, in Veranstaltungsprogrammen,
|
||||
auf der Sektionshomepage, in Büchern, Faltblättern, Plakaten, Broschüren
|
||||
und weiteren Werbe- und Informationsmitteln sowie Anzeigen) zu vervielfältigen
|
||||
und zu verbreiten sowie öffentlich zugänglich zu machen.
|
||||
Ein Vergütungsanspruch besteht nicht. Du verzichtest auf deine Nennung als Urheber/in.
|
||||
Des Weiteren bestätigst du als Bildautor/in bzw. Videoersteller/in, dass alle auf den
|
||||
Bildern und in den Videos abgebildeten Personen (insbesondere Kinder) und ggf. deren
|
||||
Erziehungsberechtige mit der uneingeschränkten Veröffentlichung einverstanden sind und
|
||||
du dir das entsprechende Einverständnis der abgebildeten Personen eingeholt hast.
|
||||
</li>
|
||||
<li>
|
||||
Der Veranstalter der Aktion ist allein die Sektion Karlsruhe des
|
||||
Deutschen Alpenvereins (DAV) e.V.
|
||||
</li>
|
||||
<li>
|
||||
Durch die Teilnahme akzeptieren die Teilnehmer/innen allein diese Teilnahmebedingungen.
|
||||
Sämtliche Informationen, die die Teilnehmer/innen der Sektion Karlsruhe des
|
||||
Deutschen Alpenverein (DAV) e.V. im Rahmen der Teilnahme zur Verfügung stellen,
|
||||
werden ausschließlich der Sektion Karlsruhe bereitgestellt.
|
||||
</li>
|
||||
<li>
|
||||
<b>Nochmals: Alle abgebildeten Personen sind einverstanden.</b>
|
||||
</li>
|
||||
</ul>
|
||||
</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>
|
||||
{% endif %}
|
||||
{% endblock page-container %}
|
||||
@@ -1,12 +0,0 @@
|
||||
from django.conf.urls import url
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = 'dav_submission'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.UploadView.as_view(), name='root'),
|
||||
url(r'^danke', views.SuccessView.as_view(), name='success'),
|
||||
url(r'^download/(?P<pk>.+)', views.DownloadView.as_view(), name='download'),
|
||||
url(r'^download', views.ListView.as_view(), name='list'),
|
||||
]
|
||||
@@ -1,295 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import codecs
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import urllib
|
||||
import zipfile
|
||||
import pytz
|
||||
from django.apps import apps
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
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.decorators import method_decorator
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views import generic
|
||||
|
||||
from .emails import NewSubmissionMail
|
||||
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,
|
||||
'group': None,
|
||||
'timestamp': None,
|
||||
}
|
||||
with codecs.open(metadata_file_path, encoding='utf-8') 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'^Gruppe: (.*)$', line)
|
||||
if mo is not None:
|
||||
metadata['group'] = 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})[\s]*(.*)$', line)
|
||||
if mo is not None:
|
||||
date_str = mo.group(1)
|
||||
time_str = mo.group(2)
|
||||
zone_str = mo.group(3)
|
||||
if not zone_str:
|
||||
zone_str = timezone.get_current_timezone_name()
|
||||
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
|
||||
mo = re.match(r'^Beschreibung:$', line)
|
||||
if mo is not None:
|
||||
break
|
||||
|
||||
all_metadata[subdir] = metadata
|
||||
|
||||
sorted(subdirs)
|
||||
qs = [all_metadata[subdir] for subdir in subdirs]
|
||||
return qs
|
||||
|
||||
@method_decorator(login_required)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
permission_group = app_config.settings.download_group
|
||||
if not request.user.groups.filter(name=permission_group).exists():
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class DownloadView(generic.DetailView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
cached_zip_file_name = app_config.settings.cached_zip_file_name
|
||||
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)
|
||||
|
||||
submission_dir = os.path.join(base_path, subdir)
|
||||
|
||||
if not os.path.isdir(submission_dir):
|
||||
raise Http404()
|
||||
|
||||
cached_zip = os.path.join(submission_dir, cached_zip_file_name)
|
||||
if not os.path.isfile(cached_zip):
|
||||
with open(cached_zip, 'wb') as cache_f:
|
||||
with zipfile.ZipFile(cache_f, 'w') as z:
|
||||
for filename in os.listdir(submission_dir):
|
||||
if filename == cached_zip_file_name:
|
||||
continue
|
||||
z.write(os.path.join(submission_dir, filename), os.path.join(subdir, filename))
|
||||
|
||||
zip_f = open(cached_zip, 'rb')
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
response = FileResponse(streaming_content=zip_f, content_type=mime_type)
|
||||
disposition_header = 'attachment; filename="{}"'.format(disposition_file_name)
|
||||
response['Content-Disposition'] = disposition_header
|
||||
|
||||
return response
|
||||
|
||||
@method_decorator(login_required)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
permission_group = app_config.settings.download_group
|
||||
if not request.user.groups.filter(name=permission_group).exists():
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
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, filename):
|
||||
max_length = None
|
||||
discard_chars = ''
|
||||
replace_chars = {
|
||||
'ä': 'ae',
|
||||
'ö': 'oe',
|
||||
'ü': 'ue',
|
||||
'ß': 'ss',
|
||||
'Ä': 'Ae',
|
||||
'Ö': 'Oe',
|
||||
'Ü': 'Ue',
|
||||
}
|
||||
allowed_chars = ('abcdefghijklmnopqrstuvwxyz'
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
'0123456789'
|
||||
'._-')
|
||||
non_allowed_substitute = '_'
|
||||
space_substitute = '_'
|
||||
|
||||
if space_substitute is None:
|
||||
space_substitute = non_allowed_substitute
|
||||
|
||||
r = ''
|
||||
for c in filename:
|
||||
if c in discard_chars:
|
||||
continue
|
||||
elif c in replace_chars:
|
||||
r += replace_chars[c]
|
||||
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().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 = '{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 = _('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 = """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') + ' ' + timezone.get_current_timezone_name(),
|
||||
'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 = _('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().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 = _('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 = '%s MiB' % ('%.3f' % (size / 1024.0 / 1024.0)).rstrip('0').rstrip('.')
|
||||
elif size > 1024:
|
||||
size_str = '%s KiB' % ('%.3f' % (size / 1024.0)).rstrip('0').rstrip('.')
|
||||
else:
|
||||
size_str = '%d Byte' % size
|
||||
message = _('Datei erfolgreich hochgeladen: %(name)s (%(size)s)') % {'name': input_file.name,
|
||||
'size': size_str}
|
||||
messages.success(self.request, message)
|
||||
except Exception as e:
|
||||
message = _('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().form_valid(form)
|
||||
|
||||
mail = NewSubmissionMail(metadata_format_kwargs)
|
||||
mail.send()
|
||||
return super().form_valid(form)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not app_config.settings.enable_upload:
|
||||
raise PermissionDenied(_('Der Upload ist noch nicht freigeschaltet.'))
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
|
||||
class SuccessView(generic.TemplateView):
|
||||
template_name = 'dav_submission/success.html'
|
||||
Reference in New Issue
Block a user