merge master into pm changes

v1-0-stable
Christian Merten 7 years ago
commit a97812e8c3

@ -0,0 +1,14 @@
import os
from celery import Celery
from django.conf import settings
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'jdav_web.settings')
app = Celery()
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(settings.INSTALLED_APPS)
if __name__ == '__main__':
app.start()

@ -48,6 +48,8 @@ INSTALLED_APPS = [
'members.apps.MembersConfig', 'members.apps.MembersConfig',
'mailer.apps.MailerConfig', 'mailer.apps.MailerConfig',
'easy_select2', 'easy_select2',
'djcelery_email',
'djcelery',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@ -162,3 +164,13 @@ EMAIL_PORT = 587 if deployed else 25
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', '') EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', '')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '') EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '')
EMAIL_USE_TLS = True if deployed else False EMAIL_USE_TLS = True if deployed else False
EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend'
# Admin setup
ADMINS = (('admin', 'christian@merten-moser.de'),)
# Celery and Redis setup
BROKER_URL = os.environ.get('BROKER_URL', 'redis://localhost:6379/0')

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-11 21:51+0200\n" "POT-Creation-Date: 2017-11-11 16:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -48,3 +48,11 @@ msgstr "Start"
#~ msgid "JDAV LB Administration" #~ msgid "JDAV LB Administration"
#~ msgstr "JDAV LB Verwaltung" #~ msgstr "JDAV LB Verwaltung"
#: utils.py:26
msgid "Filetype not supported."
msgstr "Dateityp nicht unterstützt."
#: utils.py:28
msgid "Please keep filesize under {}. Current filesize: {}"
msgstr "Maximale Dateigröße {}. Aktuelle Dateigröße: {}."

@ -5,9 +5,11 @@ from django.shortcuts import render
from django.db import models from django.db import models
from django import forms from django import forms
from easy_select2 import apply_select2 from easy_select2 import apply_select2
import json
from .models import Message, Attachment, MessageForm from .models import Message, Attachment, MessageForm
from .mailutils import NOT_SENT, PARTLY_SENT from .mailutils import NOT_SENT, PARTLY_SENT
from members.models import Member
class AttachmentInline(admin.TabularInline): class AttachmentInline(admin.TabularInline):
@ -53,6 +55,17 @@ class MessageAdmin(admin.ModelAdmin):
submit_message(obj, request) submit_message(obj, request)
return super(MessageAdmin, self).response_add(request, obj) return super(MessageAdmin, self).response_add(request, obj)
def get_form(self, request, obj=None, **kwargs):
form = super(MessageAdmin, self).get_form(request, obj, **kwargs)
raw_members = request.GET.get('members', None)
if raw_members is not None:
m_ids = json.loads(raw_members)
if type(m_ids) != list:
return form
members = Member.objects.filter(pk__in=m_ids)
form.base_fields['to_members'].initial = members
return form
class Media: class Media:
css = {'all': ('admin/css/tabular_hide_original.css',)} css = {'all': ('admin/css/tabular_hide_original.css',)}

@ -24,7 +24,7 @@ def send(subject, content, sender, recipients, reply_to=None,
for attach in attachments: for attach in attachments:
email.attach_file(attach) email.attach_file(attach)
try: try:
email.send() email.send(fail_silently=True)
except Exception as e: except Exception as e:
print("Error when sending mail:", e) print("Error when sending mail:", e)
failed = True failed = True

@ -3,7 +3,9 @@ from django.core.exceptions import ValidationError
from django import forms from django import forms
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ugettext from django.utils.translation import ugettext
from .mailutils import send, get_content, SENT, PARTLY_SENT, mail_root from .mailutils import send, get_content, NOT_SENT, SENT, PARTLY_SENT, mail_root
from utils import RestrictedFileField
from jdav_web.celery import app
import os import os
@ -11,28 +13,6 @@ import os
SENDING_ADDRESS = mail_root SENDING_ADDRESS = mail_root
class RestrictedFileField(models.FileField):
def __init__(self, *args, **kwargs):
if "max_upload_size" in kwargs:
self.max_upload_size = kwargs.pop("max_upload_size")
super(RestrictedFileField, self).__init__(*args, **kwargs)
def clean(self, *args, **kwargs):
data = super(RestrictedFileField, self).clean(*args, **kwargs)
f = data.file
try:
if f._size > self.max_upload_size:
raise forms.ValidationError('Please keep filesize under {}. '
'Current filesize: '
'{}'.format(self.max_upload_size,
f._size))
except AttributeError as e:
print(e)
return data
# Create your models here. # Create your models here.
class Message(models.Model): class Message(models.Model):
"""Represents a message that can be sent to some members""" """Represents a message that can be sent to some members"""
@ -93,17 +73,22 @@ class Message(models.Model):
# remove any underscores from subject to prevent Arne from using # remove any underscores from subject to prevent Arne from using
# terrible looking underscores in subjects # terrible looking underscores in subjects
self.subject = self.subject.replace('_', ' ') self.subject = self.subject.replace('_', ' ')
success = send(self.subject, get_content(self.content), try:
SENDING_ADDRESS, success = send(self.subject, get_content(self.content),
emails, SENDING_ADDRESS,
attachments=attach, emails,
reply_to=self.reply_to.email if self.reply_to else None) attachments=attach,
for a in Attachment.objects.filter(msg__id=self.pk): reply_to=self.reply_to.email if self.reply_to else None)
if a.f.name: if success == SENT or success == PARTLY_SENT:
os.remove(a.f.path) self.sent = True
a.delete() for a in Attachment.objects.filter(msg__id=self.pk):
if success == SENT or success == PARTLY_SENT: if a.f.name:
self.sent = True os.remove(a.f.path)
a.delete()
except Exception as e:
print("Exception catched", e)
success = NOT_SENT
finally:
self.save() self.save()
return success return success

@ -4,8 +4,9 @@ import os
import subprocess import subprocess
import shutil import shutil
import time import time
import unicodedata
from django.http import HttpResponse from django.http import HttpResponse, HttpResponseRedirect
from wsgiref.util import FileWrapper from wsgiref.util import FileWrapper
from django import forms from django import forms
from django.contrib import admin from django.contrib import admin
@ -74,6 +75,7 @@ class MemberAdmin(admin.ModelAdmin):
ForeignKey: {'widget': apply_select2(forms.Select)} ForeignKey: {'widget': apply_select2(forms.Select)}
} }
change_form_template = "members/change_member.html" change_form_template = "members/change_member.html"
actions = ['send_mail_to']
def change_view(self, request, object_id, form_url="", extra_context=None): def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {} extra_context = extra_context or {}
@ -83,6 +85,12 @@ class MemberAdmin(admin.ModelAdmin):
form_url=form_url, form_url=form_url,
extra_context=extra_context) extra_context=extra_context)
def send_mail_to(self, request, queryset):
member_pks = [m.pk for m in queryset]
query = str(member_pks).replace(' ', '')
return HttpResponseRedirect("/admin/mailer/message/add/?members={}".format(query))
send_mail_to.short_description = _('Compose new mail to selected members')
class GroupAdmin(admin.ModelAdmin): class GroupAdmin(admin.ModelAdmin):
fields = ['name', 'min_age'] fields = ['name', 'min_age']
@ -148,6 +156,9 @@ class MemberListAdmin(admin.ModelAdmin):
# create a unique filename # create a unique filename
filename = memberlist.name + "_" + datetime.today().strftime("%d_%m_%Y") filename = memberlist.name + "_" + datetime.today().strftime("%d_%m_%Y")
filename = filename.replace(' ', '_') filename = filename.replace(' ', '_')
# drop umlauts, accents etc.
filename = unicodedata.normalize('NFKD', filename).\
encode('ASCII', 'ignore').decode()
filename_table = 'table_' + filename filename_table = 'table_' + filename
filename_tex = filename + '.tex' filename_tex = filename + '.tex'
filename_pdf = filename + '.pdf' filename_pdf = filename + '.pdf'
@ -247,6 +258,9 @@ class MemberListAdmin(admin.ModelAdmin):
# unique filename # unique filename
filename = memberlist.name + "_note_" + datetime.today().strftime("%d_%m_%Y") filename = memberlist.name + "_note_" + datetime.today().strftime("%d_%m_%Y")
filename = filename.replace(' ', '_') filename = filename.replace(' ', '_')
# drop umlauts, accents etc.
filename = unicodedata.normalize('NFKD', filename).\
encode('ASCII', 'ignore').decode()
filename_tex = filename + '.tex' filename_tex = filename + '.tex'
filename_pdf = filename + '.pdf' filename_pdf = filename + '.pdf'

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-10-11 14:50+0200\n" "POT-Creation-Date: 2017-11-11 14:53+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -34,23 +34,27 @@ msgstr "Nein"
msgid "All" msgid "All"
msgstr "Alle" msgstr "Alle"
#: admin.py:100 #: admin.py:91
msgid "Compose new mail to selected members"
msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen"
#: admin.py:107
msgid "Difficulty" msgid "Difficulty"
msgstr "Schwierigkeit" msgstr "Schwierigkeit"
#: admin.py:104 #: admin.py:111
msgid "Tour type" msgid "Tour type"
msgstr "Art der Tour" msgstr "Art der Tour"
#: admin.py:242 #: admin.py:249
msgid "Convert to PDF" msgid "Convert to PDF"
msgstr "Kriseninterventionsliste erstellen" msgstr "Kriseninterventionsliste erstellen"
#: admin.py:348 #: admin.py:355
msgid "Generate overview" msgid "Generate overview"
msgstr "Hinweise für Jugendleiter erstellen" msgstr "Hinweise für Jugendleiter erstellen"
#: apps.py:7 models.py:107 #: apps.py:7 models.py:112
msgid "members" msgid "members"
msgstr "Teilnehmer" msgstr "Teilnehmer"
@ -62,7 +66,7 @@ msgstr "Name"
msgid "Description" msgid "Description"
msgstr "Beschreibung" msgstr "Beschreibung"
#: models.py:23 models.py:123 templates/members/change_member.html:9 #: models.py:23 models.py:128 templates/members/change_member.html:9
msgid "Activity" msgid "Activity"
msgstr "Aktivität" msgstr "Aktivität"
@ -138,87 +142,87 @@ msgstr "erstellt"
msgid "registration form" msgid "registration form"
msgstr "Anmeldeformular" msgstr "Anmeldeformular"
#: models.py:103 models.py:187 #: models.py:108 models.py:192
msgid "Group" msgid "Group"
msgstr "Gruppe" msgstr "Gruppe"
#: models.py:106 #: models.py:111
msgid "member" msgid "member"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: models.py:125 #: models.py:130
msgid "Place" msgid "Place"
msgstr "Ort" msgstr "Ort"
#: models.py:126 #: models.py:131
msgid "Destination (optional)" msgid "Destination (optional)"
msgstr "Ziel (optional)" msgstr "Ziel (optional)"
#: models.py:128 models.py:183 #: models.py:133 models.py:188
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
#: models.py:129 #: models.py:134
msgid "End (optional)" msgid "End (optional)"
msgstr "Ende" msgstr "Ende"
#: models.py:131 #: models.py:136
msgid "Groups" msgid "Groups"
msgstr "Gruppen" msgstr "Gruppen"
#: models.py:139 #: models.py:144
msgid "Categories" msgid "Categories"
msgstr "Kategorien" msgstr "Kategorien"
#: models.py:140 #: models.py:145
msgid "easy" msgid "easy"
msgstr "leicht" msgstr "leicht"
#: models.py:140 #: models.py:145
msgid "medium" msgid "medium"
msgstr "mittel" msgstr "mittel"
#: models.py:140 #: models.py:145
msgid "hard" msgid "hard"
msgstr "schwer" msgstr "schwer"
#: models.py:149 #: models.py:154
msgid "Memberlist" msgid "Memberlist"
msgstr "Teilnehmerliste" msgstr "Teilnehmerliste"
#: models.py:150 #: models.py:155
msgid "Memberlists" msgid "Memberlists"
msgstr "Teilnehmerlisten" msgstr "Teilnehmerlisten"
#: models.py:165 models.py:173 models.py:218 models.py:225 #: models.py:170 models.py:178 models.py:223 models.py:230
msgid "Member" msgid "Member"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: models.py:167 #: models.py:172
msgid "Comment" msgid "Comment"
msgstr "Kommentar" msgstr "Kommentar"
#: models.py:174 models.py:226 #: models.py:179 models.py:231
msgid "Members" msgid "Members"
msgstr "Teilnehmer" msgstr "Teilnehmer"
#: models.py:184 #: models.py:189
msgid "Location" msgid "Location"
msgstr "Ort" msgstr "Ort"
#: models.py:185 #: models.py:190
msgid "Topic" msgid "Topic"
msgstr "Thema" msgstr "Thema"
#: models.py:209 #: models.py:214
msgid "Jugendleiter" msgid "Jugendleiter"
msgstr "Jugendleiter" msgstr "Jugendleiter"
#: models.py:212 #: models.py:217
msgid "Klettertreff" msgid "Klettertreff"
msgstr "Klettertreff" msgstr "Klettertreff"
#: models.py:213 #: models.py:218
msgid "Klettertreffs" msgid "Klettertreffs"
msgstr "Klettertreffs" msgstr "Klettertreffs"

@ -3,6 +3,7 @@ import uuid
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from utils import RestrictedFileField
GEMEINSCHAFTS_TOUR = 0 GEMEINSCHAFTS_TOUR = 0
FUEHRUNGS_TOUR = 1 FUEHRUNGS_TOUR = 1
@ -67,7 +68,14 @@ class Member(models.Model):
comments = models.TextField(_('comments'), default='', blank=True) comments = models.TextField(_('comments'), default='', blank=True)
created = models.DateField(auto_now=True, verbose_name=_('created')) created = models.DateField(auto_now=True, verbose_name=_('created'))
registered = models.BooleanField(default=False, verbose_name=_('Registration complete')) registered = models.BooleanField(default=False, verbose_name=_('Registration complete'))
registration_form = models.ImageField(verbose_name=_('registration form'), blank=True) registration_form = RestrictedFileField(verbose_name=_('registration form'),
upload_to='registration_forms',
blank=True,
max_upload_size=5242880,
content_types=['application/pdf',
'image/jpeg',
'image/png',
'image/gif'])
def __str__(self): def __str__(self):
"""String representation""" """String representation"""

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-01-14 17:13+0100\n" "POT-Creation-Date: 2017-11-11 16:16+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"

@ -0,0 +1,34 @@
from django.db import models
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
class RestrictedFileField(models.FileField):
def __init__(self, *args, **kwargs):
if "max_upload_size" in kwargs:
self.max_upload_size = kwargs.pop("max_upload_size")
else:
self.max_upload_size = None
if "content_types" in kwargs:
self.content_types = kwargs.pop("content_types")
else:
self.content_types = None
super(RestrictedFileField, self).__init__(*args, **kwargs)
def clean(self, *args, **kwargs):
data = super(RestrictedFileField, self).clean(*args, **kwargs)
f = data.file
try:
content_type = f.content_type
if self.content_types is not None and content_type not in self.content_types:
raise ValidationError(_('Filetype not supported.'))
if self.max_upload_size is not None and f._size > self.max_upload_size:
raise ValidationError(_('Please keep filesize under {}. '
'Current filesize: '
'{}').format(self.max_upload_size,
f._size))
except AttributeError as e:
print(e)
return data

@ -70,7 +70,7 @@
\vspace{1cm} \vspace{1cm}
\noindent Bitte die ausgefüllte Teilnehmerliste vor Antritt der Aktivität per E-Mail an \noindent Bitte die ausgefüllte Teilnehmerliste vor Antritt der Aktivität per E-Mail an
\href{mailto:info@alpenverein-ludwigsburg.de}{info@alpenverein.de} und \href{mailto:info@alpenverein-ludwigsburg.de}{info@alpenverein-ludwigsburg.de} und
\href{mailto:vorstand@alpenverein-ludwigsburg.de}{vorstand@alpenverein-ludwigsburg.de} senden. \href{mailto:vorstand@alpenverein-ludwigsburg.de}{vorstand@alpenverein-ludwigsburg.de} senden.
\end{document} \end{document}

Loading…
Cancel
Save