diff --git a/jdav_web/jdav_web/urls.py b/jdav_web/jdav_web/urls.py index 9f394f0..06fbd3b 100644 --- a/jdav_web/jdav_web/urls.py +++ b/jdav_web/jdav_web/urls.py @@ -28,4 +28,5 @@ urlpatterns += i18n_patterns( ) # TODO: django serving from MEDIA_URL should be disabled in production stage -# see http://stackoverflow.com/questions/5871730/need-a-minimal-django-file-upload-example +# see +# http://stackoverflow.com/questions/5871730/need-a-minimal-django-file-upload-example diff --git a/jdav_web/mailer/mailutils.py b/jdav_web/mailer/mailutils.py new file mode 100644 index 0000000..bd47c74 --- /dev/null +++ b/jdav_web/mailer/mailutils.py @@ -0,0 +1,33 @@ +from django.core.mail import send_mass_mail, send_mail + + +def send(subject, content, sender, recipicient): + send_mail(subject, content, sender, [recipicient]) + + +def send_mass(subject, content, sender, recipicients): + data = [ + (subject, content, sender, [recipicient]) + for recipicient in recipicients] + print("sending data", data) + send_mass_mail(data) + + +def get_content(content): + # TODO: generate right url here + url = "localhost:8000/newsletter/unsubscribe" + text = "{}\n\nDiese Email wurde über die Webseite der JDAV Ludwigsburg"\ + " verschickt. Wenn du in Zukunft keine Emails mehr erhalten möchtest,"\ + " kannst du hier den Newsletter deabonnieren.\n\n{}"\ + .format(content, url) + return text + + +def get_unsubscribe_link(member): + key = member.generate_key() + print("generating key for", member, key) + # TODO: generate right url here + return "localhost:8000/newsletter/unsubscribe?key={}".format(key) + + +mail_root = "christian@localhost" diff --git a/jdav_web/mailer/models.py b/jdav_web/mailer/models.py index 2969ad5..12bd453 100644 --- a/jdav_web/mailer/models.py +++ b/jdav_web/mailer/models.py @@ -1,6 +1,6 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -from django.core.mail import send_mass_mail +from .mailutils import send_mass, get_content # Create your models here. @@ -29,13 +29,8 @@ class Message(models.Model): if not member.gets_newsletter: continue members.add(member) - data = [ - (self.subject, get_content(self.content), self.from_addr, - [member.email]) - for member in members - ] - print("data to be sent", data) - send_mass_mail(data) + send_mass(self.subject, get_content(self.content), + self.from_addr, [member.email for member in members]) self.sent = True self.save() @@ -45,13 +40,3 @@ class Message(models.Model): permissions = ( ("submit_mails", _("Can submit mails")), ) - - -def get_content(content): - # TODO: generate right url here - url = "work in progress" - text = "{}\n\nDiese Email wurde über die Webseite der JDAV Ludwigsburg"\ - "verschickt. Wenn du in Zukunft keine Emails mehr erhalten möchtest,"\ - "kannst du hier den Newsletter deabonnieren.\n\n{}"\ - .format(content, url) - return text diff --git a/jdav_web/mailer/templates/mailer/confirmation_sent.html b/jdav_web/mailer/templates/mailer/confirmation_sent.html new file mode 100644 index 0000000..8f6b32d --- /dev/null +++ b/jdav_web/mailer/templates/mailer/confirmation_sent.html @@ -0,0 +1,3 @@ +{% load i18n %} + +

{% trans "Sent confirmation mail to" %} {{ email }}. {% trans "Follow the link in your mail to confirm your unsubscription." %}

diff --git a/jdav_web/mailer/templates/mailer/unsubscribe.html b/jdav_web/mailer/templates/mailer/unsubscribe.html new file mode 100644 index 0000000..5055820 --- /dev/null +++ b/jdav_web/mailer/templates/mailer/unsubscribe.html @@ -0,0 +1,21 @@ +{% load i18n %} + +

{% trans "Here you can unsubscribe from the newsletter" %}

+ +{% if error_message %} +

{{ error_message }}

+{% endif %} + +
+ {% csrf_token %} + + +

+ {% trans "Email address" %} + +

+ +

+ +

+
diff --git a/jdav_web/mailer/templates/mailer/unsubscribed.html b/jdav_web/mailer/templates/mailer/unsubscribed.html new file mode 100644 index 0000000..9c05d11 --- /dev/null +++ b/jdav_web/mailer/templates/mailer/unsubscribed.html @@ -0,0 +1,5 @@ +{% load i18n %} + +

+{% trans "Successfully unsubscribed from the newsletter for " %}{{ email }} +

diff --git a/jdav_web/mailer/urls.py b/jdav_web/mailer/urls.py index 3654aec..63aee39 100644 --- a/jdav_web/mailer/urls.py +++ b/jdav_web/mailer/urls.py @@ -5,5 +5,6 @@ from . import views app_name = "mailer" urlpatterns = [ url(r'^$', views.index, name='index'), - url(r'^subscribe$', views.subscribe, name='subscribe'), + # url(r'^subscribe', views.subscribe, name='subscribe'), + url(r'^unsubscribe', views.unsubscribe, name='unsubscribe'), ] diff --git a/jdav_web/mailer/views.py b/jdav_web/mailer/views.py index a21e674..00f2e63 100644 --- a/jdav_web/mailer/views.py +++ b/jdav_web/mailer/views.py @@ -3,12 +3,54 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from django.urls import reverse from django.http import HttpResponseRedirect +from .mailutils import send as send_mail, mail_root, get_unsubscribe_link from members.models import Member def index(request): - return HttpResponseRedirect(reverse('mailer:subscribe')) + return HttpResponseRedirect(reverse('mailer:unsubscribe')) + + +def render_unsubscribe(request, error_message=""): + context = {} + if error_message: + context['error_message'] = error_message + return render(request, 'mailer/unsubscribe.html', context) + + +def render_unsubscribed(request, email): + return render(request, 'mailer/unsubscribed.html', {'email': email}) + + +def unsubscribe(request): + if request.method == 'GET' and 'key' in request.GET: + try: + key = request.GET['key'] + member = Member.objects.get(unsubscribe_key=key) + if not member.unsubscribe(key): + raise KeyError + except (KeyError, Member.DoesNotExist): + return render_unsubscribe(request, + _("Can't verify this link. Try again!")) + else: + return render_unsubscribed(request, member.email) + elif not request.POST.get('post', False): + # just calling up unsubscribe page + return render_unsubscribe(request) + try: + email = request.POST['email'] + member = Member.objects.filter(email=email).first() + if not member: # member not found + raise KeyError + except (KeyError, Member.DoesNotExist): + return render_unsubscribe(request, _("Please fill in every field")) + else: + send_mail(_("Confirmation of unsubscription"), + _("Click the link to unsubscribe to the newsletter of" + " the JDAV\n{}".format(get_unsubscribe_link(member))), + mail_root, email) + return render_confirmation_sent(request, email) def render_subscribe(request, error_message=""): @@ -22,6 +64,10 @@ def render_subscribe(request, error_message=""): return render(request, 'mailer/subscribe.html', context) +def render_confirmation_sent(request, email): + return render(request, 'mailer/confirmation_sent.html', {'email': email}) + + def subscribe(request): try: request.POST['post'] @@ -41,7 +87,8 @@ def subscribe(request): lastname=lastname) if len(exists) > 0: return render_subscribe(request, - error_message=_("Member already exists")) + error_message=_("Member " + "already exists")) member = Member(prename=prename, lastname=lastname, email=email, diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 0a29463..2a7619a 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -1,7 +1,8 @@ from datetime import datetime -import hashlib +import uuid from django.db import models from django.utils.translation import ugettext_lazy as _ +from django.utils import timezone class Group(models.Model): @@ -34,17 +35,29 @@ class Member(models.Model): group = models.ManyToManyField(Group) gets_newsletter = models.BooleanField(_('receives newsletter'), default=True) - key = models.CharField(max_length=32, default="") + unsubscribe_key = models.CharField(max_length=32, default="") + unsubscribe_expire = models.DateTimeField(default=timezone.now) def __str__(self): """String representation""" return self.name - def save(self, *args, **kwargs): - if len(self.key) == 0: - self.key = hashlib.md5((self.prename + self.lastname + - self.email).encode()).hexdigest() - super(Member, self).save(*args, **kwargs) + def generate_key(self): + self.unsubscribe_key = uuid.uuid4().hex + self.unsubscribe_expire = timezone.now() + timezone.timedelta(days=1) + self.save() + return self.unsubscribe_key + + def unsubscribe(self, key): + if self.unsubscribe_key == key and timezone.now() <\ + self.unsubscribe_expire: + for member in Member.objects.filter(email=self.email): + member.gets_newsletter = False + member.save() + self.unsubscribe_key, self.unsubscribe_expire = "", timezone.now() + return True + else: + return False @property def name(self):