mirror of
				https://github.com/Tivix/django-rest-auth.git
				synced 2025-11-04 09:37:35 +03:00 
			
		
		
		
	Merge branch 'master' of https://github.com/Tivix/django-rest-auth
This commit is contained in:
		
						commit
						ccc261d57f
					
				| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
from django.conf.urls import patterns, include, url
 | 
					from django.conf.urls import include, url
 | 
				
			||||||
from django.contrib import admin
 | 
					from django.contrib import admin
 | 
				
			||||||
from django.views.generic import TemplateView, RedirectView
 | 
					from django.views.generic import TemplateView, RedirectView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = patterns('',
 | 
					urlpatterns = [
 | 
				
			||||||
    url(r'^$', TemplateView.as_view(template_name="home.html"), name='home'),
 | 
					    url(r'^$', TemplateView.as_view(template_name="home.html"), name='home'),
 | 
				
			||||||
    url(r'^signup/$', TemplateView.as_view(template_name="signup.html"),
 | 
					    url(r'^signup/$', TemplateView.as_view(template_name="signup.html"),
 | 
				
			||||||
        name='signup'),
 | 
					        name='signup'),
 | 
				
			||||||
| 
						 | 
					@ -36,4 +36,4 @@ urlpatterns = patterns('',
 | 
				
			||||||
    url(r'^account/', include('allauth.urls')),
 | 
					    url(r'^account/', include('allauth.urls')),
 | 
				
			||||||
    url(r'^admin/', include(admin.site.urls)),
 | 
					    url(r'^admin/', include(admin.site.urls)),
 | 
				
			||||||
    url(r'^accounts/profile/$', RedirectView.as_view(url='/', permanent=True), name='profile-redirect'),
 | 
					    url(r'^accounts/profile/$', RedirectView.as_view(url='/', permanent=True), name='profile-redirect'),
 | 
				
			||||||
)
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ Basic
 | 
				
			||||||
- /rest-auth/login/ (POST)
 | 
					- /rest-auth/login/ (POST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - username (string)
 | 
					    - username (string)
 | 
				
			||||||
 | 
					    - email (string)
 | 
				
			||||||
    - password (string)
 | 
					    - password (string)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,16 +56,6 @@ Registration
 | 
				
			||||||
    - password2
 | 
					    - password2
 | 
				
			||||||
    - email
 | 
					    - email
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    .. note:: This endpoint is based on ``allauth.account.views.SignupView`` and uses the same form as in this view. To override fields you have to create custom Signup Form and define it in django settings:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        .. code-block:: python
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            ACCOUNT_FORMS = {
 | 
					 | 
				
			||||||
                'signup': 'path.to.custom.SignupForm'
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        See allauth documentation for more details.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- /rest-auth/registration/verify-email/ (POST)
 | 
					- /rest-auth/registration/verify-email/ (POST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    - key
 | 
					    - key
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,13 @@ Configuration
 | 
				
			||||||
            ...
 | 
					            ...
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- **REST_AUTH_REGISTRATION_SERIALIZERS**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    You can define your custom serializers for registration endpoint.
 | 
				
			||||||
 | 
					    Possible key values:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        - REGISTER_SERIALIZER - serializer class in ``rest_auth.register.views.RegisterView``, default value ``rest_auth.register.serializers.RegisterSerializer``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models``
 | 
					- **REST_AUTH_TOKEN_MODEL** - model class for tokens, default value ``rest_framework.authtoken.models``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **REST_AUTH_TOKEN_CREATOR** - callable to create tokens, default value ``rest_auth.utils.default_create_token``.
 | 
					- **REST_AUTH_TOKEN_CREATOR** - callable to create tokens, default value ``rest_auth.utils.default_create_token``.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@ You're good to go now!
 | 
				
			||||||
Registration (optional)
 | 
					Registration (optional)
 | 
				
			||||||
-----------------------
 | 
					-----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. If you want to enable standard registration process you will need to install ``django-allauth`` - see this doc for installation http://django-allauth.readthedocs.org/en/latest/installation.html.
 | 
					1. If you want to enable standard registration process you will need to install ``django-allauth`` by using ``pip install django-rest-auth[extras]`` or ``pip install django-rest-auth[with_social]``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. Add ``allauth``, ``allauth.account`` and ``rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py:
 | 
					2. Add ``allauth``, ``allauth.account`` and ``rest_auth.registration`` apps to INSTALLED_APPS in your django settings.py:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								rest_auth/registration/app_settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								rest_auth/registration/app_settings.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from rest_auth.registration.serializers import (
 | 
				
			||||||
 | 
					    RegisterSerializer as DefaultRegisterSerializer)
 | 
				
			||||||
 | 
					from ..utils import import_callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					serializers = getattr(settings, 'REST_AUTH_REGISTER_SERIALIZERS', {})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RegisterSerializer = import_callable(
 | 
				
			||||||
 | 
					    serializers.get('REGISTER_SERIALIZER', DefaultRegisterSerializer))
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,15 @@
 | 
				
			||||||
from django.http import HttpRequest
 | 
					from django.http import HttpRequest
 | 
				
			||||||
from django.conf import settings
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    from allauth.account import app_settings as allauth_settings
 | 
				
			||||||
 | 
					    from allauth.utils import (email_address_exists,
 | 
				
			||||||
 | 
					                               get_username_max_length)
 | 
				
			||||||
 | 
					    from allauth.account.adapter import get_adapter
 | 
				
			||||||
 | 
					    from allauth.account.utils import setup_user_email
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    raise ImportError('allauth needs to be added to INSTALLED_APPS.')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_framework import serializers
 | 
					from rest_framework import serializers
 | 
				
			||||||
from requests.exceptions import HTTPError
 | 
					from requests.exceptions import HTTPError
 | 
				
			||||||
# Import is needed only if we are using social login, in which
 | 
					# Import is needed only if we are using social login, in which
 | 
				
			||||||
| 
						 | 
					@ -109,3 +118,57 @@ class SocialLoginSerializer(serializers.Serializer):
 | 
				
			||||||
        attrs['user'] = login.account.user
 | 
					        attrs['user'] = login.account.user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return attrs
 | 
					        return attrs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RegisterSerializer(serializers.Serializer):
 | 
				
			||||||
 | 
					    username = serializers.CharField(
 | 
				
			||||||
 | 
					        max_length=get_username_max_length(),
 | 
				
			||||||
 | 
					        min_length=allauth_settings.USERNAME_MIN_LENGTH,
 | 
				
			||||||
 | 
					        required=allauth_settings.USERNAME_REQUIRED
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    email = serializers.EmailField(required=allauth_settings.EMAIL_REQUIRED)
 | 
				
			||||||
 | 
					    password1 = serializers.CharField(required=True, write_only=True)
 | 
				
			||||||
 | 
					    password2 = serializers.CharField(required=True, write_only=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate_username(self, username):
 | 
				
			||||||
 | 
					        username = get_adapter().clean_username(username)
 | 
				
			||||||
 | 
					        return username
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate_email(self, email):
 | 
				
			||||||
 | 
					        email = get_adapter().clean_email(email)
 | 
				
			||||||
 | 
					        if allauth_settings.UNIQUE_EMAIL:
 | 
				
			||||||
 | 
					            if email and email_address_exists(email):
 | 
				
			||||||
 | 
					                raise serializers.ValidationError(
 | 
				
			||||||
 | 
					                    "A user is already registered with this e-mail address.")
 | 
				
			||||||
 | 
					        return email
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate_password1(self, password):
 | 
				
			||||||
 | 
					        return get_adapter().clean_password(password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate(self, data):
 | 
				
			||||||
 | 
					        if data['password1'] != data['password2']:
 | 
				
			||||||
 | 
					            raise serializers.ValidationError("The two password fields didn't match.")
 | 
				
			||||||
 | 
					        return data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def custom_signup(self, request, user):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_cleaned_data(self):
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'username': self.validated_data.get('username', ''),
 | 
				
			||||||
 | 
					            'password1': self.validated_data.get('password1', ''),
 | 
				
			||||||
 | 
					            'email': self.validated_data.get('email', '')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, request):
 | 
				
			||||||
 | 
					        adapter = get_adapter()
 | 
				
			||||||
 | 
					        user = adapter.new_user(request)
 | 
				
			||||||
 | 
					        self.cleaned_data = self.get_cleaned_data()
 | 
				
			||||||
 | 
					        adapter.save_user(request, user, self)
 | 
				
			||||||
 | 
					        self.custom_signup(request, user)
 | 
				
			||||||
 | 
					        setup_user_email(request, user, [])
 | 
				
			||||||
 | 
					        return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VerifyEmailSerializer(serializers.Serializer):
 | 
				
			||||||
 | 
					    key = serializers.CharField()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,9 @@
 | 
				
			||||||
from django.views.generic import TemplateView
 | 
					from django.views.generic import TemplateView
 | 
				
			||||||
from django.conf.urls import patterns, url
 | 
					from django.conf.urls import url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .views import RegisterView, VerifyEmailView
 | 
					from .views import RegisterView, VerifyEmailView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = patterns(
 | 
					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'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,4 +20,4 @@ urlpatterns = patterns(
 | 
				
			||||||
    # djang-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py#L190
 | 
					    # djang-allauth https://github.com/pennersr/django-allauth/blob/master/allauth/account/views.py#L190
 | 
				
			||||||
    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'),
 | 
				
			||||||
)
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,77 +1,44 @@
 | 
				
			||||||
from django.http import HttpRequest
 | 
					 | 
				
			||||||
from rest_framework.views import APIView
 | 
					from rest_framework.views import APIView
 | 
				
			||||||
from rest_framework.response import Response
 | 
					from rest_framework.response import Response
 | 
				
			||||||
from rest_framework.permissions import AllowAny
 | 
					from rest_framework.permissions import AllowAny
 | 
				
			||||||
 | 
					from rest_framework.generics import CreateAPIView
 | 
				
			||||||
from rest_framework import status
 | 
					from rest_framework import status
 | 
				
			||||||
 | 
					from rest_framework.exceptions import MethodNotAllowed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from allauth.account.views import SignupView, ConfirmEmailView
 | 
					from allauth.account.views import ConfirmEmailView
 | 
				
			||||||
from allauth.account.utils import complete_signup
 | 
					from allauth.account.utils import complete_signup
 | 
				
			||||||
from allauth.account import app_settings
 | 
					from allauth.account import app_settings as allauth_settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_auth.app_settings import TokenSerializer
 | 
					from rest_auth.app_settings import (TokenSerializer,
 | 
				
			||||||
from rest_auth.registration.serializers import SocialLoginSerializer
 | 
					                                    create_token)
 | 
				
			||||||
 | 
					from rest_auth.registration.serializers import (SocialLoginSerializer,
 | 
				
			||||||
 | 
					                                                VerifyEmailSerializer)
 | 
				
			||||||
from rest_auth.views import LoginView
 | 
					from rest_auth.views import LoginView
 | 
				
			||||||
from rest_auth.models import TokenModel
 | 
					from rest_auth.models import TokenModel
 | 
				
			||||||
 | 
					from .app_settings import RegisterSerializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RegisterView(APIView, SignupView):
 | 
					class RegisterView(CreateAPIView):
 | 
				
			||||||
    """
 | 
					    serializer_class = RegisterSerializer
 | 
				
			||||||
    Accepts the credentials and creates a new user
 | 
					    permission_classes = (AllowAny, )
 | 
				
			||||||
    if user does not exist already
 | 
					 | 
				
			||||||
    Return the REST Token if the credentials are valid and authenticated.
 | 
					 | 
				
			||||||
    Calls allauth complete_signup method
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Accept the following POST parameters: username, email, password
 | 
					 | 
				
			||||||
    Return the REST Framework Token Object's key.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    permission_classes = (AllowAny,)
 | 
					 | 
				
			||||||
    allowed_methods = ('POST', 'OPTIONS', 'HEAD')
 | 
					 | 
				
			||||||
    token_model = TokenModel
 | 
					    token_model = TokenModel
 | 
				
			||||||
    serializer_class = TokenSerializer
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, *args, **kwargs):
 | 
					    def create(self, request, *args, **kwargs):
 | 
				
			||||||
        return Response({}, status=status.HTTP_405_METHOD_NOT_ALLOWED)
 | 
					        serializer = self.get_serializer(data=request.data)
 | 
				
			||||||
 | 
					        serializer.is_valid(raise_exception=True)
 | 
				
			||||||
 | 
					        user = self.perform_create(serializer)
 | 
				
			||||||
 | 
					        headers = self.get_success_headers(serializer.data)
 | 
				
			||||||
 | 
					        return Response(TokenSerializer(user.auth_token).data,
 | 
				
			||||||
 | 
					                        status=status.HTTP_201_CREATED,
 | 
				
			||||||
 | 
					                        headers=headers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def put(self, *args, **kwargs):
 | 
					    def perform_create(self, serializer):
 | 
				
			||||||
        return Response({}, status=status.HTTP_405_METHOD_NOT_ALLOWED)
 | 
					        user = serializer.save(self.request)
 | 
				
			||||||
 | 
					        create_token(self.token_model, user, serializer)
 | 
				
			||||||
    def form_valid(self, form):
 | 
					        complete_signup(self.request._request, user,
 | 
				
			||||||
        self.user = form.save(self.request)
 | 
					                        allauth_settings.EMAIL_VERIFICATION,
 | 
				
			||||||
        self.token, created = self.token_model.objects.get_or_create(
 | 
					                        None)
 | 
				
			||||||
            user=self.user
 | 
					        return user
 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
        if isinstance(self.request, HttpRequest):
 | 
					 | 
				
			||||||
            request = self.request
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            request = self.request._request
 | 
					 | 
				
			||||||
        return complete_signup(request, self.user,
 | 
					 | 
				
			||||||
                               app_settings.EMAIL_VERIFICATION,
 | 
					 | 
				
			||||||
                               self.get_success_url())
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_form_kwargs(self, *args, **kwargs):
 | 
					 | 
				
			||||||
        kwargs = super(RegisterView, self).get_form_kwargs(*args, **kwargs)
 | 
					 | 
				
			||||||
        kwargs['data'] = self.request.data
 | 
					 | 
				
			||||||
        return kwargs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					 | 
				
			||||||
        self.initial = {}
 | 
					 | 
				
			||||||
        form_class = self.get_form_class()
 | 
					 | 
				
			||||||
        self.form = self.get_form(form_class)
 | 
					 | 
				
			||||||
        if self.form.is_valid():
 | 
					 | 
				
			||||||
            self.form_valid(self.form)
 | 
					 | 
				
			||||||
            return self.get_response()
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            return self.get_response_with_errors()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_response(self):
 | 
					 | 
				
			||||||
        # serializer = self.user_serializer_class(instance=self.user)
 | 
					 | 
				
			||||||
        serializer = self.serializer_class(instance=self.token,
 | 
					 | 
				
			||||||
                                           context={'request': self.request})
 | 
					 | 
				
			||||||
        return Response(serializer.data, status=status.HTTP_201_CREATED)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_response_with_errors(self):
 | 
					 | 
				
			||||||
        return Response(self.form.errors, status=status.HTTP_400_BAD_REQUEST)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VerifyEmailView(APIView, ConfirmEmailView):
 | 
					class VerifyEmailView(APIView, ConfirmEmailView):
 | 
				
			||||||
| 
						 | 
					@ -80,10 +47,12 @@ class VerifyEmailView(APIView, ConfirmEmailView):
 | 
				
			||||||
    allowed_methods = ('POST', 'OPTIONS', 'HEAD')
 | 
					    allowed_methods = ('POST', 'OPTIONS', 'HEAD')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, *args, **kwargs):
 | 
					    def get(self, *args, **kwargs):
 | 
				
			||||||
        return Response({}, status=status.HTTP_405_METHOD_NOT_ALLOWED)
 | 
					        raise MethodNotAllowed('GET')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def post(self, request, *args, **kwargs):
 | 
					    def post(self, request, *args, **kwargs):
 | 
				
			||||||
        self.kwargs['key'] = self.request.data.get('key', '')
 | 
					        serializer = VerifyEmailSerializer(data=request.data)
 | 
				
			||||||
 | 
					        serializer.is_valid(raise_exception=True)
 | 
				
			||||||
 | 
					        self.kwargs['key'] = serializer.validated_data['key']
 | 
				
			||||||
        confirmation = self.get_object()
 | 
					        confirmation = self.get_object()
 | 
				
			||||||
        confirmation.confirm(self.request)
 | 
					        confirmation.confirm(self.request)
 | 
				
			||||||
        return Response({'message': 'ok'}, status=status.HTTP_200_OK)
 | 
					        return Response({'message': 'ok'}, status=status.HTTP_200_OK)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,43 +20,73 @@ class LoginSerializer(serializers.Serializer):
 | 
				
			||||||
    email = serializers.EmailField(required=False, allow_blank=True)
 | 
					    email = serializers.EmailField(required=False, allow_blank=True)
 | 
				
			||||||
    password = serializers.CharField(style={'input_type': 'password'})
 | 
					    password = serializers.CharField(style={'input_type': 'password'})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _validate_email(self, email, password):
 | 
				
			||||||
 | 
					        user = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if email and password:
 | 
				
			||||||
 | 
					            user = authenticate(email=email, password=password)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            msg = _('Must include "email" and "password".')
 | 
				
			||||||
 | 
					            raise exceptions.ValidationError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _validate_username(self, username, password):
 | 
				
			||||||
 | 
					        user = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if username and password:
 | 
				
			||||||
 | 
					            user = authenticate(username=username, password=password)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            msg = _('Must include "username" and "password".')
 | 
				
			||||||
 | 
					            raise exceptions.ValidationError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _validate_username_email(self, username, email, password):
 | 
				
			||||||
 | 
					        user = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if email and password:
 | 
				
			||||||
 | 
					            user = authenticate(email=email, password=password)
 | 
				
			||||||
 | 
					        elif username and password:
 | 
				
			||||||
 | 
					            user = authenticate(username=username, password=password)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            msg = _('Must include either "username" or "email" and "password".')
 | 
				
			||||||
 | 
					            raise exceptions.ValidationError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate(self, attrs):
 | 
					    def validate(self, attrs):
 | 
				
			||||||
        username = attrs.get('username')
 | 
					        username = attrs.get('username')
 | 
				
			||||||
        email = attrs.get('email')
 | 
					        email = attrs.get('email')
 | 
				
			||||||
        password = attrs.get('password')
 | 
					        password = attrs.get('password')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        user = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if 'allauth' in settings.INSTALLED_APPS:
 | 
					        if 'allauth' in settings.INSTALLED_APPS:
 | 
				
			||||||
            from allauth.account import app_settings
 | 
					            from allauth.account import app_settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Authentication through email
 | 
					            # Authentication through email
 | 
				
			||||||
            if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.EMAIL:
 | 
					            if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.EMAIL:
 | 
				
			||||||
                if email and password:
 | 
					                user = self._validate_email(email, password)
 | 
				
			||||||
                    user = authenticate(email=email, password=password)
 | 
					
 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    msg = _('Must include "email" and "password".')
 | 
					 | 
				
			||||||
                    raise exceptions.ValidationError(msg)
 | 
					 | 
				
			||||||
            # Authentication through username
 | 
					            # Authentication through username
 | 
				
			||||||
            elif app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME:
 | 
					            if app_settings.AUTHENTICATION_METHOD == app_settings.AuthenticationMethod.USERNAME:
 | 
				
			||||||
                if username and password:
 | 
					                user = self._validate_username(username, password)
 | 
				
			||||||
                    user = authenticate(username=username, password=password)
 | 
					
 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    msg = _('Must include "username" and "password".')
 | 
					 | 
				
			||||||
                    raise exceptions.ValidationError(msg)
 | 
					 | 
				
			||||||
            # Authentication through either username or email
 | 
					            # Authentication through either username or email
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                if email and password:
 | 
					                user = self._validate_username_email(username, email, password)
 | 
				
			||||||
                    user = authenticate(email=email, password=password)
 | 
					 | 
				
			||||||
                elif username and password:
 | 
					 | 
				
			||||||
                    user = authenticate(username=username, password=password)
 | 
					 | 
				
			||||||
                else:
 | 
					 | 
				
			||||||
                    msg = _('Must include either "username" or "email" and "password".')
 | 
					 | 
				
			||||||
                    raise exceptions.ValidationError(msg)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        elif username and password:
 | 
					 | 
				
			||||||
            user = authenticate(username=username, password=password)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            msg = _('Must include "username" and "password".')
 | 
					            # Authentication without using allauth
 | 
				
			||||||
            raise exceptions.ValidationError(msg)
 | 
					            if email:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    username = UserModel.objects.get(email__iexact=email).username
 | 
				
			||||||
 | 
					                except UserModel.DoesNotExist:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if username:
 | 
				
			||||||
 | 
					                user = self._validate_username_email(username, '', password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Did we get back an active user?
 | 
					        # Did we get back an active user?
 | 
				
			||||||
        if user:
 | 
					        if user:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ from django.core.urlresolvers import reverse
 | 
				
			||||||
from django.test import TestCase
 | 
					from django.test import TestCase
 | 
				
			||||||
from django.contrib.auth import get_user_model
 | 
					from django.contrib.auth import get_user_model
 | 
				
			||||||
from django.core import mail
 | 
					from django.core import mail
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
from django.test.utils import override_settings
 | 
					from django.test.utils import override_settings
 | 
				
			||||||
from django.utils.encoding import force_text
 | 
					from django.utils.encoding import force_text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -90,6 +91,51 @@ class APITestCase1(TestCase, BaseAPITestCase):
 | 
				
			||||||
        # test empty payload
 | 
					        # test empty payload
 | 
				
			||||||
        self.post(self.login_url, data={}, status_code=400)
 | 
					        self.post(self.login_url, data={}, status_code=400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_login_by_email(self):
 | 
				
			||||||
 | 
					        # starting test without allauth app
 | 
				
			||||||
 | 
					        settings.INSTALLED_APPS.remove('allauth')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            "email": self.EMAIL.lower(),
 | 
				
			||||||
 | 
					            "password": self.PASS
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        # 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # create user
 | 
				
			||||||
 | 
					        user = get_user_model().objects.create_user(self.USERNAME, self.EMAIL, self.PASS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # test auth by email
 | 
				
			||||||
 | 
					        self.post(self.login_url, data=payload, status_code=200)
 | 
				
			||||||
 | 
					        self.assertEqual('key' in self.response.json.keys(), True)
 | 
				
			||||||
 | 
					        self.token = self.response.json['key']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # test auth by email in different case
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            "email": self.EMAIL.upper(),
 | 
				
			||||||
 | 
					            "password": self.PASS
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.post(self.login_url, data=payload, status_code=200)
 | 
				
			||||||
 | 
					        self.assertEqual('key' in self.response.json.keys(), True)
 | 
				
			||||||
 | 
					        self.token = self.response.json['key']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # test inactive user
 | 
				
			||||||
 | 
					        user.is_active = False
 | 
				
			||||||
 | 
					        user.save()
 | 
				
			||||||
 | 
					        self.post(self.login_url, data=payload, status_code=400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # test wrong email/password
 | 
				
			||||||
 | 
					        payload = {
 | 
				
			||||||
 | 
					            "email": 't' + self.EMAIL,
 | 
				
			||||||
 | 
					            "password": self.PASS
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.post(self.login_url, data=payload, status_code=400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # test empty payload
 | 
				
			||||||
 | 
					        self.post(self.login_url, data={}, status_code=400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_password_change(self):
 | 
					    def test_password_change(self):
 | 
				
			||||||
        login_payload = {
 | 
					        login_payload = {
 | 
				
			||||||
            "username": self.USERNAME,
 | 
					            "username": self.USERNAME,
 | 
				
			||||||
| 
						 | 
					@ -225,7 +271,7 @@ 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):
 | 
				
			||||||
        user = 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)
 | 
				
			||||||
| 
						 | 
					@ -272,6 +318,12 @@ class APITestCase1(TestCase, BaseAPITestCase):
 | 
				
			||||||
        self._login()
 | 
					        self._login()
 | 
				
			||||||
        self._logout()
 | 
					        self._logout()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_registration_with_invalid_password(self):
 | 
				
			||||||
 | 
					        data = self.REGISTRATION_DATA.copy()
 | 
				
			||||||
 | 
					        data['password2'] = 'foobar'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.post(self.register_url, data=data, status_code=400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @override_settings(
 | 
					    @override_settings(
 | 
				
			||||||
        ACCOUNT_EMAIL_VERIFICATION='mandatory',
 | 
					        ACCOUNT_EMAIL_VERIFICATION='mandatory',
 | 
				
			||||||
        ACCOUNT_EMAIL_REQUIRED=True
 | 
					        ACCOUNT_EMAIL_REQUIRED=True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -99,7 +99,6 @@ class TestSocialAuth(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)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        self.post(
 | 
					        self.post(
 | 
				
			||||||
            self.register_url,
 | 
					            self.register_url,
 | 
				
			||||||
            data=self.REGISTRATION_DATA,
 | 
					            data=self.REGISTRATION_DATA,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
from django.conf.urls import patterns, url, include
 | 
					from django.conf.urls import url, include
 | 
				
			||||||
from django.views.generic import TemplateView
 | 
					from django.views.generic import TemplateView
 | 
				
			||||||
from . import django_urls
 | 
					from . import django_urls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,8 +11,7 @@ from rest_auth.registration.views import SocialLoginView
 | 
				
			||||||
class FacebookLogin(SocialLoginView):
 | 
					class FacebookLogin(SocialLoginView):
 | 
				
			||||||
    adapter_class = FacebookOAuth2Adapter
 | 
					    adapter_class = FacebookOAuth2Adapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns += patterns(
 | 
					urlpatterns += [
 | 
				
			||||||
    '',
 | 
					 | 
				
			||||||
    url(r'^rest-registration/', include('rest_auth.registration.urls')),
 | 
					    url(r'^rest-registration/', include('rest_auth.registration.urls')),
 | 
				
			||||||
    url(r'^test-admin/', include(django_urls)),
 | 
					    url(r'^test-admin/', include(django_urls)),
 | 
				
			||||||
    url(r'^account-email-verification-sent/$', TemplateView.as_view(),
 | 
					    url(r'^account-email-verification-sent/$', TemplateView.as_view(),
 | 
				
			||||||
| 
						 | 
					@ -21,4 +20,4 @@ urlpatterns += patterns(
 | 
				
			||||||
        name='account_confirm_email'),
 | 
					        name='account_confirm_email'),
 | 
				
			||||||
    url(r'^social-login/facebook/$', FacebookLogin.as_view(), name='fb_login'),
 | 
					    url(r'^social-login/facebook/$', FacebookLogin.as_view(), name='fb_login'),
 | 
				
			||||||
    url(r'^accounts/', include('allauth.socialaccount.urls'))
 | 
					    url(r'^accounts/', include('allauth.socialaccount.urls'))
 | 
				
			||||||
)
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,11 @@
 | 
				
			||||||
from django.conf.urls import patterns, url
 | 
					from django.conf.urls import url
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_auth.views import (
 | 
					from rest_auth.views import (
 | 
				
			||||||
    LoginView, LogoutView, UserDetailsView, PasswordChangeView,
 | 
					    LoginView, LogoutView, UserDetailsView, PasswordChangeView,
 | 
				
			||||||
    PasswordResetView, PasswordResetConfirmView
 | 
					    PasswordResetView, PasswordResetConfirmView
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = patterns(
 | 
					urlpatterns = [
 | 
				
			||||||
    '',
 | 
					 | 
				
			||||||
    # URLs that do not require a session or valid token
 | 
					    # URLs that do not require a session or valid token
 | 
				
			||||||
    url(r'^password/reset/$', PasswordResetView.as_view(),
 | 
					    url(r'^password/reset/$', PasswordResetView.as_view(),
 | 
				
			||||||
        name='rest_password_reset'),
 | 
					        name='rest_password_reset'),
 | 
				
			||||||
| 
						 | 
					@ -18,4 +17,4 @@ urlpatterns = patterns(
 | 
				
			||||||
    url(r'^user/$', UserDetailsView.as_view(), name='rest_user_details'),
 | 
					    url(r'^user/$', UserDetailsView.as_view(), name='rest_user_details'),
 | 
				
			||||||
    url(r'^password/change/$', PasswordChangeView.as_view(),
 | 
					    url(r'^password/change/$', PasswordChangeView.as_view(),
 | 
				
			||||||
        name='rest_password_change'),
 | 
					        name='rest_password_change'),
 | 
				
			||||||
)
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,6 @@ def import_callable(path_or_callable):
 | 
				
			||||||
        return getattr(import_module(package), attr)
 | 
					        return getattr(import_module(package), attr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def default_create_token(token_model, serializer):
 | 
					def default_create_token(token_model, user, serializer):
 | 
				
			||||||
    user = serializer.validated_data['user']
 | 
					 | 
				
			||||||
    token, _ = token_model.objects.get_or_create(user=user)
 | 
					    token, _ = token_model.objects.get_or_create(user=user)
 | 
				
			||||||
    return token
 | 
					    return token
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,7 +35,7 @@ class LoginView(GenericAPIView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def login(self):
 | 
					    def login(self):
 | 
				
			||||||
        self.user = self.serializer.validated_data['user']
 | 
					        self.user = self.serializer.validated_data['user']
 | 
				
			||||||
        self.token = create_token(self.token_model, self.serializer)
 | 
					        self.token = create_token(self.token_model, self.user, self.serializer)
 | 
				
			||||||
        if getattr(settings, 'REST_SESSION_LOGIN', True):
 | 
					        if getattr(settings, 'REST_SESSION_LOGIN', True):
 | 
				
			||||||
            login(self.request, self.user)
 | 
					            login(self.request, self.user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								setup.py
									
									
									
									
									
								
							| 
						 | 
					@ -32,6 +32,13 @@ setup(
 | 
				
			||||||
        'djangorestframework>=3.1.0',
 | 
					        'djangorestframework>=3.1.0',
 | 
				
			||||||
        'six>=1.9.0',
 | 
					        'six>=1.9.0',
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					    extras_require={
 | 
				
			||||||
 | 
					        'with_social': ['django-allauth>=0.24.1'],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    tests_require=[
 | 
				
			||||||
 | 
					        'responses>=0.5.0',
 | 
				
			||||||
 | 
					        'django-allauth>=0.24.1',
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
    test_suite='runtests.runtests',
 | 
					    test_suite='runtests.runtests',
 | 
				
			||||||
    include_package_data=True,
 | 
					    include_package_data=True,
 | 
				
			||||||
    # cmdclass={},
 | 
					    # cmdclass={},
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user