diff --git a/README.md b/README.md index 2758b581559cece1a2bcc399d311aebdc7416dd6..d3f01682caf48ccd0bdcc4294b9e36a4c86d9b20 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ BASETHEME_BOOTSTRAP_TEMPLATE_LOCATION_PROJECT = "test_app_1" BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_ENABLED = True BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_LOCATION_APP = "test_app_1" BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_NAME = "MyUserPreferences" +BASETHEME_BOOTSTRAP_USERNAME_IS_EMAIL = False ################################################################################ ``` diff --git a/basetheme_bootstrap/forms.py b/basetheme_bootstrap/forms.py index e1f9b6243aee49eb58b6d11e88428730efe13f7e..af757135054acfff44823e5fccd59c659a77cc0f 100644 --- a/basetheme_bootstrap/forms.py +++ b/basetheme_bootstrap/forms.py @@ -1,13 +1,39 @@ -import itertools - +from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.forms import UserCreationForm, UsernameField, UserChangeForm -from django.db.models.query_utils import Q +from django.db.models import Q from django.forms import ModelForm -from django.utils.translation import ugettext as _ +from django.urls import reverse +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ + + +class CleanUsernameAndSuggestReset: + class Meta: + abstract = True + + @property + def is_username_is_email(self): + try: + return settings.BASETHEME_BOOTSTRAP_USERNAME_IS_EMAIL + except AttributeError: + return False + def clean(self): + f = super().clean() + qs = get_user_model().objects + if hasattr(self, 'instance'): + qs = qs.filter(~Q(id=self.instance.id)) + if qs.filter(email=f["email"]).exists() or \ + not self.is_username_is_email and \ + qs.filter(username=f.get("username", "")).exists(): + self.add_error("email", mark_safe(_( + 'The email already exists, if you have lost your password you can reset it ' + '<a href="%s">here</a>.') % (reverse('basetheme_bootstrap:password_reset')))) + return f -class UserCreationFormWithMore(UserCreationForm): + +class UserCreationFormWithMore(CleanUsernameAndSuggestReset, UserCreationForm): class Meta: model = get_user_model() fields = ("username", "email", "first_name", "last_name") @@ -16,15 +42,39 @@ class UserCreationFormWithMore(UserCreationForm): def __init__(self, *args, **kwargs): super(UserCreationFormWithMore, self).__init__(*args, **kwargs) self.fields['email'].widget.attrs.update({'required': True}) + if self.is_username_is_email: + del self.fields['username'] + + def save(self, commit=True): + user = super().save(commit=False) + if self.is_username_is_email: + user.username = user.email + if commit: + user.save() + return user -class MyUserChangeForm(UserChangeForm): +class MyUserChangeForm(CleanUsernameAndSuggestReset, UserChangeForm): class Meta: model = get_user_model() fields = ("username", "email", "first_name", "last_name", "password") + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.is_username_is_email: + del self.fields['username'] + self.fields['email'].widget.attrs.update({'required': True}) + + def save(self, commit=True): + user = super().save(commit=False) + if self.is_username_is_email: + user.username = user.email + if commit: + user.save() + return user + class UserDeleteForm(ModelForm): class Meta: model = get_user_model() - fields = () \ No newline at end of file + fields = () diff --git a/basetheme_bootstrap/tests.py b/basetheme_bootstrap/tests.py index e0aff444cbde5cff9cbdf01040adfe1f1e45d6ec..625dcf3c663a00eb0ecb101f013e35b709cf06b6 100644 --- a/basetheme_bootstrap/tests.py +++ b/basetheme_bootstrap/tests.py @@ -38,16 +38,54 @@ class SignUpTests(TestCase): def test_sign_up_form_view(self): user_count = get_user_model().objects.count() - response = self.client.post(reverse('basetheme_bootstrap:signup'), { + data = { 'username': "userAAA", 'email': "userAAA@mp.com", 'password1': "user@mp.comuser@mp.comuser@mp.comuser@mp.com", 'password2': "user@mp.comuser@mp.comuser@mp.comuser@mp.com", 'first_name': "user" - }) + } + response = self.client.post(reverse('basetheme_bootstrap:signup'), data) self.assertEqual(response.status_code, 302) self.assertRedirects(response, expected_url=reverse('home'), ) self.assertEqual(get_user_model().objects.count(), user_count + 1) + user = get_user_model().objects.last() + self.assertEqual(user.username, data["username"]) + self.assertEqual(user.email, data["email"]) + + +@override_settings( + BASETHEME_BOOTSTRAP_USERNAME_IS_EMAIL=True, +) +class SignUpWithoutUsernameTests(TestCase): + + def test_sign_up_form_view(self): + user_count = get_user_model().objects.count() + data = { + 'email': "userAAA@mp.com", + 'password1': "user@mp.comuser@mp.comuser@mp.comuser@mp.com", + 'password2': "user@mp.comuser@mp.comuser@mp.comuser@mp.com", + 'first_name': "user" + } + response = self.client.post(reverse('basetheme_bootstrap:signup'), data) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, expected_url=reverse('home'), ) + self.assertEqual(get_user_model().objects.count(), user_count + 1) + user = get_user_model().objects.last() + self.assertEqual(user.username, data["email"]) + self.assertEqual(user.email, data["email"]) + + def test_sign_up_detecte_duplicate_email(self): + get_user_model().objects.create(username="toto",email="userAAA@mp.com") + user_count = get_user_model().objects.count() + data = { + 'email': "userAAA@mp.com", + 'password1': "user@mp.comuser@mp.comuser@mp.comuser@mp.com", + 'password2': "user@mp.comuser@mp.comuser@mp.comuser@mp.com", + 'first_name': "user" + } + response = self.client.post(reverse('basetheme_bootstrap:signup'), data) + self.assertEqual(response.status_code, 200) class TestWithTemplatesInPlace(SignUpTests): diff --git a/basetheme_bootstrap/views.py b/basetheme_bootstrap/views.py index c7d1c05e9b13c087977b97cfb750c69217dfb80e..4c6f4e510e72fc9f68eef4a213af2e2c06c6f83c 100644 --- a/basetheme_bootstrap/views.py +++ b/basetheme_bootstrap/views.py @@ -57,7 +57,7 @@ def signup(request): user.is_superuser = True user.is_staff = True user.save() - username = form.cleaned_data.get('username') + username = user.username raw_password = form.cleaned_data.get('password1') user = authenticate(username=username, password=raw_password) request.user = user diff --git a/setup.py b/setup.py index 2eeea07b248ab05ad2f4223f889577cb9fcf2074..b069a61f09e4e9b3fbe5a8962bbb502dcf5e0c9b 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ readme = open('README.rst').read() setup( name='django-basetheme-bootstrap', - version='0.2.6', + version='0.2.7', description='Django Basetheme Bootstrap', long_description=readme, author='Bryan Brancotte', diff --git a/tests/settings.py b/tests/settings.py index 374509b000f08d1cdf8863b523e7bf5ce97e3bfc..842ee24bbbab75d0ce804b58d7dbe0f9ea22ca11 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -136,6 +136,7 @@ BASETHEME_BOOTSTRAP_TEMPLATE_LOCATION_PROJECT = "test_app_1" BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_ENABLED = True BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_LOCATION_APP = "test_app_1" BASETHEME_BOOTSTRAP_USER_PREFERENCE_MODEL_NAME = "MyUserPreferences" +# BASETHEME_BOOTSTRAP_USERNAME_IS_EMAIL = True # default is False ################################################################################ # Various debug stuff