[RFC PATCH v2 18/19] templates: Convert mail settings pages

Stephen Finucane stephen at that.guru
Thu Sep 2 02:57:55 AEST 2021


This one is rather tricky. We do a major overhaul of URLs and general
flow of confirmations, relying heavily on the messages framework to
avoid the need to have separate pages. Previously, configuring opt-in or
opt-out of email involved the following:

  GET /mail/
    POST /mail/
      [some validation]
      POST /mail/optout/  # or optin

If the last step threw an error, we'd stay on '/mail/optout/' or
'/mail/optin/' with a displayed error and tell the user to correct the
mistake. Now, we simply do this:

  GET /mail/
    POST /mail/
      [some validation]
      GET /mail/<email>/
      POST /mail/<email>/

Error messages are propagated via the messages framework with all
non-field validation errors resulting in a redirect to the homepage.

Signed-off-by: Stephen Finucane <stephen at that.guru>
---
 .../templates/patchwork/confirm-error.html    |  23 ---
 .../templates/patchwork/mail-configure.html   |  70 ++++++++
 .../templates/patchwork/mail-settings.html    | 106 +++++++----
 patchwork/templates/patchwork/mail.html       |  37 ----
 .../templates/patchwork/optin-request.html    |  53 ------
 patchwork/templates/patchwork/optin.html      |  21 ---
 .../templates/patchwork/optout-request.html   |  56 ------
 patchwork/templates/patchwork/optout.html     |  25 ---
 .../patchwork/registration-confirm.html       |  14 --
 patchwork/urls.py                             |   3 +-
 patchwork/views/mail.py                       | 168 +++++++++++-------
 patchwork/views/notification.py               |  35 ++--
 patchwork/views/user.py                       |  56 +++---
 13 files changed, 304 insertions(+), 363 deletions(-)
 delete mode 100644 patchwork/templates/patchwork/confirm-error.html
 create mode 100644 patchwork/templates/patchwork/mail-configure.html
 delete mode 100644 patchwork/templates/patchwork/mail.html
 delete mode 100644 patchwork/templates/patchwork/optin-request.html
 delete mode 100644 patchwork/templates/patchwork/optin.html
 delete mode 100644 patchwork/templates/patchwork/optout-request.html
 delete mode 100644 patchwork/templates/patchwork/optout.html
 delete mode 100644 patchwork/templates/patchwork/registration-confirm.html

diff --git patchwork/templates/patchwork/confirm-error.html patchwork/templates/patchwork/confirm-error.html
deleted file mode 100644
index b1ce42ee..00000000
--- patchwork/templates/patchwork/confirm-error.html
+++ /dev/null
@@ -1,23 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Confirmation{% endblock %}
-{% block heading %}Confirmation{% endblock %}
-
-
-{% block body %}
-
-{% if error == 'inactive' %}
-<p>
-  This confirmation has already been processed; you've probably visited this
-  page before.
-</p>
-{% endif %}
-
-{% if error == 'expired' %}
-<p>
-  The confirmation has expired. If you'd still like to perform the
-  {{ conf.get_type_display }} process, you'll need to resubmit the request.
-</p>
-{% endif %}
-
-{% endblock %}
diff --git patchwork/templates/patchwork/mail-configure.html patchwork/templates/patchwork/mail-configure.html
new file mode 100644
index 00000000..c0e07154
--- /dev/null
+++ patchwork/templates/patchwork/mail-configure.html
@@ -0,0 +1,70 @@
+{% extends "base2.html" %}
+
+{% block title %}Mail settings{% endblock %}
+
+{% block body %}
+{% for message in messages %}
+{% if message.tags == 'success' %}
+<div class="notification is-success">
+{% elif message.tags == 'warning' %}
+<div class="notification is-warning">
+{% elif message.tags == 'error' %}
+<div class="notification is-danger">
+{% else %}
+<div class="notification">
+{% endif %}
+  {{ message }}
+  <button class="delete" onclick="dismiss(this);"></button>
+</div>
+{% endfor %}
+
+<div class="container" style="margin-top: 1rem;">
+  <section class="block">
+    <h1 class="title">
+      Mail settings for {{ email }}
+    </h1>
+  </section>
+
+  <div class="content">
+    <p>
+      You can configure your notification settings for Patchwork.
+      Use this if you wish to opt out of all email from Patchwork,
+      or if have previously opted out of Patchwork mail but now wish to
+      receive notifications from Patchwork.
+    </p>
+    <p>
+      If you opt out of email, Patchwork may still email you if you do certain
+      actions yourself (such as create a new Patchwork account) but will not
+      send you unsolicited email.
+    </p>
+    <p>
+      When you submit a request, an email will be sent to your address with
+      a link to click to finalise the request.
+      Patchwork does this to prevent someone modifying your mail settings
+      without your consent.
+    </p>
+
+{% if is_optout %}
+    <p>
+      Patchwork <strong>may not</strong> send automated notifications to this address.
+    </p>
+{% else %}
+    <p>
+      Patchwork <strong>may</strong> send automated notifications to this address.
+    </p>
+{% endif %}
+
+    <form class="form" method="post">
+      {% csrf_token %}
+      <div class="field is-grouped">
+        <div class="control">
+          <input class="button" type="submit" name="optin" value="Opt-in"{% if not is_optout %} disabled{% endif %}/>
+        </div>
+        <div class="control">
+          <input class="button" type="submit" name="optout" value="Opt-out"{% if is_optout %} disabled{% endif %}/>
+        </div>
+      </div>
+    </form>
+  </div>
+</div>
+{% endblock %}
diff --git patchwork/templates/patchwork/mail-settings.html patchwork/templates/patchwork/mail-settings.html
index 58f567ac..858140ae 100644
--- patchwork/templates/patchwork/mail-settings.html
+++ patchwork/templates/patchwork/mail-settings.html
@@ -1,37 +1,83 @@
-{% extends "base.html" %}
+{% extends "base2.html" %}
 
 {% block title %}Mail settings{% endblock %}
-{% block heading %}Mail settings{% endblock %}
 
 {% block body %}
-<p>Settings for <strong>{{ email }}</strong>:</p>
-
-<table class="horizontal">
-  <tr>
-    <th>Opt-out list</th>
-{% if is_optout %}
-    <td>
-      Patchwork <strong>may not</strong> send automated notifications to this address.
-    </td>
-    <td>
-      <form method="post" action="{% url 'mail-optin' %}">
-        {% csrf_token %}
-        <input type="hidden" name="email" value="{{ email }}"/>
-        <input type="submit" value="Opt-in"/>
-      </form>
-    </td>
+{% for message in messages %}
+{% if message.tags == 'success' %}
+<div class="notification is-success">
+{% elif message.tags == 'warning' %}
+<div class="notification is-warning">
+{% elif message.tags == 'error' %}
+<div class="notification is-danger">
 {% else %}
-    <td>
-      Patchwork <strong>may</strong> send automated notifications to this address.
-    </td>
-    <td>
-      <form method="post" action="{% url 'mail-optout' %}">
-        {% csrf_token %}
-        <input type="hidden" name="email" value="{{ email }}"/>
-        <input type="submit" value="Opt-out"/>
-      </form>
-    </td>
+<div class="notification">
 {% endif %}
-  </tr>
-</table>
+  {{ message }}
+  <button class="delete" onclick="dismiss(this);"></button>
+</div>
+{% endfor %}
+
+<div class="container" style="margin-top: 1rem;">
+  <section class="block">
+    <h1 class="title">
+      Mail settings
+    </h1>
+  </section>
+
+  <p>
+    You can configure Patchwork to send you mail on certain events,
+    or block automated mail altogether. Enter your email address to
+    view or change your email settings.
+  </p>
+
+  <div class="block"></div>
+
+{% if form.non_field_errors %}
+  <div class="notification is-danger is-light">
+    <button class="delete" onclick="dismiss(this);"></button>
+    {{ form.non_field_errors }}
+  </div>
+{% endif %}
+
+  <form class="form" method="post">
+    {% csrf_token %}
+
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label for="email" class="label">
+          Email address
+        </label>
+      </div>
+      <div class="field-body">
+        <div class="field">
+          <div class="control">
+            <input id="id_email" type="email" name="email" class="input" placeholder="e.g. bobsmith at example.com">
+          </div>
+          <p class="help">
+            Your email address
+          </p>
+{% for error in form.email.errors %}
+          <p class="help is-danger">{{ error }}</p>
+{% endfor %}
+        </div>
+      </div>
+    </div>
+
+    <div class="field is-horizontal">
+      <div class="field-label">
+        <!-- Left empty for spacing -->
+      </div>
+      <div class="field-body">
+        <div class="field">
+          <div class="control">
+            <button class="button is-primary">
+              Submit
+            </button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </form>
+</div>
 {% endblock %}
diff --git patchwork/templates/patchwork/mail.html patchwork/templates/patchwork/mail.html
deleted file mode 100644
index a2ad23d1..00000000
--- patchwork/templates/patchwork/mail.html
+++ /dev/null
@@ -1,37 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Mail settings{% endblock %}
-{% block heading %}Mail settings{% endblock %}
-
-{% block body %}
-<p>
-  You can configure Patchwork to send you mail on certain events,
-  or block automated mail altogether. Enter your email address to
-  view or change your email settings.
-</p>
-
-<form method="post">
-{% csrf_token %}
-<table class="form registerform">
-{% if form.errors %}
-  <tr>
-    <td colspan="2" class="error">
-      There was an error accessing your mail settings:
-    </td>
-  </tr>
-{% endif %}
-  <tr>
-    <th>{{ form.email.label_tag }}</th>
-    <td>
-      {{ form.email }}
-      {{ form.email.errors }}
-    </td>
-  </tr>
-  <tr>
-    <td colspan="2" class="submitrow">
-      <input type="submit" value="Access mail settings"/>
-    </td>
-  </tr>
-</table>
-</form>
-{% endblock %}
diff --git patchwork/templates/patchwork/optin-request.html patchwork/templates/patchwork/optin-request.html
deleted file mode 100644
index 36744c26..00000000
--- patchwork/templates/patchwork/optin-request.html
+++ /dev/null
@@ -1,53 +0,0 @@
-{% extends "base.html" %}
-
-{% load admins %}
-
-{% block title %}Opt-in{% endblock %}
-{% block heading %}Opt-in{% endblock %}
-
-{% block body %}
-{% if confirmation %}
-<p><strong>Opt-in confirmation email sent</strong></p>
-<p>
-  An opt-in confirmation mail has been sent to
-  <strong>{{ confirmation.email }}</strong>, containing a link. Please click on
-  that link to confirm your opt-in.
-</p>
-{% else %}
-{% if error %}
-<p class="error">{{ error }}</p>
-{% endif %}
-
-{% if form %}
-<p>
-  This form allows you to opt-in to automated email from Patchwork. Use
-  this if you have previously opted-out of Patchwork mail, but now want to
-  received notifications from Patchwork.
-</p>
-<p>
-  When you submit it, an email will be sent to your address with a link to
-  click to finalise the opt-in. Patchwork does this to prevent someone opting
-  you in without your consent.
-</p>
-
-<form method="post" action="">
-  {% csrf_token %}
-  {{ form.email.errors }}
-  <div style="padding: 0.5em 1em 2em;">
-    {{ form.email.label_tag }}: {{ form.email }}
-  </div>
-  <input type="submit" value="Send me an opt-in link">
-</form>
-{% endif %}
-
-{% if error and admins %}
-<p>
-  If you are having trouble opting in, please email {% site_admins %}.
-</p>
-{% endif %}
-{% endif %}
-
-{% if user.is_authenticated %}
-<p>Return to your <a href="{% url 'user-profile' %}">user profile</a>.</p>
-{% endif %}
-{% endblock %}
diff --git patchwork/templates/patchwork/optin.html patchwork/templates/patchwork/optin.html
deleted file mode 100644
index 659bfccb..00000000
--- patchwork/templates/patchwork/optin.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Opt-in{% endblock %}
-{% block heading %}Opt-in{% endblock %}
-
-{% block body %}
-<p>
-  <strong>Opt-in complete</strong>. You have successfully opted back in to
-  automated email from this Patchwork system, using the address
-  <strong>{{ email }}</strong>.
-</p>
-<p>
-  If you later decide that you no longer want to receive automated mail from
-  Patchwork, just visit
-  <a href="{% url 'mail-settings' %}">http://{{ site.domain }}{% url 'mail-settings' %}</a>,
-  or visit the main Patchwork page and navigate from there.
-</p>
-{% if user.is_authenticated %}
-<p>Return to your <a href="{% url 'user-profile' %}">user profile</a>.</p>
-{% endif %}
-{% endblock %}
diff --git patchwork/templates/patchwork/optout-request.html patchwork/templates/patchwork/optout-request.html
deleted file mode 100644
index a89f72bb..00000000
--- patchwork/templates/patchwork/optout-request.html
+++ /dev/null
@@ -1,56 +0,0 @@
-{% extends "base.html" %}
-
-{% load admins %}
-
-{% block title %}Opt-out{% endblock %}
-{% block heading %}Opt-out{% endblock %}
-
-{% block body %}
-{% if confirmation %}
-<p><strong>Opt-out confirmation email sent</strong></p>
-<p>
-  An opt-out confirmation mail has been sent to
-  <strong>{{ confirmation.email }}</strong>, containing a link. Please click on
-  that link to confirm your opt-out.
-</p>
-{% else %}
-{% if error %}
-<p class="error">{{ error }}</p>
-{% endif %}
-
-{% if form %}
-<p>
-  This form allows you to opt-out of automated email from Patchwork.
-</p>
-<p>
-  If you opt-out of email, Patchwork may still email you if you do certain
-  actions yourself (such as create a new Patchwork account), but will not
-  send you unsolicited email.
-</p>
-<p>
-  When you submit it, one email will be sent to your address with a link to
-  click to finalise the opt-out. Patchwork does this to prevent someone
-  opting you out without your consent.
-</p>
-<form method="post" action="">
-  {% csrf_token %}
-  {{ form.email.errors }}
-  <div style="padding: 0.5em 1em 2em;">
-    {{ form.email.label_tag }}: {{ form.email }}
-  </div>
-  <input type="submit" value="Send me an opt-out link">
-</form>
-{% endif %}
-
-{% if error and admins %}
-<p>
-  If you are having trouble opting out, please email {% site_admins %}.
-</p>
-{% endif %}
-{% endif %}
-
-{% if user.is_authenticated %}
-<p>Return to your <a href="{% url 'user-profile' %}">user profile</a>.</p>
-{% endif %}
-
-{% endblock %}
diff --git patchwork/templates/patchwork/optout.html patchwork/templates/patchwork/optout.html
deleted file mode 100644
index 2d7e67e5..00000000
--- patchwork/templates/patchwork/optout.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Opt-out{% endblock %}
-{% block heading %}Opt-out{% endblock %}
-
-{% block body %}
-<p>
-  <strong>Opt-out complete</strong>. You have successfully opted-out of
-  automated notifications from this Patchwork system, from the address
-  <strong>{{ email }}</strong>
-</p>
-<p>
-  Please note that you may still receive email from other Patchwork setups at
-  different sites, as they are run independently. You may need to opt-out of
-  those separately.
-</p>
-<p>
-  If you later decide to receive mail from Patchwork, just visit
-  <a href="{% url 'mail-settings' %}">http://{{ site.domain }}{% url 'mail-settings' %}</a>,
-  or visit the main Patchwork page and navigate from there.
-</p>
-{% if user.is_authenticated %}
-<p>Return to your <a href="{% url 'user-profile' %}">user profile</a>.</p>
-{% endif %}
-{% endblock %}
diff --git patchwork/templates/patchwork/registration-confirm.html patchwork/templates/patchwork/registration-confirm.html
deleted file mode 100644
index e9219a5a..00000000
--- patchwork/templates/patchwork/registration-confirm.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Registration{% endblock %}
-{% block heading %}Registration{% endblock %}
-
-{% block body %}
-<p>Registration confirmed!</p>
-
-<p>
-  Your Patchwork registration is complete. Head over to your
-  <a href="{% url 'user-profile' %}">profile</a> to start using
-  Patchwork's extra features.
-</p>
-{% endblock %}
diff --git patchwork/urls.py patchwork/urls.py
index 30c070a9..e8ddba10 100644
--- patchwork/urls.py
+++ patchwork/urls.py
@@ -185,8 +185,7 @@ urlpatterns = [
     path('delegate/', api_views.delegates, name='api-delegates'),
     # email setup
     path('mail/', mail_views.settings, name='mail-settings'),
-    path('mail/optout/', mail_views.optout, name='mail-optout'),
-    path('mail/optin/', mail_views.optin, name='mail-optin'),
+    path('mail/<path:email>/', mail_views.configure, name='mail-configure'),
     # about
     path('about/', about_views.about, name='about'),
     # legacy redirects
diff --git patchwork/views/mail.py patchwork/views/mail.py
index 1a2019eb..d20f9d2f 100644
--- patchwork/views/mail.py
+++ patchwork/views/mail.py
@@ -7,6 +7,7 @@ import smtplib
 
 from django.conf import settings as conf_settings
 from django.core.mail import send_mail
+from django.contrib import messages
 from django.http import HttpResponseRedirect
 from django.shortcuts import render
 from django.template.loader import render_to_string
@@ -22,12 +23,9 @@ def settings(request):
         form = EmailForm(data=request.POST)
         if form.is_valid():
             email = form.cleaned_data['email']
-            is_optout = EmailOptout.objects.filter(email=email).count() > 0
-            context = {
-                'email': email,
-                'is_optout': is_optout,
-            }
-            return render(request, 'patchwork/mail-settings.html', context)
+            return HttpResponseRedirect(
+                reverse('mail-configure', kwargs={'email': email}),
+            )
     else:
         form = EmailForm()
 
@@ -35,91 +33,125 @@ def settings(request):
         'form': form,
     }
 
-    return render(request, 'patchwork/mail.html', context)
+    return render(request, 'patchwork/mail-settings.html', context)
 
 
-def optout_confirm(request, conf):
-    email = conf.email.strip().lower()
-    # silently ignore duplicated optouts
-    if EmailOptout.objects.filter(email=email).count() == 0:
-        optout = EmailOptout(email=email)
-        optout.save()
+def _opt_in(request, email):
+    EmailConfirmation.objects.filter(type='optin', email=email).delete()
 
-    conf.deactivate()
+    confirmation = EmailConfirmation(type='optin', email=email)
+    confirmation.save()
 
-    context = {
-        'email': conf.email,
-    }
+    context = {'confirmation': confirmation}
+    subject = render_to_string('patchwork/mails/optin-request-subject.txt')
+    message = render_to_string(
+        'patchwork/mails/optin-request.txt', context, request=request)
 
-    return render(request, 'patchwork/optout.html', context)
+    try:
+        send_mail(subject, message, conf_settings.DEFAULT_FROM_EMAIL, [email])
+    except smtplib.SMTPException:
+        messages.error(
+            request,
+            'An error occurred while submitting this request. '
+            'Please contact an administrator.'
+        )
+        return False
 
+    messages.success(
+        request,
+        'Requested opt-in to email from Patchwork. '
+        'Check your email for confirmation.',
+    )
 
-def optin_confirm(request, conf):
-    email = conf.email.strip().lower()
-    EmailOptout.objects.filter(email=email).delete()
+    return True
 
-    conf.deactivate()
 
-    context = {
-        'email': conf.email,
-    }
+def _opt_out(request, email):
+    EmailConfirmation.objects.filter(type='optout', email=email).delete()
 
-    return render(request, 'patchwork/optin.html', context)
+    confirmation = EmailConfirmation(type='optout', email=email)
+    confirmation.save()
 
+    context = {'confirmation': confirmation}
+    subject = render_to_string('patchwork/mails/optout-request-subject.txt')
+    message = render_to_string(
+        'patchwork/mails/optout-request.txt', context, request=request)
 
-def _optinout(request, action):
-    context = {}
-    mail_template = 'patchwork/mails/%s-request.txt' % action
-    mail_subject_template = 'patchwork/mails/%s-request-subject.txt' % action
-    html_template = 'patchwork/%s-request.html' % action
+    try:
+        send_mail(subject, message, conf_settings.DEFAULT_FROM_EMAIL, [email])
+    except smtplib.SMTPException:
+        messages.error(
+            request,
+            'An error occurred while submitting this request. '
+            'Please contact an administrator.'
+        )
+        return False
 
-    if request.method != 'POST':
-        return HttpResponseRedirect(reverse(settings))
+    messages.success(
+        request,
+        'Requested opt-out of email from Patchwork. '
+        'Check your email for confirmation.',
+    )
+
+    return True
 
-    form = EmailForm(data=request.POST)
+
+def configure(request, email):
+    # Yes, we're kind of abusing forms here, but this is easier than doing our
+    # own view-based validation
+    form = EmailForm(data={'email': email})
     if not form.is_valid():
-        context['error'] = (
-            'There was an error in the form. Please review ' 'and re-submit.'
-        )
-        context['form'] = form
-        return render(request, html_template, context)
+        # don't worry - Django escapes these by default
+        messages.error(request, f'{email} is not a valid email address.')
+        return HttpResponseRedirect(reverse(settings))
 
     email = form.cleaned_data['email']
-    if (
-        action == 'optin' and
-        EmailOptout.objects.filter(email=email).count() == 0
-    ):
-        context['error'] = (
-            "The email address %s is not on the patchwork "
-            "opt-out list, so you don't need to opt back in" % email
-        )
-        context['form'] = form
-        return render(request, html_template, context)
 
-    conf = EmailConfirmation(type=action, email=email)
-    conf.save()
+    if request.method == 'POST':
+        if 'optin' in request.POST:
+            if _opt_in(request, email):
+                return HttpResponseRedirect(reverse('project-list'))
+        elif 'optout' in request.POST:
+            if _opt_out(request, email):
+                return HttpResponseRedirect(reverse('project-list'))
+        else:
+            messages.error(request, 'Invalid request.')
+
+    is_optout = EmailOptout.objects.filter(email=email).count() > 0
+    context = {
+        'email': email,
+        'is_optout': is_optout,
+    }
 
-    context['confirmation'] = conf
+    return render(request, 'patchwork/mail-configure.html', context)
 
-    subject = render_to_string(mail_subject_template)
-    message = render_to_string(mail_template, context, request=request)
 
-    try:
-        send_mail(subject, message, conf_settings.DEFAULT_FROM_EMAIL, [email])
-    except smtplib.SMTPException:
-        context['confirmation'] = None
-        context['error'] = (
-            'An error occurred during confirmation. '
-            'Please try again later.'
-        )
-        context['admins'] = conf_settings.ADMINS
+def optout_confirm(request, confirmation):
+    email = confirmation.email.strip().lower()
+    # silently ignore duplicated optouts
+    if EmailOptout.objects.filter(email=email).count() == 0:
+        optout = EmailOptout(email=email)
+        optout.save()
 
-    return render(request, html_template, context)
+    confirmation.deactivate()
 
+    messages.success(
+        request,
+        'Successfully opted out of email from Patchwork.'
+    )
+
+    return HttpResponseRedirect(reverse('project-list'))
+
+
+def optin_confirm(request, confirmation):
+    email = confirmation.email.strip().lower()
+    EmailOptout.objects.filter(email=email).delete()
 
-def optout(request):
-    return _optinout(request, 'optout')
+    confirmation.deactivate()
 
+    messages.success(
+        request,
+        'Successfully opted into email from Patchwork.'
+    )
 
-def optin(request):
-    return _optinout(request, 'optin')
+    return HttpResponseRedirect(reverse('project-list'))
diff --git patchwork/views/notification.py patchwork/views/notification.py
index 4e023867..7c773ba7 100644
--- patchwork/views/notification.py
+++ patchwork/views/notification.py
@@ -4,9 +4,9 @@
 #
 # SPDX-License-Identifier: GPL-2.0-or-later
 
-from django.http import Http404
-from django.shortcuts import get_object_or_404
-from django.shortcuts import render
+from django.contrib import messages
+from django.http import HttpResponseRedirect
+from django.urls import reverse
 
 from patchwork.models import EmailConfirmation
 from patchwork.views import mail
@@ -22,18 +22,27 @@ def confirm(request, key):
         'optin': mail.optin_confirm,
     }
 
-    conf = get_object_or_404(EmailConfirmation, key=key)
+    try:
+        conf = EmailConfirmation.objects.get(key=key)
+    except EmailConfirmation.DoesNotExist:
+        messages.error(
+            request,
+            'That request is invalid or expired. Please try again.'
+        )
+        return HttpResponseRedirect(reverse('project-list'))
+
     if conf.type not in views:
-        raise Http404
+        messages.error(
+            request,
+            'That request is invalid or expired. Please try again.'
+        )
+        return HttpResponseRedirect(reverse('project-list'))
 
     if conf.active and conf.is_valid():
         return views[conf.type](request, conf)
 
-    context = {}
-    context['conf'] = conf
-    if not conf.active:
-        context['error'] = 'inactive'
-    elif not conf.is_valid():
-        context['error'] = 'expired'
-
-    return render(request, 'patchwork/confirm-error.html', context)
+    messages.error(
+        request,
+        'That request is invalid or expired. Please try again.'
+    )
+    return HttpResponseRedirect(reverse('project-list'))
diff --git patchwork/views/user.py patchwork/views/user.py
index 440aa38a..973061b7 100644
--- patchwork/views/user.py
+++ patchwork/views/user.py
@@ -54,12 +54,12 @@ def register(request):
             user.save()
 
             # create confirmation
-            conf = EmailConfirmation(
+            confirmation = EmailConfirmation(
                 type='registration', user=user, email=user.email
             )
-            conf.save()
+            confirmation.save()
 
-            context['confirmation'] = conf
+            context['confirmation'] = confirmation
 
             # send email
             subject = render_to_string(
@@ -67,12 +67,18 @@ def register(request):
             )
             message = render_to_string(
                 'patchwork/mails/activation.txt',
-                {'site': Site.objects.get_current(), 'confirmation': conf},
+                {
+                    'site': Site.objects.get_current(),
+                    'confirmation': confirmation,
+                },
             )
 
             try:
                 send_mail(
-                    subject, message, settings.DEFAULT_FROM_EMAIL, [conf.email]
+                    subject,
+                    message,
+                    settings.DEFAULT_FROM_EMAIL,
+                    [confirmation.email]
                 )
             except smtplib.SMTPException:
                 context['confirmation'] = None
@@ -88,26 +94,34 @@ def register(request):
     return render(request, 'patchwork/registration.html', context)
 
 
-def register_confirm(request, conf):
-    conf.user.is_active = True
-    conf.user.save()
-    conf.deactivate()
+def register_confirm(request, confirmation):
+    confirmation.user.is_active = True
+    confirmation.user.save()
+    confirmation.deactivate()
 
     try:
-        person = Person.objects.get(email__iexact=conf.user.email)
+        person = Person.objects.get(email__iexact=confirmation.user.email)
     except Person.DoesNotExist:
-        person = Person(email=conf.user.email, name=conf.user.profile.name)
-    person.user = conf.user
+        person = Person(
+            email=confirmation.user.email, name=confirmation.user.profile.name,
+        )
+    person.user = confirmation.user
     person.save()
 
-    return render(request, 'patchwork/registration-confirm.html')
+    messages.success(request, 'Successfully confirmed account.')
+
+    return HttpResponseRedirect(reverse('project-list'))
 
 
 def _send_confirmation_email(request, email):
-    conf = EmailConfirmation(type='userperson', user=request.user, email=email)
-    conf.save()
+    confirmation = EmailConfirmation(
+        type='userperson',
+        user=request.user,
+        email=email,
+    )
+    confirmation.save()
 
-    context = {'confirmation': conf}
+    context = {'confirmation': confirmation}
     subject = render_to_string('patchwork/mails/user-link-subject.txt')
     message = render_to_string(
         'patchwork/mails/user-link.txt',
@@ -273,15 +287,15 @@ def profile(request):
 
 
 @login_required
-def link_confirm(request, conf):
+def link_confirm(request, confirmation):
     try:
-        person = Person.objects.get(email__iexact=conf.email)
+        person = Person.objects.get(email__iexact=confirmation.email)
     except Person.DoesNotExist:
-        person = Person(email=conf.email)
+        person = Person(email=confirmation.email)
 
-    person.link_to_user(conf.user)
+    person.link_to_user(confirmation.user)
     person.save()
-    conf.deactivate()
+    confirmation.deactivate()
 
     messages.success(request, 'Successfully linked email to account.')
 
-- 
2.31.1



More information about the Patchwork mailing list