From 35825be0382330d794525630845213d688f15c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89lie=20Bouttier?= Date: Mon, 31 Jul 2017 23:20:16 +0200 Subject: [PATCH] authentication with email instead of username --- cfp/forms.py | 2 +- locale/fr/LC_MESSAGES/django.mo | Bin 18463 -> 18669 bytes locale/fr/LC_MESSAGES/django.po | 28 +++++++++++++++------ ponyconf/backends.py | 16 ++++++++++++ ponyconf/settings.py | 5 +++- ponyconf/templates/registration/login.html | 6 ++--- ponyconf/urls.py | 14 +++++++++++ 7 files changed, 59 insertions(+), 12 deletions(-) create mode 100644 ponyconf/backends.py diff --git a/cfp/forms.py b/cfp/forms.py index ab15e33..364102f 100644 --- a/cfp/forms.py +++ b/cfp/forms.py @@ -52,7 +52,7 @@ class CreateUserForm(forms.ModelForm): user = User(first_name=self.cleaned_data.get('first_name'), last_name=self.cleaned_data.get('last_name')) username = slugify(user.get_full_name()) if User.objects.filter(username=username).exists(): - raise forms.ValidationError(_('An user with that firstname and lastname already exists.')) + raise forms.ValidationError(_('An user with that firstname and that lastname already exists.')) def clean_email(self): email = self.cleaned_data.get('email') diff --git a/locale/fr/LC_MESSAGES/django.mo b/locale/fr/LC_MESSAGES/django.mo index f2a230b68bd251690b5d5a27e3572160611b925f..111f7dc7dcd23edd7908b7c42f95878abfafe400 100644 GIT binary patch delta 5902 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 diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index a8e55ba..294880a 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-07-30 19:44+0000\n" +"POT-Creation-Date: 2017-07-31 21:38+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -288,7 +288,11 @@ msgstr "%(name)s a été ajouté aux participants" msgid "%(name)s is already a participant" msgstr "%(name)s est déjà participant" -#: cfp/forms.py:47 +#: cfp/forms.py:55 +msgid "An user with that firstname and that lastname already exists." +msgstr "Un utilisateur avec ce prénom et ce nom existe déjà." + +#: cfp/forms.py:60 msgid "A user with that email already exists." msgstr "Un utilisateur avec cet email existe déjà." @@ -448,7 +452,7 @@ msgid "An email has been sent to you with those URLs" msgstr "Un mail vous a été envoyé avec toutes les URLs" #: cfp/templates/cfp/propose.html:22 cfp/templates/cfp/speaker.html:21 -#: cfp/templates/cfp/staff/conference.html:13 +#: cfp/templates/cfp/staff/conference.html:14 #: cfp/templates/cfp/staff/create_user.html:13 msgid "Save" msgstr "Envoyer" @@ -462,6 +466,7 @@ msgstr "Conférence" msgid "Please select a category." msgstr "Veuillez sélectionner une catégorie." +#: cfp/templates/cfp/staff/conference.html:13 #: cfp/templates/cfp/staff/create_user.html:8 msgid "Add a new user" msgstr "Ajouter un nouvel utilisateur" @@ -745,11 +750,11 @@ msgstr "Vote mis à jour" msgid "Decision taken in account" msgstr "Décision enregistrée" -#: cfp/views.py:208 +#: cfp/views.py:214 msgid "Modifications successfully saved." msgstr "Modification enregistrée avec succès." -#: cfp/views.py:222 +#: cfp/views.py:228 msgid "User created successfully." msgstr "Utilisateur créé avec succès." @@ -830,11 +835,11 @@ msgstr "Certains exposés ne sont pas encore planifiés." msgid "No rooms." msgstr "Aucune salle." -#: ponyconf/settings.py:145 +#: ponyconf/settings.py:147 msgid "English" msgstr "Anglais" -#: ponyconf/settings.py:146 +#: ponyconf/settings.py:148 msgid "French" msgstr "Français" @@ -852,6 +857,7 @@ msgstr "Staff" #: ponyconf/templates/base.html:50 #: ponyconf/templates/registration/login.html:10 +#: ponyconf/templates/registration/login.html:23 msgid "Login" msgstr "Se connecter" @@ -859,10 +865,18 @@ msgstr "Se connecter" msgid "Powered by" msgstr "Propulsé par" +#: ponyconf/templates/registration/login.html:24 +msgid "Forgot password?" +msgstr "Mot de passe oublié ?" + #: ponyconf/templates/registration/password_change_form.html:9 msgid "Password Change" msgstr "Changement de mot de passe" +#: ponyconf/urls.py:27 +msgid "Email address" +msgstr "" + #: proposals/forms.py:46 msgid "Should be less than 255 characters" msgstr "Texte court, moins de 255 caractères" diff --git a/ponyconf/backends.py b/ponyconf/backends.py new file mode 100644 index 0000000..29d3dea --- /dev/null +++ b/ponyconf/backends.py @@ -0,0 +1,16 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import ModelBackend + + +class EmailBackend(ModelBackend): + def authenticate(self, request, username=None, password=None, **kwargs): + if not username: + return None + UserModel = get_user_model() + try: + user = UserModel._default_manager.get(email__iexact=username) + except UserModel.DoesNotExist: + UserModel().set_password(password) # https://code.djangoproject.com/ticket/20760 + else: + if user.check_password(password) and self.user_can_authenticate(user): + return user diff --git a/ponyconf/settings.py b/ponyconf/settings.py index 9f546e3..ce22f05 100644 --- a/ponyconf/settings.py +++ b/ponyconf/settings.py @@ -210,7 +210,10 @@ SELECT2_JS = 'select2/dist/js/select2.min.js' SELECT2_CSS = 'select2/dist/css/select2.min.css' SELECT2_I18N_PATH = 'select2/dist/js/i18n' -#AUTHENTICATION_BACKENDS = ['yeouia.backends.YummyEmailOrUsernameInsensitiveAuth'] +AUTHENTICATION_BACKENDS = [ + 'django.contrib.auth.backends.ModelBackend', + 'ponyconf.backends.EmailBackend', +] LOGOUT_REDIRECT_URL = 'home' CRISPY_TEMPLATE_PACK='bootstrap3' diff --git a/ponyconf/templates/registration/login.html b/ponyconf/templates/registration/login.html index 2293b3e..33a3bde 100644 --- a/ponyconf/templates/registration/login.html +++ b/ponyconf/templates/registration/login.html @@ -17,11 +17,11 @@ {% bootstrap_form_errors form layout="horizontal" %}
{% csrf_token %} - {% bootstrap_field form.username layout="horizontal" placeholder="Nom d’utilisateur, e-mail ou numéro d’adhérent" %} + {% bootstrap_field form.username layout="horizontal" %} {% bootstrap_field form.password layout="horizontal" %} {% buttons layout="horizontal" %} - - Mot de passe oublié ? + + {% trans "Forgot password?" %} {% endbuttons %}
diff --git a/ponyconf/urls.py b/ponyconf/urls.py index a17e402..12018a8 100644 --- a/ponyconf/urls.py +++ b/ponyconf/urls.py @@ -15,10 +15,24 @@ Including another URLconf """ from django.conf.urls import include, url from django.contrib import admin +from django.contrib.auth.views import LoginView +from django.contrib.auth.forms import AuthenticationForm +from django.utils.translation import ugettext_lazy as _ + + +class EmailAuthenticationForm(AuthenticationForm): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['username'].label = _('Email address') + + +class EmailLoginView(LoginView): + authentication_form = EmailAuthenticationForm urlpatterns = [ url(r'^admin/', admin.site.urls), + url(r'accounts/login/', EmailLoginView.as_view()), url(r'accounts/', include('django.contrib.auth.urls')), url(r'^', include('cfp.urls')), ]