Merge branch 'Aufinal/password_management' into 'master'

Vues de réinitialisation de mot de passe

See merge request klub-dev-ens/authens!15
This commit is contained in:
Martin Pepin 2020-07-05 11:20:20 +02:00
commit ffd5155061
13 changed files with 185 additions and 55 deletions

View file

@ -1,3 +1,7 @@
/*
Generic page layout
*/
html, body { html, body {
width: 100%; width: 100%;
background: #eee; background: #eee;
@ -7,31 +11,43 @@ html, body {
} }
#container { #container {
display: flex;
flex-flow: row wrap;
padding: 10% 1em; padding: 10% 1em;
min-width: 300px; min-width: 300px;
max-width: 900px; max-width: 900px;
margin: auto; margin: auto;
} }
h2 { #container-title {
margin: 0;
padding: 15px;
width: 100%; width: 100%;
background: #505160; background: #505160;
color: white; color: white;
}
#container-title h2 {
padding: 15px;
font-weight: initial; font-weight: initial;
font-size: 2em; font-size: 2em;
margin: 0;
} }
#container-content {
text-align: center;
width: 100%;
display: flex;
flex-flow: row wrap;
}
/*
Background color definitions
*/
.cas { .cas {
background: #4D85BD; background: #4D85BD;
color: white; color: white;
} }
.exte { .exte {
background: #749F2A; background: #598507;
color: white; color: white;
} }
@ -40,48 +56,81 @@ h2 {
color: white; color: white;
} }
#container-content { /*
Login switch layout
*/
.big-button {
flex: 1;
height: 200px;
min-width: 300px;
text-align: center; text-align: center;
width: 100%; font-size: 2.5em;
color: white;
line-height: 200px;
text-decoration: none;
} }
.auth_form { .big-button :hover {
padding: 0.5em; text-decoration: underline;
font-size: 1.5em;
} }
/*
Message styling
*/
.error { .error {
background: red; background: red;
color: white; color: white;
width: 100%; width: 100%;
padding: 0.5em; padding: 0.5em 0;
margin: 0; margin: 0;
font-size: 1.2em; font-size: 1.2em;
text-align: center; text-align: center;
} }
.success {
background: green;
color: white;
width: 100%;
padding: 0.5em 0;
margin: 0;
font-size: 1.2em;
text-align: center;
}
/*
Form styling
*/
.auth_form {
width: 100%;
padding: 0.5em;
font-size: 1.5em;
}
.auth_form table {
margin: 20px auto;
border-spacing: 0.3em;
}
.auth_form th {
padding: 10px 0;
vertical-align: text-top;
text-align: right;
}
ul.errorlist { ul.errorlist {
text-align: left; text-align: left;
font-size: 0.8em; font-size: 0.8em;
padding-left: 20px; padding-left: 20px;
} }
.auth_form table {
margin: 20px auto;
border-spacing: 0.3em;
}
th {
padding: 5px 0;
vertical-align: text-top;
text-align: right;
}
input { input {
font-size: 1em; font-size: 1em;
} }
input[type="text"], input[type="password"] { input[type="text"], input[type="password"], input[type="email"] {
border: 0; border: 0;
padding: 5px; padding: 5px;
width: 100%; width: 100%;
@ -111,17 +160,16 @@ select {
text-align: end; text-align: end;
} }
a { /*
flex: 1; Misc
height: 200px; */
min-width: 300px;
text-align: center; .forgot-pwd {
font-size: 2.5em; width:100%;
color: white; padding: 0.5em 0px 1em;
line-height: 200px; font-size: 1.2em;
text-decoration: none;
} }
a:hover { .forgot-pwd > a {
text-decoration: underline; color: white;
} }

View file

@ -1,4 +0,0 @@
<tr>
<th>{{ field.label_tag }}</th>
<td>{{ field }}</td>
</tr>

View file

@ -16,8 +16,23 @@
<body> <body>
<div id="container"> <div id="container">
{% block container-top %} {% block container-top %}
<h2>{% if request.site.name %}{{ request.site.name }}{% else %}AuthENS{% endif %} - {% block container-title %}{% endblock %}</h2> <div id="container-title">
<h2>{% if request.site.name %}{{ request.site.name }}{% else %}AuthENS{% endif %} - {% block container-title %}{% endblock %}</h2>
</div>
{% endblock %} {% endblock %}
{% if messages %}
{% for message in messages %}
<p class="{{ message.level_tag }}">
{% if 'safe' in message.tags %}
{{ message|safe }}
{% else %}
{{ message }}
{% endif %}
</p>
{% endfor %}
{% endif %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
</div> </div>
</body> </body>

View file

@ -6,19 +6,15 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<a href="{% url "authens:login.cas" %}?next={{ next| urlencode }}"> <div id="container-content">
<div class="big-button cas"> <a class="big-button cas" href="{% url "authens:login.cas" %}?next={{ next| urlencode }}">
{% trans "Clipper" %} {% trans "Clipper" %}
</div>
</a> </a>
<a href="{% url "authens:login.pwd" %}?next={{ next| urlencode }}"> <a class="big-button exte" href="{% url "authens:login.pwd" %}?next={{ next| urlencode }}">
<div class="big-button exte"> {% trans "Mot de passe" %}
{% trans "Mot de passe" %}
</div>
</a> </a>
<a href="{% url "authens:login.oldcas" %}?next={{ next| urlencode }}"> <a class="big-button oldcas" href="{% url "authens:login.oldcas" %}?next={{ next| urlencode }}">
<div class="big-button oldcas"> {% trans "Vieilleux" %}
{% trans "Vieilleux" %}
</div>
</a> </a>
</div>
{% endblock %} {% endblock %}

View file

@ -8,5 +8,9 @@
{% block content %} {% block content %}
<div id="container-content" class="exte"> <div id="container-content" class="exte">
{% include "authens/form_full_snippet.html" with submit_text="Se connecter" %} {% include "authens/form_full_snippet.html" with submit_text="Se connecter" %}
<div class="forgot-pwd">
<a href={% url "authens:reset.pwd" %}>{% trans "Mot de passe oublié ?" %}</a>
</div>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "authens/base.html" %}
{% load i18n %}
{% block container-title %}
{% trans "Réinitialisation du mot de passe" %}
{% endblock %}
{% block content %}
<div id="container-content" class="exte">
{% include "authens/form_full_snippet.html" with submit_text="Envoyer un mail" %}
</div>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "authens/base.html" %}
{% load i18n %}
{% block container-title %}
{% trans "Nouveau mot de passe" %}
{% endblock %}
{% block content %}
<div id="container-content" class="exte">
{% include "authens/form_full_snippet.html" with submit_text="Enregistrer" %}
</div>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% load i18n %}{% autoescape off %}
{% blocktrans %}Quelqu'un (probablement vous) a demandé la réinitialisation du mot de passe associé à cette addresse sur {{ site_name }}.{% endblocktrans %}
{% blocktrans %}S'il s'agit bien de vous, vous pouvez vous rendre à l'adresse suivante pour en choisir un nouveau : {% endblocktrans %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url "authens:reset.pwd.confirm" uidb64=uid token=token %}
{% endblock %}
{% blocktrans with username=user.get_username %}Pour information, votre nom d'utilisateur est le suivant : {{ username }}{% endblocktrans %}
{% block signature %}{% blocktrans %}L'équipe {{site_name}}{% endblocktrans %}{% endblock %}
{% endautoescape %}

View file

@ -0,0 +1 @@
Réinitialisation de votre mot de passe {{site_name}}

View file

@ -9,4 +9,10 @@ urlpatterns = [
path("login/pwd", views.PasswordLoginView.as_view(), name="login.pwd"), path("login/pwd", views.PasswordLoginView.as_view(), name="login.pwd"),
path("login/oldcas", views.OldCASLoginView.as_view(), name="login.oldcas"), path("login/oldcas", views.OldCASLoginView.as_view(), name="login.oldcas"),
path("logout", views.LogoutView.as_view(), name="logout"), path("logout", views.LogoutView.as_view(), name="logout"),
path("reset/pwd", views.PasswordResetView.as_view(), name="reset.pwd"),
path(
"reset/pwd/<uidb64>/<token>/",
views.PasswordResetConfirmView.as_view(),
name="reset.pwd.confirm",
),
] ]

View file

@ -3,13 +3,16 @@ from urllib.parse import urlparse, urlunparse
from django.conf import settings from django.conf import settings
from django.contrib import auth from django.contrib import auth
from django.contrib.auth import views as auth_views from django.contrib.auth import views as auth_views
from django.contrib.messages.views import SuccessMessageMixin
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.views.generic import TemplateView, View
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy
from django.views.generic import TemplateView, View
from authens.utils import get_cas_client
from authens.forms import OldCASAuthForm from authens.forms import OldCASAuthForm
from authens.utils import get_cas_client
class NextPageMixin: class NextPageMixin:
@ -80,10 +83,33 @@ class PasswordLoginView(auth_views.LoginView):
template_name = "authens/pwd_login.html" template_name = "authens/pwd_login.html"
class PasswordResetView(SuccessMessageMixin, auth_views.PasswordResetView):
template_name = "authens/pwd_reset.html"
email_template_name = "authens/pwd_reset_email.txt"
subject_template_name = "authens/pwd_reset_subject.txt"
success_url = reverse_lazy("authens:login")
success_message = _(
"Un email de réinitialisation vient d'être envoyé à l'adresse indiquée !"
)
class PasswordResetConfirmView(
SuccessMessageMixin, auth_views.PasswordResetConfirmView
):
template_name = "authens/pwd_reset_confirm.html"
success_url = reverse_lazy("authens:login")
success_message = _("Mot de passe modifié avec succès !")
class OldCASLoginView(auth_views.LoginView): class OldCASLoginView(auth_views.LoginView):
template_name = "authens/old_cas_login.html" template_name = "authens/oldcas_login.html"
authentication_form = OldCASAuthForm authentication_form = OldCASAuthForm
def get_initial(self):
return {"entrance_year": timezone.now().year - 5}
class LogoutView(auth_views.LogoutView): class LogoutView(auth_views.LogoutView):
"""Logout view of AuthENS. """Logout view of AuthENS.

View file

@ -128,6 +128,8 @@ AUTHENTICATION_BACKENDS = [
"authens.backends.OldCASBackend", "authens.backends.OldCASBackend",
] ]
LOGIN_URL = reverse_lazy("authens:login") LOGIN_URL = reverse_lazy("authens:login")
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
# This is cosmetic # This is cosmetic
LOGIN_REDIRECT_URL = reverse_lazy("home") LOGIN_REDIRECT_URL = reverse_lazy("home")