merge fix

This commit is contained in:
mjaworski 2015-04-28 10:57:53 +02:00
commit 86f55483ee
13 changed files with 149 additions and 70 deletions

View File

@ -21,3 +21,5 @@ script:
- coverage run --source=rest_auth setup.py test - coverage run --source=rest_auth setup.py test
after_success: after_success:
- coveralls - coveralls
before_script:
- flake8 . --config=flake8

4
flake8 Normal file
View File

@ -0,0 +1,4 @@
[flake8]
max-line-length = 160
exclude = docs/*,demo/*
ignore = F403

View File

@ -24,16 +24,22 @@ LoginSerializer = import_callable(
) )
PasswordResetSerializer = import_callable( PasswordResetSerializer = import_callable(
serializers.get('PASSWORD_RESET_SERIALIZER', serializers.get(
DefaultPasswordResetSerializer) 'PASSWORD_RESET_SERIALIZER',
DefaultPasswordResetSerializer
)
) )
PasswordResetConfirmSerializer = import_callable( PasswordResetConfirmSerializer = import_callable(
serializers.get('PASSWORD_RESET_CONFIRM_SERIALIZER', serializers.get(
DefaultPasswordResetConfirmSerializer) 'PASSWORD_RESET_CONFIRM_SERIALIZER',
DefaultPasswordResetConfirmSerializer
)
) )
PasswordChangeSerializer = import_callable( PasswordChangeSerializer = import_callable(
serializers.get('PASSWORD_CHANGE_SERIALIZER', serializers.get(
DefaultPasswordChangeSerializer) 'PASSWORD_CHANGE_SERIALIZER',
DefaultPasswordChangeSerializer
)
) )

View File

@ -21,7 +21,9 @@ class CustomRequestAuthenticationForm(AuthenticationForm):
@never_cache @never_cache
def remote_user_auth_view(request): def remote_user_auth_view(request):
"Dummy view for remote user tests" """
Dummy view for remote user tests
"""
t = Template("Username is {{ user }}.") t = Template("Username is {{ user }}.")
c = RequestContext(request, {}) c = RequestContext(request, {})
return HttpResponse(t.render(c)) return HttpResponse(t.render(c))
@ -100,4 +102,4 @@ urlpatterns += [
# This line is only required to render the password reset with is_admin=True # This line is only required to render the password reset with is_admin=True
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
] ]

View File

@ -16,8 +16,10 @@ class SocialLoginSerializer(serializers.Serializer):
request = request._request request = request._request
if not view: if not view:
raise serializers.ValidationError('View is not defined, pass it ' + raise serializers.ValidationError(
'as a context variable') 'View is not defined, pass it as a context variable'
)
self.adapter_class = getattr(view, 'adapter_class', None) self.adapter_class = getattr(view, 'adapter_class', None)
if not self.adapter_class: if not self.adapter_class:

View File

@ -3,7 +3,8 @@ from django.conf.urls import patterns, url
from .views import Register, VerifyEmail from .views import Register, VerifyEmail
urlpatterns = patterns('', urlpatterns = patterns(
'',
url(r'^$', Register.as_view(), name='rest_register'), url(r'^$', Register.as_view(), name='rest_register'),
url(r'^verify-email/$', VerifyEmail.as_view(), name='rest_verify_email'), url(r'^verify-email/$', VerifyEmail.as_view(), name='rest_verify_email'),
@ -21,4 +22,3 @@ urlpatterns = patterns('',
url(r'^account-confirm-email/(?P<key>\w+)/$', TemplateView.as_view(), url(r'^account-confirm-email/(?P<key>\w+)/$', TemplateView.as_view(),
name='account_confirm_email'), name='account_confirm_email'),
) )

View File

@ -78,7 +78,6 @@ class PasswordResetSerializer(serializers.Serializer):
class PasswordResetConfirmSerializer(serializers.Serializer): class PasswordResetConfirmSerializer(serializers.Serializer):
""" """
Serializer for requesting a password reset e-mail. Serializer for requesting a password reset e-mail.
""" """
@ -107,8 +106,9 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
self.custom_validation(attrs) self.custom_validation(attrs)
# Construct SetPasswordForm instance # Construct SetPasswordForm instance
self.set_password_form = self.set_password_form_class(user=self.user, self.set_password_form = self.set_password_form_class(
data=attrs) user=self.user, data=attrs
)
if not self.set_password_form.is_valid(): if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors) raise serializers.ValidationError(self.set_password_form.errors)
if not default_token_generator.check_token(self.user, attrs['token']): if not default_token_generator.check_token(self.user, attrs['token']):
@ -129,8 +129,9 @@ class PasswordChangeSerializer(serializers.Serializer):
set_password_form_class = SetPasswordForm set_password_form_class = SetPasswordForm
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.old_password_field_enabled = getattr(settings, self.old_password_field_enabled = getattr(
'OLD_PASSWORD_FIELD_ENABLED', False) settings, 'OLD_PASSWORD_FIELD_ENABLED', False
)
super(PasswordChangeSerializer, self).__init__(*args, **kwargs) super(PasswordChangeSerializer, self).__init__(*args, **kwargs)
if not self.old_password_field_enabled: if not self.old_password_field_enabled:
@ -140,14 +141,20 @@ class PasswordChangeSerializer(serializers.Serializer):
self.user = getattr(self.request, 'user', None) self.user = getattr(self.request, 'user', None)
def validate_old_password(self, value): def validate_old_password(self, value):
if self.old_password_field_enabled and self.user and \ invalid_password_conditions = (
not self.user.check_password(value): self.old_password_field_enabled,
self.user,
not self.user.check_password(value)
)
if all(invalid_password_conditions):
raise serializers.ValidationError('Invalid password') raise serializers.ValidationError('Invalid password')
return value return value
def validate(self, attrs): def validate(self, attrs):
self.set_password_form = self.set_password_form_class(user=self.user, self.set_password_form = self.set_password_form_class(
data=attrs) user=self.user, data=attrs
)
if not self.set_password_form.is_valid(): if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors) raise serializers.ValidationError(self.set_password_form.errors)

View File

@ -11,7 +11,8 @@ from rest_auth.registration.views import SocialLogin
class FacebookLogin(SocialLogin): class FacebookLogin(SocialLogin):
adapter_class = FacebookOAuth2Adapter adapter_class = FacebookOAuth2Adapter
urlpatterns += patterns('', urlpatterns += patterns(
'',
url(r'^rest-registration/', include('rest_auth.registration.urls')), url(r'^rest-registration/', include('rest_auth.registration.urls')),
url(r'^test-admin/', include(rest_auth.django_test_urls)), url(r'^test-admin/', include(rest_auth.django_test_urls)),
url(r'^account-email-verification-sent/$', TemplateView.as_view(), url(r'^account-email-verification-sent/$', TemplateView.as_view(),

View File

@ -35,7 +35,7 @@ class BaseAPITestCase(object):
def send_request(self, request_method, *args, **kwargs): def send_request(self, request_method, *args, **kwargs):
request_func = getattr(self.client, request_method) request_func = getattr(self.client, request_method)
status_code = None status_code = None
if not 'content_type' in kwargs and request_method != 'get': if 'content_type' not in kwargs and request_method != 'get':
kwargs['content_type'] = 'application/json' kwargs['content_type'] = 'application/json'
if 'data' in kwargs and request_method != 'get' and kwargs['content_type'] == 'application/json': if 'data' in kwargs and request_method != 'get' and kwargs['content_type'] == 'application/json':
data = kwargs.get('data', '') data = kwargs.get('data', '')
@ -216,8 +216,11 @@ class APITestCase1(TestCase, BaseAPITestCase):
"new_password1": "new_person", "new_password1": "new_person",
"new_password2": "new_person" "new_password2": "new_person"
} }
self.post(self.password_change_url, data=new_password_payload, self.post(
status_code=200) self.password_change_url,
data=new_password_payload,
status_code=200
)
# user should not be able to login using old password # user should not be able to login using old password
self.post(self.login_url, data=login_payload, status_code=400) self.post(self.login_url, data=login_payload, status_code=400)
@ -231,8 +234,11 @@ class APITestCase1(TestCase, BaseAPITestCase):
"new_password1": "new_person1", "new_password1": "new_person1",
"new_password2": "new_person" "new_password2": "new_person"
} }
self.post(self.password_change_url, data=new_password_payload, self.post(
status_code=400) self.password_change_url,
data=new_password_payload,
status_code=400
)
# send empty payload # send empty payload
self.post(self.password_change_url, data={}, status_code=400) self.post(self.password_change_url, data={}, status_code=400)
@ -252,16 +258,22 @@ class APITestCase1(TestCase, BaseAPITestCase):
"new_password1": "new_person", "new_password1": "new_person",
"new_password2": "new_person" "new_password2": "new_person"
} }
self.post(self.password_change_url, data=new_password_payload, self.post(
status_code=400) self.password_change_url,
data=new_password_payload,
status_code=400
)
new_password_payload = { new_password_payload = {
"old_password": self.PASS, "old_password": self.PASS,
"new_password1": "new_person", "new_password1": "new_person",
"new_password2": "new_person" "new_password2": "new_person"
} }
self.post(self.password_change_url, data=new_password_payload, self.post(
status_code=200) self.password_change_url,
data=new_password_payload,
status_code=200
)
# user should not be able to login using old password # user should not be able to login using old password
self.post(self.login_url, data=login_payload, status_code=400) self.post(self.login_url, data=login_payload, status_code=400)
@ -364,11 +376,17 @@ class APITestCase1(TestCase, BaseAPITestCase):
mail_count = len(mail.outbox) mail_count = len(mail.outbox)
# test empty payload # test empty payload
self.post(self.register_url, data={}, self.post(
status_code=status.HTTP_400_BAD_REQUEST) self.register_url,
data={},
status_code=status.HTTP_400_BAD_REQUEST
)
self.post(self.register_url, data=self.REGISTRATION_DATA_WITH_EMAIL, self.post(
status_code=status.HTTP_201_CREATED) self.register_url,
data=self.REGISTRATION_DATA_WITH_EMAIL,
status_code=status.HTTP_201_CREATED
)
self.assertEqual(get_user_model().objects.all().count(), user_count + 1) self.assertEqual(get_user_model().objects.all().count(), user_count + 1)
self.assertEqual(len(mail.outbox), mail_count + 1) self.assertEqual(len(mail.outbox), mail_count + 1)
new_user = get_user_model().objects.latest('id') new_user = get_user_model().objects.latest('id')
@ -379,14 +397,20 @@ class APITestCase1(TestCase, BaseAPITestCase):
"username": self.USERNAME, "username": self.USERNAME,
"password": self.PASS "password": self.PASS
} }
self.post(self.login_url, data=payload, self.post(
status=status.HTTP_400_BAD_REQUEST) self.login_url,
data=payload,
status=status.HTTP_400_BAD_REQUEST
)
# veirfy email # verify email
email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\
.emailconfirmation_set.order_by('-created')[0] .emailconfirmation_set.order_by('-created')[0]
self.post(self.veirfy_email_url, data={"key": email_confirmation.key}, self.post(
status_code=status.HTTP_200_OK) self.veirfy_email_url,
data={"key": email_confirmation.key},
status_code=status.HTTP_200_OK
)
# try to login again # try to login again
self._login() self._login()
@ -423,8 +447,13 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
@responses.activate @responses.activate
def test_failed_social_auth(self): def test_failed_social_auth(self):
# fake response # fake response
responses.add(responses.GET, self.graph_api_url, body='', status=400, responses.add(
content_type='application/json') responses.GET,
self.graph_api_url,
body='',
status=400,
content_type='application/json'
)
payload = { payload = {
'access_token': 'abc123' 'access_token': 'abc123'
@ -434,9 +463,14 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
@responses.activate @responses.activate
def test_social_auth(self): def test_social_auth(self):
# fake response for facebook call # fake response for facebook call
resp_body = '{"id":"123123123123","first_name":"John","gender":"male","last_name":"Smith","link":"https:\\/\\/www.facebook.com\\/john.smith","locale":"en_US","name":"John Smith","timezone":2,"updated_time":"2014-08-13T10:14:38+0000","username":"john.smith","verified":true}' resp_body = '{"id":"123123123123","first_name":"John","gender":"male","last_name":"Smith","link":"https:\\/\\/www.facebook.com\\/john.smith","locale":"en_US","name":"John Smith","timezone":2,"updated_time":"2014-08-13T10:14:38+0000","username":"john.smith","verified":true}' # noqa
responses.add(responses.GET, self.graph_api_url, body=resp_body, responses.add(
status=200, content_type='application/json') responses.GET,
self.graph_api_url,
body=resp_body,
status=200,
content_type='application/json'
)
users_count = get_user_model().objects.all().count() users_count = get_user_model().objects.all().count()
payload = { payload = {
@ -459,24 +493,34 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
REST_SESSION_LOGIN=False REST_SESSION_LOGIN=False
) )
def test_edge_case(self): def test_edge_case(self):
resp_body = '{"id":"123123123123","first_name":"John","gender":"male","last_name":"Smith","link":"https:\\/\\/www.facebook.com\\/john.smith","locale":"en_US","name":"John Smith","timezone":2,"updated_time":"2014-08-13T10:14:38+0000","username":"john.smith","verified":true,"email":"%s"}' resp_body = '{"id":"123123123123","first_name":"John","gender":"male","last_name":"Smith","link":"https:\\/\\/www.facebook.com\\/john.smith","locale":"en_US","name":"John Smith","timezone":2,"updated_time":"2014-08-13T10:14:38+0000","username":"john.smith","verified":true,"email":"%s"}' # noqa
responses.add(responses.GET, self.graph_api_url, responses.add(
responses.GET,
self.graph_api_url,
body=resp_body % self.EMAIL, body=resp_body % self.EMAIL,
status=200, content_type='application/json') status=200,
content_type='application/json'
)
# test empty payload # test empty payload
self.post(self.register_url, data={}, status_code=400) self.post(self.register_url, data={}, status_code=400)
self.post(self.register_url, data=self.REGISTRATION_DATA, self.post(
status_code=201) self.register_url,
data=self.REGISTRATION_DATA,
status_code=201
)
new_user = get_user_model().objects.latest('id') new_user = get_user_model().objects.latest('id')
self.assertEqual(new_user.username, self.REGISTRATION_DATA['username']) self.assertEqual(new_user.username, self.REGISTRATION_DATA['username'])
# veirfy email # verify email
email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\ email_confirmation = new_user.emailaddress_set.get(email=self.EMAIL)\
.emailconfirmation_set.order_by('-created')[0] .emailconfirmation_set.order_by('-created')[0]
self.post(self.veirfy_email_url, data={"key": email_confirmation.key}, self.post(
status_code=status.HTTP_200_OK) self.veirfy_email_url,
data={"key": email_confirmation.key},
status_code=status.HTTP_200_OK
)
self._login() self._login()
self._logout() self._logout()

View File

@ -1,9 +1,12 @@
from django.conf.urls import patterns, url from django.conf.urls import patterns, url
from rest_auth.views import (Login, Logout, UserDetails, PasswordChange, from rest_auth.views import (
PasswordReset, PasswordResetConfirm) Login, Logout, UserDetails, PasswordChange,
PasswordReset, PasswordResetConfirm
)
urlpatterns = patterns('', urlpatterns = patterns(
'',
# URLs that do not require a session or valid token # URLs that do not require a session or valid token
url(r'^password/reset/$', PasswordReset.as_view(), url(r'^password/reset/$', PasswordReset.as_view(),
name='rest_password_reset'), name='rest_password_reset'),

View File

@ -13,4 +13,3 @@ def import_callable(path_or_callable):
assert isinstance(path_or_callable, string_types) assert isinstance(path_or_callable, string_types)
package, attr = path_or_callable.rsplit('.', 1) package, attr = path_or_callable.rsplit('.', 1)
return getattr(import_module(package), attr) return getattr(import_module(package), attr)

View File

@ -9,9 +9,11 @@ from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.authtoken.models import Token from rest_framework.authtoken.models import Token
from rest_framework.generics import RetrieveUpdateAPIView from rest_framework.generics import RetrieveUpdateAPIView
from .app_settings import (TokenSerializer, UserDetailsSerializer, from .app_settings import (
LoginSerializer, PasswordResetSerializer, PasswordResetConfirmSerializer, TokenSerializer, UserDetailsSerializer, LoginSerializer,
PasswordChangeSerializer) PasswordResetSerializer, PasswordResetConfirmSerializer,
PasswordChangeSerializer
)
class Login(GenericAPIView): class Login(GenericAPIView):
@ -38,12 +40,14 @@ class Login(GenericAPIView):
login(self.request, self.user) login(self.request, self.user)
def get_response(self): def get_response(self):
return Response(self.response_serializer(self.token).data, return Response(
status=status.HTTP_200_OK) self.response_serializer(self.token).data, status=status.HTTP_200_OK
)
def get_error_response(self): def get_error_response(self):
return Response(self.serializer.errors, return Response(
status=status.HTTP_400_BAD_REQUEST) self.serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
self.serializer = self.get_serializer(data=self.request.DATA) self.serializer = self.get_serializer(data=self.request.DATA)
@ -114,8 +118,10 @@ class PasswordReset(GenericAPIView):
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)
serializer.save() serializer.save()
# Return the success message with OK HTTP status # Return the success message with OK HTTP status
return Response({"success": "Password reset e-mail has been sent."}, return Response(
status=status.HTTP_200_OK) {"success": "Password reset e-mail has been sent."},
status=status.HTTP_200_OK
)
class PasswordResetConfirm(GenericAPIView): class PasswordResetConfirm(GenericAPIView):
@ -134,8 +140,9 @@ class PasswordResetConfirm(GenericAPIView):
def post(self, request): def post(self, request):
serializer = self.get_serializer(data=request.DATA) serializer = self.get_serializer(data=request.DATA)
if not serializer.is_valid(): if not serializer.is_valid():
return Response(serializer.errors, return Response(
status=status.HTTP_400_BAD_REQUEST) serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
serializer.save() serializer.save()
return Response({"success": "Password has been reset with the new password."}) return Response({"success": "Password has been reset with the new password."})
@ -155,7 +162,8 @@ class PasswordChange(GenericAPIView):
def post(self, request): def post(self, request):
serializer = self.get_serializer(data=request.DATA) serializer = self.get_serializer(data=request.DATA)
if not serializer.is_valid(): if not serializer.is_valid():
return Response(serializer.errors, return Response(
status=status.HTTP_400_BAD_REQUEST) serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
serializer.save() serializer.save()
return Response({"success": "New password has been saved."}) return Response({"success": "New password has been saved."})

View File

@ -1,4 +1,5 @@
# This file mainly exists to allow python setup.py test to work. # This file mainly exists to allow python setup.py test to work.
# flake8: noqa
import os import os
import sys import sys