mirror of
https://github.com/Tivix/django-rest-auth.git
synced 2025-07-22 13:39:45 +03:00
Merge 4a4f02f46a
into eb9e6eb05a
This commit is contained in:
commit
bebb82fd73
|
@ -18,7 +18,6 @@ from requests.exceptions import HTTPError
|
||||||
if 'allauth.socialaccount' in settings.INSTALLED_APPS:
|
if 'allauth.socialaccount' in settings.INSTALLED_APPS:
|
||||||
from allauth.socialaccount.helpers import complete_social_login
|
from allauth.socialaccount.helpers import complete_social_login
|
||||||
|
|
||||||
|
|
||||||
class SocialLoginSerializer(serializers.Serializer):
|
class SocialLoginSerializer(serializers.Serializer):
|
||||||
access_token = serializers.CharField(required=False, allow_blank=True)
|
access_token = serializers.CharField(required=False, allow_blank=True)
|
||||||
code = serializers.CharField(required=False, allow_blank=True)
|
code = serializers.CharField(required=False, allow_blank=True)
|
||||||
|
@ -40,7 +39,8 @@ class SocialLoginSerializer(serializers.Serializer):
|
||||||
`allauth.socialaccount.SocialLoginView` instance
|
`allauth.socialaccount.SocialLoginView` instance
|
||||||
"""
|
"""
|
||||||
request = self._get_request()
|
request = self._get_request()
|
||||||
social_login = adapter.complete_login(request, app, token, response=response)
|
social_login = adapter.complete_login(
|
||||||
|
request, app, token, response=response)
|
||||||
social_login.token = token
|
social_login.token = token
|
||||||
return social_login
|
return social_login
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ from .views import RegisterView, VerifyEmailView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', RegisterView.as_view(), name='rest_register'),
|
url(r'^$', RegisterView.as_view(), name='rest_register'),
|
||||||
url(r'^verify-email/$', VerifyEmailView.as_view(), name='rest_verify_email'),
|
url(r'^verify-email/$', VerifyEmailView.as_view(),
|
||||||
|
name='rest_verify_email'),
|
||||||
|
|
||||||
# This url is used by django-allauth and empty TemplateView is
|
# This url is used by django-allauth and empty TemplateView is
|
||||||
# defined just to allow reverse() call inside app, for example when email
|
# defined just to allow reverse() call inside app, for example when email
|
||||||
|
|
|
@ -92,6 +92,7 @@ class VerifyEmailView(APIView, ConfirmEmailView):
|
||||||
|
|
||||||
|
|
||||||
class SocialLoginView(LoginView):
|
class SocialLoginView(LoginView):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
class used for social authentications
|
class used for social authentications
|
||||||
example usage for facebook with access_token
|
example usage for facebook with access_token
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django.contrib.auth import get_user_model, authenticate
|
from django.contrib.auth import get_user_model, authenticate
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
|
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
|
||||||
from django.contrib.auth.tokens import default_token_generator
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
@ -51,7 +52,8 @@ class LoginSerializer(serializers.Serializer):
|
||||||
elif username and password:
|
elif username and password:
|
||||||
user = authenticate(username=username, password=password)
|
user = authenticate(username=username, password=password)
|
||||||
else:
|
else:
|
||||||
msg = _('Must include either "username" or "email" and "password".')
|
msg = _(
|
||||||
|
'Must include either "username" or "email" and "password".')
|
||||||
raise exceptions.ValidationError(msg)
|
raise exceptions.ValidationError(msg)
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
@ -102,7 +104,10 @@ class LoginSerializer(serializers.Serializer):
|
||||||
if 'rest_auth.registration' in settings.INSTALLED_APPS:
|
if 'rest_auth.registration' in settings.INSTALLED_APPS:
|
||||||
from allauth.account import app_settings
|
from allauth.account import app_settings
|
||||||
if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
|
if app_settings.EMAIL_VERIFICATION == app_settings.EmailVerificationMethod.MANDATORY:
|
||||||
|
try:
|
||||||
email_address = user.emailaddress_set.get(email=user.email)
|
email_address = user.emailaddress_set.get(email=user.email)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
raise serializers.ValidationError(_('E-mail for this user not created'))
|
||||||
if not email_address.verified:
|
if not email_address.verified:
|
||||||
raise serializers.ValidationError(_('E-mail is not verified.'))
|
raise serializers.ValidationError(_('E-mail is not verified.'))
|
||||||
|
|
||||||
|
@ -111,6 +116,7 @@ class LoginSerializer(serializers.Serializer):
|
||||||
|
|
||||||
|
|
||||||
class TokenSerializer(serializers.ModelSerializer):
|
class TokenSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Serializer for Token model.
|
Serializer for Token model.
|
||||||
"""
|
"""
|
||||||
|
@ -164,7 +170,8 @@ class PasswordResetSerializer(serializers.Serializer):
|
||||||
|
|
||||||
def validate_email(self, value):
|
def validate_email(self, value):
|
||||||
# Create PasswordResetForm with the serializer
|
# Create PasswordResetForm with the serializer
|
||||||
self.reset_form = self.password_reset_form_class(data=self.initial_data)
|
self.reset_form = self.password_reset_form_class(
|
||||||
|
data=self.initial_data)
|
||||||
if not self.reset_form.is_valid():
|
if not self.reset_form.is_valid():
|
||||||
raise serializers.ValidationError(self.reset_form.errors)
|
raise serializers.ValidationError(self.reset_form.errors)
|
||||||
|
|
||||||
|
@ -184,6 +191,7 @@ 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.
|
||||||
"""
|
"""
|
||||||
|
@ -205,7 +213,7 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
|
||||||
uid = force_text(uid_decoder(attrs['uid']))
|
uid = force_text(uid_decoder(attrs['uid']))
|
||||||
self.user = UserModel._default_manager.get(pk=uid)
|
self.user = UserModel._default_manager.get(pk=uid)
|
||||||
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
|
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
|
||||||
raise ValidationError({'uid': ['Invalid value']})
|
raise ValidationError({'uid': [_('Invalid value')]})
|
||||||
|
|
||||||
self.custom_validation(attrs)
|
self.custom_validation(attrs)
|
||||||
# Construct SetPasswordForm instance
|
# Construct SetPasswordForm instance
|
||||||
|
@ -215,7 +223,7 @@ class PasswordResetConfirmSerializer(serializers.Serializer):
|
||||||
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']):
|
||||||
raise ValidationError({'token': ['Invalid value']})
|
raise ValidationError({'token': [_('Invalid value')]})
|
||||||
|
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
|
@ -253,7 +261,7 @@ class PasswordChangeSerializer(serializers.Serializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
if all(invalid_password_conditions):
|
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):
|
||||||
|
|
|
@ -8,7 +8,8 @@ from django.contrib.auth.urls import urlpatterns
|
||||||
|
|
||||||
# special urls for auth test cases
|
# special urls for auth test cases
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
url(r'^logout/custom_query/$', views.logout, dict(redirect_field_name='follow')),
|
url(r'^logout/custom_query/$', views.logout,
|
||||||
|
dict(redirect_field_name='follow')),
|
||||||
url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')),
|
url(r'^logout/next_page/$', views.logout, dict(next_page='/somewhere/')),
|
||||||
url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')),
|
url(r'^logout/next_page/named/$', views.logout, dict(next_page='password_reset')),
|
||||||
url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')),
|
url(r'^password_reset_from_email/$', views.password_reset, dict(from_email='staffmember@example.com')),
|
||||||
|
@ -22,9 +23,12 @@ urlpatterns += [
|
||||||
url(r'^reset/custom/named/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
|
url(r'^reset/custom/named/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
|
||||||
views.password_reset_confirm,
|
views.password_reset_confirm,
|
||||||
dict(post_reset_redirect='password_reset')),
|
dict(post_reset_redirect='password_reset')),
|
||||||
url(r'^password_change/custom/$', views.password_change, dict(post_change_redirect='/custom/')),
|
url(r'^password_change/custom/$', views.password_change,
|
||||||
url(r'^password_change/custom/named/$', views.password_change, dict(post_change_redirect='password_reset')),
|
dict(post_change_redirect='/custom/')),
|
||||||
url(r'^admin_password_reset/$', views.password_reset, dict(is_admin_site=True)),
|
url(r'^password_change/custom/named/$', views.password_change,
|
||||||
|
dict(post_change_redirect='password_reset')),
|
||||||
|
url(r'^admin_password_reset/$',
|
||||||
|
views.password_reset, dict(is_admin_site=True)),
|
||||||
url(r'^login_required/$', login_required(views.password_reset)),
|
url(r'^login_required/$', login_required(views.password_reset)),
|
||||||
url(r'^login_required_login_url/$', login_required(views.password_reset, login_url='/somewhere/')),
|
url(r'^login_required_login_url/$', login_required(views.password_reset, login_url='/somewhere/')),
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,6 +12,7 @@ from .test_base import BaseAPITestCase
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF="tests.urls")
|
@override_settings(ROOT_URLCONF="tests.urls")
|
||||||
class APITestCase1(TestCase, BaseAPITestCase):
|
class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Case #1:
|
Case #1:
|
||||||
- user profile: defined
|
- user profile: defined
|
||||||
|
@ -97,7 +98,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
self.post(self.password_change_url, status_code=403)
|
self.post(self.password_change_url, status_code=403)
|
||||||
|
|
||||||
# create user
|
# create user
|
||||||
user = get_user_model().objects.create_user(self.USERNAME, '', self.PASS)
|
user = get_user_model().objects.create_user(
|
||||||
|
self.USERNAME, '', self.PASS)
|
||||||
|
|
||||||
self.post(self.login_url, data=payload, status_code=200)
|
self.post(self.login_url, data=payload, status_code=200)
|
||||||
self.assertEqual('key' in self.response.json.keys(), True)
|
self.assertEqual('key' in self.response.json.keys(), True)
|
||||||
|
@ -162,7 +164,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
self.post(self.password_change_url, status_code=403)
|
self.post(self.password_change_url, status_code=403)
|
||||||
|
|
||||||
# create user
|
# create user
|
||||||
user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS)
|
user = get_user_model().objects.create_user(
|
||||||
|
self.USERNAME, self.EMAIL, self.PASS)
|
||||||
|
|
||||||
# test auth by email
|
# test auth by email
|
||||||
self.post(self.login_url, data=payload, status_code=200)
|
self.post(self.login_url, data=payload, status_code=200)
|
||||||
|
@ -276,7 +279,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
self.post(self.login_url, data=login_payload, status_code=200)
|
self.post(self.login_url, data=login_payload, status_code=200)
|
||||||
|
|
||||||
def test_password_reset(self):
|
def test_password_reset(self):
|
||||||
user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS)
|
user = get_user_model().objects.create_user(
|
||||||
|
self.USERNAME, self.EMAIL, self.PASS)
|
||||||
|
|
||||||
# call password reset
|
# call password reset
|
||||||
mail_count = len(mail.outbox)
|
mail_count = len(mail.outbox)
|
||||||
|
@ -331,7 +335,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
self.post(self.login_url, data=payload, status_code=200)
|
self.post(self.login_url, data=payload, status_code=200)
|
||||||
|
|
||||||
def test_password_reset_with_email_in_different_case(self):
|
def test_password_reset_with_email_in_different_case(self):
|
||||||
get_user_model().objects.create_user(self.USERNAME, self.EMAIL.lower(), self.PASS)
|
get_user_model().objects.create_user(
|
||||||
|
self.USERNAME, self.EMAIL.lower(), self.PASS)
|
||||||
|
|
||||||
# call password reset in upper case
|
# call password reset in upper case
|
||||||
mail_count = len(mail.outbox)
|
mail_count = len(mail.outbox)
|
||||||
|
@ -343,7 +348,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
"""
|
"""
|
||||||
Invalid email should not raise error, as this would leak users
|
Invalid email should not raise error, as this would leak users
|
||||||
"""
|
"""
|
||||||
get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS)
|
get_user_model().objects.create_user(
|
||||||
|
self.USERNAME, self.EMAIL, self.PASS)
|
||||||
|
|
||||||
# call password reset
|
# call password reset
|
||||||
mail_count = len(mail.outbox)
|
mail_count = len(mail.outbox)
|
||||||
|
@ -352,7 +358,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
self.assertEqual(len(mail.outbox), mail_count)
|
self.assertEqual(len(mail.outbox), mail_count)
|
||||||
|
|
||||||
def test_user_details(self):
|
def test_user_details(self):
|
||||||
user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS)
|
user = get_user_model().objects.create_user(
|
||||||
|
self.USERNAME, self.EMAIL, self.PASS)
|
||||||
payload = {
|
payload = {
|
||||||
"username": self.USERNAME,
|
"username": self.USERNAME,
|
||||||
"password": self.PASS
|
"password": self.PASS
|
||||||
|
@ -388,9 +395,11 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
# test empty payload
|
# test empty payload
|
||||||
self.post(self.register_url, data={}, status_code=400)
|
self.post(self.register_url, data={}, status_code=400)
|
||||||
|
|
||||||
result = self.post(self.register_url, data=self.REGISTRATION_DATA, status_code=201)
|
result = self.post(
|
||||||
|
self.register_url, data=self.REGISTRATION_DATA, status_code=201)
|
||||||
self.assertIn('key', result.data)
|
self.assertIn('key', result.data)
|
||||||
self.assertEqual(get_user_model().objects.all().count(), user_count + 1)
|
self.assertEqual(
|
||||||
|
get_user_model().objects.all().count(), user_count + 1)
|
||||||
|
|
||||||
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'])
|
||||||
|
@ -439,7 +448,8 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
||||||
status_code=status.HTTP_201_CREATED
|
status_code=status.HTTP_201_CREATED
|
||||||
)
|
)
|
||||||
self.assertNotIn('key', result.data)
|
self.assertNotIn('key', result.data)
|
||||||
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')
|
||||||
self.assertEqual(new_user.username, self.REGISTRATION_DATA['username'])
|
self.assertEqual(new_user.username, self.REGISTRATION_DATA['username'])
|
||||||
|
|
|
@ -24,6 +24,7 @@ class BaseAPITestCase(object):
|
||||||
* easy request calls, f.e.: self.post(url, data), self.get(url)
|
* easy request calls, f.e.: self.post(url, data), self.get(url)
|
||||||
* easy status check, f.e.: self.post(url, data, status_code=200)
|
* easy status check, f.e.: self.post(url, data, status_code=200)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -98,12 +98,14 @@ class TestSocialAuth(TestCase, BaseAPITestCase):
|
||||||
|
|
||||||
self.post(self.fb_login_url, data=payload, status_code=200)
|
self.post(self.fb_login_url, data=payload, status_code=200)
|
||||||
self.assertIn('key', self.response.json.keys())
|
self.assertIn('key', self.response.json.keys())
|
||||||
self.assertEqual(get_user_model().objects.all().count(), users_count + 1)
|
self.assertEqual(
|
||||||
|
get_user_model().objects.all().count(), users_count + 1)
|
||||||
|
|
||||||
# make sure that second request will not create a new user
|
# make sure that second request will not create a new user
|
||||||
self.post(self.fb_login_url, data=payload, status_code=200)
|
self.post(self.fb_login_url, data=payload, status_code=200)
|
||||||
self.assertIn('key', self.response.json.keys())
|
self.assertIn('key', self.response.json.keys())
|
||||||
self.assertEqual(get_user_model().objects.all().count(), users_count + 1)
|
self.assertEqual(
|
||||||
|
get_user_model().objects.all().count(), users_count + 1)
|
||||||
|
|
||||||
def _twitter_social_auth(self):
|
def _twitter_social_auth(self):
|
||||||
# fake response for twitter call
|
# fake response for twitter call
|
||||||
|
|
|
@ -71,6 +71,7 @@ class LoginView(GenericAPIView):
|
||||||
self.process_login()
|
self.process_login()
|
||||||
|
|
||||||
def get_response(self):
|
def get_response(self):
|
||||||
|
|
||||||
serializer_class = self.get_response_serializer()
|
serializer_class = self.get_response_serializer()
|
||||||
|
|
||||||
if getattr(settings, 'REST_USE_JWT', False):
|
if getattr(settings, 'REST_USE_JWT', False):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user