registration with email verification:

- rebuild login view
- check email verification in LoginSerializer depends on allauth settings
- add test for registration with email verification
This commit is contained in:
Mateusz Sikora 2014-10-01 15:31:10 +02:00
parent f14b3b03f7
commit de1fb3d81f
5 changed files with 79 additions and 31 deletions

View File

@ -1,3 +1,4 @@
from django.views.generic import TemplateView
from django.conf.urls import patterns, url
from .views import Register, VerifyEmail
@ -6,5 +7,11 @@ urlpatterns = patterns('',
url(r'^$', Register.as_view(), name='rest_register'),
url(r'^verify-email/(?P<activation_key>\w+)/$', VerifyEmail.as_view(),
name='verify_email'),
url(r'^account-email-verification-sent/$', TemplateView.as_view(),
name='account_email_verification_sent'),
url(r'^account-confirm-email/(?P<key>\w+)/$', TemplateView.as_view(),
name='account_confirm_email'),
)

View File

@ -4,13 +4,25 @@ from django.conf import settings
from rest_framework import serializers
from rest_framework.serializers import _resolve_model
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.serializers import AuthTokenSerializer
profile_model_path = lambda: getattr(settings, 'REST_PROFILE_MODULE', None)
class LoginSerializer(serializers.Serializer):
username = serializers.CharField(max_length=30)
password = serializers.CharField(max_length=128)
class LoginSerializer(AuthTokenSerializer):
def validate(self, attrs):
attrs = super(LoginSerializer, self).validate(attrs)
if 'rest_auth.registration' in settings.INSTALLED_APPS:
from allauth.account import app_settings
if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
user = attrs['user']
email_address = user.emailaddress_set.get(email=user.email)
if not email_address.verified:
raise serializers.ValidationError('E-mail is not verified.')
return attrs
class TokenSerializer(serializers.ModelSerializer):

View File

@ -8,8 +8,10 @@ from django.test import TestCase
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from django.core import mail
from django.test.utils import override_settings
from rest_framework.serializers import _resolve_model
from rest_framework import status
class APIClient(Client):
@ -133,6 +135,9 @@ class APITestCase1(TestCase, BaseAPITestCase):
"password2": PASS
}
REGISTRATION_DATA_WITH_EMAIL = REGISTRATION_DATA.copy()
REGISTRATION_DATA_WITH_EMAIL['email'] = EMAIL
BASIC_USER_DATA = {
'first_name': "John",
'last_name': 'Smith',
@ -164,8 +169,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
"username": self.USERNAME,
"password": self.PASS
}
# there is no users in db so it should throw error (401)
self.post(self.login_url, data=payload, status_code=401)
# there is no users in db so it should throw error (400)
self.post(self.login_url, data=payload, status_code=400)
self.post(self.password_change_url, status_code=403)
@ -181,14 +186,14 @@ class APITestCase1(TestCase, BaseAPITestCase):
# test inactive user
user.is_active = False
user.save()
self.post(self.login_url, data=payload, status_code=401)
self.post(self.login_url, data=payload, status_code=400)
# test wrong username/password
payload = {
"username": self.USERNAME + '?',
"password": self.PASS
}
self.post(self.login_url, data=payload, status_code=401)
self.post(self.login_url, data=payload, status_code=400)
# test empty payload
self.post(self.login_url, data={}, status_code=400)
@ -210,7 +215,7 @@ class APITestCase1(TestCase, BaseAPITestCase):
status_code=200)
# user should not be able to login using old password
self.post(self.login_url, data=login_payload, status_code=401)
self.post(self.login_url, data=login_payload, status_code=400)
# new password should work
login_payload['password'] = new_password_payload['new_password1']
@ -302,3 +307,33 @@ class APITestCase1(TestCase, BaseAPITestCase):
self.assertEqual(User.objects.all().count(), user_count + 1)
new_user = get_user_model().objects.latest('id')
self.assertEqual(new_user.username, self.REGISTRATION_DATA['username'])
payload = {
"username": self.USERNAME,
"password": self.PASS
}
self.post(self.login_url, data=payload, status_code=200)
@override_settings(
ACCOUNT_EMAIL_VERIFICATION='mandatory',
ACCOUNT_EMAIL_REQUIRED=True
)
def test_registration_with_email_verification(self):
user_count = User.objects.all().count()
mail_count = len(mail.outbox)
# test empty payload
self.post(self.register_url, data={}, status_code=400)
self.post(self.register_url, data=self.REGISTRATION_DATA_WITH_EMAIL, status_code=201)
self.assertEqual(User.objects.all().count(), user_count + 1)
self.assertEqual(len(mail.outbox), mail_count + 1)
new_user = get_user_model().objects.latest('id')
self.assertEqual(new_user.username, self.REGISTRATION_DATA['username'])
# email is not verified yet
payload = {
"username": self.USERNAME,
"password": self.PASS
}
self.post(self.login_url, data=payload, status=status.HTTP_400_BAD_REQUEST)

View File

@ -1,5 +1,6 @@
from django.conf import settings
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
from rest_auth.views import Login, Logout, UserDetails, \
PasswordChange, PasswordReset, PasswordResetConfirm
@ -27,5 +28,9 @@ if getattr(settings, 'IS_TEST', False):
from django.contrib.auth.tests import urls
urlpatterns += patterns('',
url(r'^rest-registration/', include('registration.urls')),
url(r'^test-admin/', include(urls))
url(r'^test-admin/', include(urls)),
url(r'^account-email-verification-sent/$', TemplateView.as_view(),
name='account_email_verification_sent'),
url(r'^account-confirm-email/(?P<key>\w+)/$', TemplateView.as_view(),
name='account_confirm_email'),
)

View File

@ -62,29 +62,18 @@ class Login(LoggedOutRESTAPIView, GenericAPIView):
# Create a serializer with request.DATA
serializer = self.serializer_class(data=request.DATA)
if serializer.is_valid():
# Authenticate the credentials by grabbing Django User object
user = authenticate(username=serializer.data['username'],
password=serializer.data['password'])
if not serializer.is_valid():
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
user = serializer.object['user']
token, created = self.token_model.objects.get_or_create(user=user)
if user and user.is_authenticated():
if user.is_active:
if getattr(settings, 'REST_SESSION_LOGIN', True):
login(request, user)
# Return REST Token object with OK HTTP status
token, created = self.token_model.objects.get_or_create(user=user)
return Response(self.token_serializer(token).data,
status=status.HTTP_200_OK)
else:
return Response({'error': 'This account is disabled.'},
status=status.HTTP_401_UNAUTHORIZED)
else:
return Response({'error': 'Invalid Username/Password.'},
status=status.HTTP_401_UNAUTHORIZED)
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
class Logout(LoggedInRESTAPIView):