Merge branch 'Aufinal/django2-login' into 'master'

Préparation Django2 : vues de login/logout

See merge request klub-dev-ens/gestioCOF!357
This commit is contained in:
Ludovic Stephan 2019-04-01 22:25:07 +02:00
commit ceff3ed6c9
6 changed files with 75 additions and 37 deletions

View file

@ -49,10 +49,14 @@ urlpatterns = [
TemplateView.as_view(template_name="cof-denied.html"),
name="cof-denied",
),
url(r"^cas/login$", django_cas_views.login, name="cas_login_view"),
url(r"^cas/logout$", django_cas_views.logout),
url(r"^outsider/login$", gestioncof_views.login_ext, name="ext_login_view"),
url(r"^outsider/logout$", django_views.logout, {"next_page": "home"}),
url(r"^cas/login$", django_cas_views.LoginView.as_view(), name="cas_login_view"),
url(r"^cas/logout$", django_cas_views.LogoutView.as_view()),
url(
r"^outsider/login$",
gestioncof_views.LoginExtView.as_view(),
name="ext_login_view",
),
url(r"^outsider/logout$", django_views.LogoutView.as_view(), {"next_page": "home"}),
url(r"^login$", gestioncof_views.login, name="cof-login"),
url(r"^logout$", gestioncof_views.logout, name="cof-logout"),
# Infos persos

View file

@ -1,5 +1,6 @@
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.forms.formsets import BaseFormSet, formset_factory
from django.forms.widgets import CheckboxSelectMultiple, RadioSelect
from django.utils.translation import ugettext_lazy as _
@ -9,6 +10,39 @@ from bda.models import Spectacle
from gestioncof.models import CalendarSubscription, Club, CofProfile, EventCommentValue
from gestioncof.widgets import TriStateCheckbox
User = get_user_model()
class ExteAuthenticationForm(AuthenticationForm):
"""
Formulaire pour l'authentification des extés : renvoie une erreur si la personne
qui essaie de s'authentifier n'a pas de mot de passe. L'erreur dépend de si la
personne a un login clipper ou non.
"""
def clean(self):
username = self.cleaned_data.get("username")
if username is not None:
try:
user = User.objects.get(username=username)
if not user.has_usable_password() or user.password in ("", "!"):
profile, created = CofProfile.objects.get_or_create(user=user)
if profile.login_clipper:
raise forms.ValidationError(
_("L'utilisateur·ice a un login clipper !"),
code="has_clipper",
)
else:
raise forms.ValidationError(
_("L'utilisateur·ice n'a pas de mot de passe"),
code="no_password",
)
except User.DoesNotExist:
pass
return super().clean()
class EventForm(forms.Form):
def __init__(self, *args, **kwargs):

View file

@ -1,14 +1,11 @@
{% extends "base_title.html" %}
{% block realcontent %}
{% if error_type == "use_clipper_login" %}
{% if error_code == "has_clipper" %}
<h2><strong>Votre identifiant est lié à un compte <tt>clipper</tt></strong></h2>
<p>Veuillez vous connecter à l'aide de votre <a href="{% url 'cas_login_view' %}">compte <tt>clipper</tt></a></p>
{% elif error_type == "no_password" %}
{% elif error_code == "no_password" %}
<h2><strong>Votre compte n'a pas de mot de passe associé</strong></h2>
<p>Veuillez <a href="mailto:cof@clipper.ens.fr">nous contacter</a> pour que nous en définissions un et que nous vous le transmettions !</p>
{% else %}
<h1><strong>{{ error_title }}</strong></h1>
<p>{{ error_description }}</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,7 @@
{% extends "base_title.html" %}
{% block realcontent %}
<h2>
Déconnexion réussie. À bientôt !
</h2>
{% endblock %}

View file

@ -7,8 +7,8 @@ from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth.views import (
login as django_login_view,
logout as django_logout_view,
LoginView as DjangoLoginView,
LogoutView as DjangoLogoutView,
redirect_to_login,
)
from django.contrib.sites.models import Site
@ -18,7 +18,7 @@ from django.urls import reverse_lazy
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django.views.generic import FormView
from django_cas_ng.views import logout as cas_logout_view
from django_cas_ng.views import LogoutView as CasLogoutView
from icalendar import Calendar, Event as Vevent
from bda.models import Spectacle, Tirage
@ -29,6 +29,7 @@ from gestioncof.forms import (
EventForm,
EventFormset,
EventStatusFilterForm,
ExteAuthenticationForm,
GestioncofConfigForm,
ProfileForm,
RegistrationPassUserForm,
@ -81,26 +82,17 @@ def login(request):
return render(request, "login_switch.html", context)
def login_ext(request):
if request.method == "POST" and "username" in request.POST:
try:
user = User.objects.get(username=request.POST["username"])
if not user.has_usable_password() or user.password in ("", "!"):
profile, created = CofProfile.objects.get_or_create(user=user)
if profile.login_clipper:
return render(
request, "error.html", {"error_type": "use_clipper_login"}
)
else:
return render(request, "error.html", {"error_type": "no_password"})
except User.DoesNotExist:
pass
context = {}
if request.method == "GET" and "next" in request.GET:
context["next"] = request.GET["next"]
if request.method == "POST" and "next" in request.POST:
context["next"] = request.POST["next"]
return django_login_view(request, template_name="login.html", extra_context=context)
class LoginExtView(DjangoLoginView):
template_name = "login.html"
form_class = ExteAuthenticationForm
def form_invalid(self, form):
# forms.non_field_errors() returns strings for some reason
non_field_errors = form.errors["__all__"].as_data()
for e in non_field_errors:
if e.code in ["has_clipper", "no_password"]:
return render(self.request, "login_error.html", {"error_code": e.code})
return super().form_invalid(form)
@login_required
@ -112,13 +104,15 @@ def logout(request, next_page=None):
if profile and profile.login_clipper:
msg = _("Déconnexion de GestioCOF et CAS réussie. À bientôt {}.")
logout_view = cas_logout_view
logout_view = CasLogoutView.as_view()
else:
msg = _("Déconnexion de GestioCOF réussie. À bientôt {}.")
logout_view = django_logout_view
logout_view = DjangoLogoutView.as_view(
next_page=next_page, template_name="logout.html"
)
messages.success(request, msg.format(request.user.get_short_name()))
return logout_view(request, next_page=next_page)
return logout_view(request)
@login_required

View file

@ -1,8 +1,9 @@
configparser==3.5.0
# TODO: change to 2.2 when out
Django==1.11.*
django-autocomplete-light==3.3.*
django-autoslug==1.9.3
django-cas-ng==3.5.*
django-cas-ng==3.6.*
django-djconfig==0.8.0
django-recaptcha==1.4.0
django-redis-cache==1.8.1
@ -20,6 +21,7 @@ git+https://git.eleves.ens.fr/cof-geek/django_custommail.git#egg=django_customma
ldap3
channels==1.1.5
python-dateutil
# TODO: change to 2.5 when out (2.4 is not explicitly compatible with Django 2.2)
wagtail==2.3.*
wagtailmenus==2.12.*
wagtail-modeltranslation==0.10.*