summaryrefslogtreecommitdiff
path: root/app/lttr
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2019-02-12 14:31:53 -0600
committerluxagraf <sng@luxagraf.net>2019-02-12 14:31:53 -0600
commit0ccf2f7b61ea9889b1c03e51dfc847ca16cd98e7 (patch)
tree3c379d541c5aa96870a54796718078668fc8263f /app/lttr
parentee2803d2f85888ce42fd6371ef606f4a9c6fd88b (diff)
finished up subscribe functions for lttr
Diffstat (limited to 'app/lttr')
-rw-r--r--app/lttr/admin.py13
-rw-r--r--app/lttr/forms.py25
-rw-r--r--app/lttr/migrations/0003_newsletter_slug.py19
-rw-r--r--app/lttr/migrations/0004_auto_20190212_1529.py21
-rw-r--r--app/lttr/models.py95
-rw-r--r--app/lttr/urls.py33
-rw-r--r--app/lttr/views.py50
7 files changed, 198 insertions, 58 deletions
diff --git a/app/lttr/admin.py b/app/lttr/admin.py
new file mode 100644
index 0000000..1b919d6
--- /dev/null
+++ b/app/lttr/admin.py
@@ -0,0 +1,13 @@
+from django.contrib import admin
+
+from .models import NewsletterMailing, Subscriber
+
+
+@admin.register(Subscriber)
+class SubscriberAdmin(admin.ModelAdmin):
+ list_display = ('email_field', 'user', 'date_created', 'subscribed', 'subscribe_date', 'unsubscribed')
+ search_fields = ['email_field']
+ list_filter = ['unsubscribed']
+
+ class Media:
+ js = ('next-prev-links.js',)
diff --git a/app/lttr/forms.py b/app/lttr/forms.py
index e1d4709..ad41d66 100644
--- a/app/lttr/forms.py
+++ b/app/lttr/forms.py
@@ -73,3 +73,28 @@ class SubscribeRequestForm(NewsletterForm):
pass
return data
+
+
+class UpdateForm(NewsletterForm):
+ """
+ This form allows one to actually update to or unsubscribe from the
+ newsletter. To do this, a correct activation code is required.
+ """
+
+ email_field = forms.EmailField(
+ label=("e-mail"), validators=[validate_email_nouser], disabled=True
+ )
+
+ def clean_user_activation_code(self):
+ data = self.cleaned_data['user_activation_code']
+
+ if data != self.instance.activation_code:
+ raise ValidationError(
+ ('The validation code supplied by you does not match.')
+ )
+
+ return data
+
+ user_activation_code = forms.CharField(
+ label=("Activation code"), max_length=40
+ )
diff --git a/app/lttr/migrations/0003_newsletter_slug.py b/app/lttr/migrations/0003_newsletter_slug.py
new file mode 100644
index 0000000..ea20b4b
--- /dev/null
+++ b/app/lttr/migrations/0003_newsletter_slug.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.1.5 on 2019-02-11 22:51
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lttr', '0002_subscriber_email_field'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='newsletter',
+ name='slug',
+ field=models.SlugField(default='friends', unique=True),
+ preserve_default=False,
+ ),
+ ]
diff --git a/app/lttr/migrations/0004_auto_20190212_1529.py b/app/lttr/migrations/0004_auto_20190212_1529.py
new file mode 100644
index 0000000..4b810c9
--- /dev/null
+++ b/app/lttr/migrations/0004_auto_20190212_1529.py
@@ -0,0 +1,21 @@
+# Generated by Django 2.1.5 on 2019-02-12 15:29
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('lttr', '0003_newsletter_slug'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='subscriber',
+ name='create_date',
+ ),
+ migrations.RemoveField(
+ model_name='subscriber',
+ name='ip',
+ ),
+ ]
diff --git a/app/lttr/models.py b/app/lttr/models.py
index 029022c..ec5e897 100644
--- a/app/lttr/models.py
+++ b/app/lttr/models.py
@@ -28,6 +28,7 @@ def make_activation_code():
class Newsletter(models.Model):
""" A model for Newletters. Might I one day have two? I might. """
title = models.CharField(max_length=250)
+ slug = models.SlugField(db_index=True, unique=True)
def __str__(self):
return self.title
@@ -36,7 +37,7 @@ class Newsletter(models.Model):
return reverse("lttr:detail", kwargs={"slug": self.slug})
def subscribe_url(self):
- return reverse('newsletter_subscribe_request', kwargs={'newsletter_slug': self.slug})
+ return reverse('lttr:newsletter_subscribe_request', kwargs={'newsletter_slug': self.slug})
def unsubscribe_url(self):
return reverse('newsletter_unsubscribe_request', kwargs={'newsletter_slug': self.slug})
@@ -50,6 +51,44 @@ class Newsletter(models.Model):
def get_subscriptions(self):
return Subscriber.objects.filter(newsletter=self, subscribed=True)
+ def get_templates(self, action):
+ """
+ Return a subject, text, HTML tuple with e-mail templates for
+ a particular action. Returns a tuple with subject, text and e-mail
+ template.
+ """
+
+ assert action in ACTIONS + ('message', ), 'Unknown action: %s' % action
+
+ # Common substitutions for filenames
+ tpl_subst = {
+ 'action': action,
+ 'newsletter': self.slug
+ }
+
+ # Common root path for all the templates
+ tpl_root = 'lttr/message/'
+
+ subject_template = select_template([
+ tpl_root + '%(newsletter)s/%(action)s_subject.txt' % tpl_subst,
+ tpl_root + '%(action)s_subject.txt' % tpl_subst,
+ ])
+
+ text_template = select_template([
+ tpl_root + '%(newsletter)s/%(action)s.txt' % tpl_subst,
+ tpl_root + '%(action)s.txt' % tpl_subst,
+ ])
+
+ html_template = select_template([
+ tpl_root + '%(newsletter)s/%(action)s.html' % tpl_subst,
+ tpl_root + '%(action)s.html' % tpl_subst,
+ ])
+
+ return (subject_template, text_template, html_template)
+
+ def get_sender(self):
+ return 'Scott Gilbertson <sng@luxagraf.net>'
+
@classmethod
def get_default(cls):
try:
@@ -85,45 +124,6 @@ class NewsletterMailing(models.Model):
self.date_created = timezone.now()
super(NewsletterMailing, self).save()
- def get_templates(self, action):
- """
- Return a subject, text, HTML tuple with e-mail templates for
- a particular action. Returns a tuple with subject, text and e-mail
- template.
- """
-
- assert action in ACTIONS + ('message', ), 'Unknown action: %s' % action
-
- # Common substitutions for filenames
- tpl_subst = {
- 'action': action,
- 'newsletter': self.slug
- }
-
- # Common root path for all the templates
- tpl_root = 'newsletter/message/'
-
- subject_template = select_template([
- tpl_root + '%(newsletter)s/%(action)s_subject.txt' % tpl_subst,
- tpl_root + '%(action)s_subject.txt' % tpl_subst,
- ])
-
- text_template = select_template([
- tpl_root + '%(newsletter)s/%(action)s.txt' % tpl_subst,
- tpl_root + '%(action)s.txt' % tpl_subst,
- ])
-
- if self.send_html:
- html_template = select_template([
- tpl_root + '%(newsletter)s/%(action)s.html' % tpl_subst,
- tpl_root + '%(action)s.html' % tpl_subst,
- ])
- else:
- # HTML templates are not required
- html_template = None
-
- return (subject_template, text_template, html_template)
-
class Subscriber(models.Model):
""" A model for Newletter Subscriber """
@@ -131,9 +131,7 @@ class Subscriber(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date_created = models.DateTimeField(blank=True, auto_now_add=True, editable=False)
date_updated = models.DateTimeField(blank=True, auto_now=True, editable=False)
- ip = models.GenericIPAddressField(blank=True, null=True)
newsletter = models.ForeignKey(Newsletter, on_delete=models.CASCADE)
- create_date = models.DateTimeField(editable=False, default=datetime.datetime.now)
activation_code = models.CharField(max_length=40, default=make_activation_code)
subscribed = models.BooleanField(default=False, db_index=True)
subscribe_date = models.DateTimeField(null=True, blank=True)
@@ -278,25 +276,22 @@ class Subscriber(models.Model):
message.send()
def subscribe_activate_url(self):
- return reverse('newsletter_update_activate', kwargs={
- 'newsletter_slug': self.newsletter.slug,
- 'email': self.email,
- 'action': 'subscribe',
+ return reverse('lttr:newsletter_activate', kwargs={
+ 'slug': self.newsletter.slug,
'activation_code': self.activation_code
})
def unsubscribe_activate_url(self):
return reverse('newsletter_update_activate', kwargs={
- 'newsletter_slug': self.newsletter.slug,
+ 'slug': self.newsletter.slug,
'email': self.email,
'action': 'unsubscribe',
'activation_code': self.activation_code
})
def update_activate_url(self):
- return reverse('newsletter_update_activate', kwargs={
- 'newsletter_slug': self.newsletter.slug,
- 'email': self.email,
+ return reverse('lttr:newsletter_update_activate', kwargs={
+ 'slug': self.newsletter.slug,
'action': 'update',
'activation_code': self.activation_code
})
diff --git a/app/lttr/urls.py b/app/lttr/urls.py
index 84b0bca..e0166f1 100644
--- a/app/lttr/urls.py
+++ b/app/lttr/urls.py
@@ -1,4 +1,4 @@
-from django.urls import path
+from django.urls import path, re_path
from . import views
@@ -11,11 +11,40 @@ urlpatterns = [
name="detail"
),
path(
- r'<int:page>',
+ r'<str:slug>/<int:page>',
views.NewsletterListView.as_view(),
name="list"
),
path(
+ '<str:slug>/activate/<str:activation_code>/',
+ views.ConfirmSubscriptionView.as_view(), name='newsletter_activate'
+ ),
+ #path(
+ # '/subscribe/confirm/',
+ # views.SubscribeRequestView.as_view(confirm=True),
+ # name='newsletter_subscribe_confirm'
+ #),
+ #path(
+ # '^<newsletter_slug:s>/update/$',
+ # views.UpdateRequestView.as_view(),
+ # name='newsletter_update_request'
+ #),
+ #path(
+ # '^<newsletter_slug:s>/unsubscribe/$',
+ # views.UnsubscribeRequestView.as_view(),
+ # name='newsletter_unsubscribe_request'
+ #),
+ #path(
+ # '^<newsletter_slug:s>/unsubscribe/confirm/$',
+ # views.UnsubscribeRequestView.as_view(confirm=True),
+ # name='newsletter_unsubscribe_confirm'
+ #),
+ path(
+ r'subscribed/',
+ views.NewsletterSubscribedView.as_view(),
+ name="subscribed"
+ ),
+ path(
r'',
views.NewsletterListView.as_view(),
{'page': 1},
diff --git a/app/lttr/views.py b/app/lttr/views.py
index 786bc5c..0d3dbea 100644
--- a/app/lttr/views.py
+++ b/app/lttr/views.py
@@ -1,14 +1,22 @@
-from django.views.generic import ListView, CreateView
+import socket
+from django.views.generic import ListView, CreateView, TemplateView, FormView
from django.views.generic.detail import DetailView
from django.views.generic.dates import YearArchiveView, MonthArchiveView
from django.contrib.syndication.views import Feed
+from django.template.response import TemplateResponse
+from django.contrib.auth import get_user_model
from django.db.models import Q
+from django.shortcuts import get_object_or_404, redirect
from django.conf import settings
+from django.urls import reverse, reverse_lazy
from utils.views import PaginatedListView
+from smtplib import SMTPException
from .models import NewsletterMailing, Subscriber, Newsletter
-from .forms import SubscribeRequestForm
+from .forms import SubscribeRequestForm, UpdateForm
+
+ACTIONS = ('subscribe', 'unsubscribe', 'update')
class NewsletterMailingDetail(DetailView):
@@ -29,12 +37,17 @@ class NewsletterMailingDetail(DetailView):
return context
+class NewsletterSubscribedView(TemplateView):
+ template_name = "lttr/subscribed.html"
+
+
class NewsletterListView(CreateView):
- model = Subscriber
- form_class = SubscribeRequestForm
"""
Return a subscribe form and list of Newsletter posts in reverse chronological order
"""
+ model = Subscriber
+ form_class = SubscribeRequestForm
+ action = 'subscribe'
def get_form_kwargs(self):
kwargs = super(NewsletterListView, self).get_form_kwargs()
@@ -46,9 +59,34 @@ class NewsletterListView(CreateView):
context['mailings'] = NewsletterMailing.objects.filter(status=1)
return context
+ def get_success_url(self):
+ return reverse_lazy('lttr:subscribed')
+
def form_valid(self, form, **kwargs):
- form.instance.user = settings.AUTH_USER_MODEL.objects.get_or_create(email=form.instance.email)
+ form.instance.user, created = get_user_model().objects.get_or_create(
+ email=form.cleaned_data['email_field'],
+ username=form.cleaned_data['email_field']
+ )
self.object = form.save()
+ try:
+ self.object.send_activation_email(action=self.action)
+
+ except (SMTPException, socket.error) as e:
+ print(e)
+ self.error = True
+
+ # Although form was valid there was error while sending email,
+ # so stay at the same url.
+ return super(NewsletterListView, self).form_invalid(form)
return super(NewsletterListView, self).form_valid(form)
- #super(NewsletterListView, self).form_valid()
+
+class ConfirmSubscriptionView(DetailView):
+ model = Subscriber
+ template_name = "lttr/confirm_activate.html"
+
+ def get_object(self):
+ obj = Subscriber.objects.get(newsletter__slug=self.kwargs['slug'], activation_code=self.kwargs['activation_code'])
+ if obj.subscribed is False:
+ obj.update('subscribe')
+ return obj