Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Django Mail Auth features:
- custom user model support
- drop in Django admin support
- drop in Django User replacement
- drop in Wagtail login replacement
- extendable SMS support

This project was inspired by:
Expand Down Expand Up @@ -43,22 +44,25 @@ Run this command to install ``django-mail-auth``::
Setup
-----

First add `mailauth` to you installed apps::
First add ``mailauth`` to you installed apps::

INSTALLED_APPS = [
# Django's builtin apps…

'mailauth',
'mailauth.contrib.admin', # optional
'mailauth.contrib.user', # optional
# optional, must be included before "wagtail.admin"
'mailauth.contrib.wagtail',


# other apps…
]

`mailauth.contrib.admin` is optional and will replace the admin's login
``mailauth.contrib.admin`` is optional and will replace the admin's login
with token based authentication too.

`mailauth.contrib.user` is optional and provides a new Django User model.
``mailauth.contrib.user`` is optional and provides a new Django User model.
The new User model needs to be enabled via the ``AUTH_USER_MODEL`` setting::

AUTH_USER_MODEL = 'mailauth_user.EmailUser'
Expand All @@ -75,16 +79,18 @@ Next you will need to add the new authentication backend::
'mailauth.backends.MailAuthBackend',
)

Django's `ModelBackend` is only needed, if you still want to support
Django's ``ModelBackend`` is only needed, if you still want to support
password based authentication. If you don't, simply remove it from the list.

Last but not least, go to your URL root config `urls.py` and add the following::
Last but not least, go to your URL root config ``urls.py`` and add the following::

from django.urls import path


urlpatterns = [
path('accounts/', include('mailauth.urls')),
# optional, must be before "wagtail.admin.urls"
path('', include('mailauth.contrib.wagtail.urls')),
]

That's it!
Expand Down
1 change: 1 addition & 0 deletions mailauth/contrib/wagtail/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default_app_config = 'mailauth.contrib.wagtail.apps.MailAuthWagtail'
6 changes: 6 additions & 0 deletions mailauth/contrib/wagtail/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class MailAuthWagtail(AppConfig):
name = 'mailauth.contrib.wagtail'
label = 'mailauth_wagtail'
90 changes: 90 additions & 0 deletions mailauth/contrib/wagtail/templates/wagtailadmin/login.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{% extends "wagtailadmin/admin_base.html" %}
{% load wagtailadmin_tags i18n %}
{% block titletag %}{% trans "Sign in" %}{% endblock %}
{% block bodyclass %}login{% endblock %}

{% block extra_css %}
{{ block.super }}

<link rel="stylesheet" href="{% versioned_static 'wagtailadmin/css/layouts/login.css' %}" type="text/css" />
{% endblock %}

{% block furniture %}
<main class="content-wrapper" role="main">
{% if messages or form.errors %}
<div class="messages">
<ul>
{% if form.errors %}
<li class="error">{{ form.errors.email.0 }}</li>
{% endif %}
{% for message in messages %}
<li class="{{ message.tags }}">{{ message }}</li>
{% endfor %}
</ul>
</div>
{% endif %}

{% block above_login %}{% endblock %}

<form action="{% url 'wagtailadmin_login' %}" method="post" autocomplete="off" novalidate>
{% block login_form %}
{% csrf_token %}

{% url 'wagtailadmin_home' as home_url %}
<input type="hidden" name="next" value="{{ next|default:home_url }}" />

<h1>{% block branding_login %}{% trans "Sign in to Wagtail" %}{% endblock %}</h1>

<ul class="fields">
{% block fields %}
<li class="full">
<div class="field iconfield">
{{ form.email.label_tag }}
<div class="input icon-mail">
{{ form.email }}
</div>
</div>
</li>

{% block extra_fields %}
{% for field_name, field in form.extra_fields %}gs
<li class="full">
{{ field.label_tag }}
<div class="field iconfield">
{{ field }}
</div>
</li>
{% endfor %}
{% endblock extra_fields %}

{% comment %}
Removed until functionality exists
<li class="checkbox">
<div class="field">
<label><input type="checkbox" />{% trans "Remember me" %}</label>
</div>
</li>
{% endcomment %}
{% endblock %}
<li class="submit">
{% block submit_buttons %}
<button type="submit" class="button button-longrunning" data-clicked-text="{% trans 'Signing in…' %}"><span class="icon icon-spinner"></span><em>{% trans 'Sign in' %}</em></button>
{% endblock %}
</li>
</ul>
{% endblock %}
</form>

{% block below_login %}{% endblock %}

</main>
{% endblock %}

{% block extra_js %}
{{ block.super }}
<script>
$(function(){
$('form input[name=email]').trigger('focus');
})
</script>
{% endblock %}
9 changes: 9 additions & 0 deletions mailauth/contrib/wagtail/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from django.urls import path

from . import views

app_name = 'mailauth_wagtail'

urlpatterns = [
path('admin/login/', views.LoginView.as_view(), name='wagtailadmin_login'),
]
24 changes: 24 additions & 0 deletions mailauth/contrib/wagtail/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.contrib import messages
from django.http import response
from django.utils.translation import gettext_lazy as _
from wagtail.admin.views.account import LoginView as WagtailLoginView

from mailauth.forms import EmailLoginForm

__all__ = ('LoginView',)


class LoginView(WagtailLoginView):
"""Authentication view for Wagtail admin."""

def get_form_class(self):
return EmailLoginForm

def form_valid(self, form):
form.save()
messages.add_message(
self.request,
messages.SUCCESS,
_('We sent you an email with instructions to log into your account.'),
)
return response.HttpResponseRedirect(self.get_success_url())
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ tests_require =
pytest
pytest-django
pytest-cov
wagtail

[options.package_data]
* = *.txt, *.rst, *.html, *.po
Expand Down
6 changes: 3 additions & 3 deletions tests/contrib/admin/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@
class TestAdminLoginView:

def test_get(self, client):
response = client.get('/admin/login/')
response = client.get('/django-admin/login/')
assert response.status_code == 200
assert b'type="email"' in response.content
assert b'id="id_email"' in response.content

def test_post(self, client, user, signature):
response = client.post(
'/admin/login/',
'/django-admin/login/',
data={'email': 'spiderman@avengers.com'}
)
assert response.status_code == 302, response.content.decode()
assert signature in mail.outbox[-1].body

def test_post__user_does_not_exist(self, db, client):
response = client.post(
'/admin/login/',
'/django-admin/login/',
data={'email': 'superman@avengers.com'}
)
assert response.status_code == 302, response.content.decode()
Expand Down
Empty file.
28 changes: 28 additions & 0 deletions tests/contrib/wagtail/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from mailauth.contrib.wagtail.views import LoginView
from mailauth.forms import EmailLoginForm


class TestLoginView:
def test_get_from_class(self):
assert issubclass(LoginView().get_form_class(), EmailLoginForm)

def test_form_valid(self, rf, db):
view = LoginView()
request = rf.get('/')

class DummyMessageStorage:
def __init__(self):
self.messages = []

def add(self, *args):
self.messages.append(args)

msgs = DummyMessageStorage()

request._messages = msgs
view.request = request
form = EmailLoginForm(view.request, data=dict(email='spiderman@avengers.com'))
assert form.is_valid()
response = view.form_valid(form)
assert response.status_code == 302
assert msgs.messages
4 changes: 4 additions & 0 deletions tests/testapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
'mailauth',
'mailauth.contrib.admin',
'mailauth.contrib.user',
'mailauth.contrib.wagtail',
'wagtail.admin',
'wagtail.core',
'wagtail',
]

AUTHENTICATION_BACKENDS = (
Expand Down
6 changes: 5 additions & 1 deletion tests/testapp/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from django.contrib import admin
from django.urls import include, path
from wagtail.admin import urls as wagtailadmin_urls

urlpatterns = [
path('accounts/', include('mailauth.urls')),
path('admin/', admin.site.urls),
path("", include("mailauth.contrib.wagtail.urls")),
path("django-admin/", admin.site.urls),
path("admin/", include(wagtailadmin_urls)),

]