Rafał Pitoń 7 лет назад
Родитель
Сommit
5f2e57594f

+ 12 - 16
misago/users/api/userendpoints/create.py

@@ -8,8 +8,7 @@ from django.views.decorators.csrf import csrf_protect
 
 from misago.conf import settings
 from misago.core.mail import mail_user
-from misago.users import captcha
-from misago.users.forms.register import RegisterForm
+from misago.users.serializers import RegisterUserSerializer
 from misago.users.tokens import make_activation_token
 
 
@@ -21,16 +20,12 @@ def create_endpoint(request):
     if settings.account_activation == 'closed':
         raise PermissionDenied(_("New users registrations are currently closed."))
 
-    form = RegisterForm(request.data, request=request)
+    serializer = RegisterUserSerializer(
+        data=request.data,
+        context={'request': request},
+    )
 
-    try:
-        if form.is_valid():
-            captcha.test_request(request)
-    except ValidationError as e:
-        form.add_error('captcha', e)
-
-    if not form.is_valid():
-        return Response(form.errors, status=400)
+    serializer.is_valid(raise_exception=True)
 
     activation_kwargs = {}
     if settings.account_activation == 'user':
@@ -40,9 +35,9 @@ def create_endpoint(request):
 
     try:
         new_user = UserModel.objects.create_user(
-            form.cleaned_data['username'],
-            form.cleaned_data['email'],
-            form.cleaned_data['password'],
+            serializer.validated_data['username'],
+            serializer.validated_data['email'],
+            serializer.validated_data['password'],
             joined_from_ip=request.user_ip,
             set_default_avatar=True,
             **activation_kwargs
@@ -60,14 +55,15 @@ def create_endpoint(request):
 
     if settings.account_activation == 'none':
         authenticated_user = authenticate(
-            username=new_user.email, password=form.cleaned_data['password']
+            username=new_user.email,
+            password=serializer.validated_data['password'],
         )
         login(request, authenticated_user)
 
         mail_user(request, new_user, mail_subject, 'misago/emails/register/complete')
 
         return Response({
-            'activation': 'active',
+            'activation': None,
             'username': new_user.username,
             'email': new_user.email
         })

+ 1 - 0
misago/users/serializers/__init__.py

@@ -4,4 +4,5 @@ from .options import *
 from .rank import *
 from .user import *
 from .auth import *
+from .register import *
 from .usernamechange import *

+ 1 - 6
misago/users/serializers/auth.py

@@ -93,7 +93,7 @@ class AnonymousUserSerializer(serializers.Serializer, AuthFlags):
 
 
 class LoginSerializer(serializers.Serializer, AuthMixin):
-    username = serializers.CharField(max_length=254)
+    username = serializers.CharField(max_length=255)
     password = serializers.CharField(max_length=255, trim_whitespace=False)
 
     def validate(self, data):
@@ -180,8 +180,3 @@ class ChangePasswordSerializer(serializers.Serializer, AuthMixin):
     def save(self):
         self.instance.set_password(self.validated_data['password'])
         self.instance.save()
-
-
-class CreateUserSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = UserModel

+ 93 - 0
misago/users/serializers/register.py

@@ -0,0 +1,93 @@
+from rest_framework import serializers
+
+from django.contrib.auth import get_user_model
+from django.contrib.auth.password_validation import validate_password
+from django.core.exceptions import ValidationError
+from django.utils.translation import ugettext as _
+
+from misago.users import captcha, validators
+from misago.users.bans import get_email_ban, get_ip_ban, get_username_ban
+
+
+UserModel = get_user_model()
+
+
+__all__ = ['RegisterUserSerializer']
+
+
+class RegisterUserSerializer(serializers.Serializer):
+    username = serializers.CharField(
+        max_length=255,
+        validators=[validators.validate_username],
+    )
+    email = serializers.CharField(
+        max_length=255,
+        validators=[validators.validate_email],
+    )
+    password = serializers.CharField(
+        max_length=255,
+        trim_whitespace=False,
+    )
+
+    def validate_username(self, data):
+        ban = get_username_ban(data, registration_only=True)
+        if ban:
+            if ban.user_message:
+                raise ValidationError(ban.user_message)
+            else:
+                raise ValidationError(_("This usernane is not allowed."))
+        return data
+
+    def validate_email(self, data):
+        ban = get_email_ban(data, registration_only=True)
+        if ban:
+            if ban.user_message:
+                raise ValidationError(ban.user_message)
+            else:
+                raise ValidationError(_("This e-mail address is not allowed."))
+        return data
+
+    def validate(self, data):
+        request = self.context['request']
+
+        ban = get_ip_ban(request.user_ip, registration_only=True)
+        if ban:
+            if ban.user_message:
+                raise ValidationError(ban.user_message)
+            else:
+                raise ValidationError(_("New registrations from this IP address are not allowed."))
+
+        self._added_errors = {}
+
+        try:
+            self.full_clean_password(data)
+        except ValidationError as e:
+            self._added_errors['password'] = [e]
+
+        validators.validate_new_registration(request, self, data)
+
+        if self._added_errors:
+            # fail registration with additional errors
+            raise serializers.ValidationError(self._added_errors)
+
+        # run test for captcha
+        try:
+            captcha.test_request(self.context['request'])
+        except ValidationError as e:
+            raise serializers.ValidationError({'captcha': [e.args[0]]})
+
+        return data
+
+    def full_clean_password(self, data):
+        if data.get('password'):
+            validate_password(
+                data['password'],
+                user=UserModel(
+                    username=data.get('username'),
+                    email=data.get('email'),
+                ),
+            )
+
+    def add_error(self, field, error):
+        """we are using custom implementation so custom validators work"""
+        self._added_errors.setdefault(field, []).append(error)

+ 21 - 13
misago/users/tests/test_user_create_api.py

@@ -85,7 +85,7 @@ class UserCreateTests(UserTestCase):
         self.assertEqual(response.status_code, 400)
         self.assertEqual(
             response.json(), {
-                '__all__': ["You can't register account like this."],
+                'non_field_errors': ["You can't register account like this."],
             }
         )
 
@@ -304,9 +304,11 @@ class UserCreateTests(UserTestCase):
             },
         )
 
-        self.assertContains(response, 'active')
-        self.assertContains(response, 'Bob')
-        self.assertContains(response, 'bob@bob.com')
+        self.assertEqual(response.json(), {
+            'activation': None,
+            'username': 'Bob',
+            'email': 'bob@bob.com',
+        })
 
         UserModel.objects.get_by_username('Bob')
 
@@ -333,9 +335,11 @@ class UserCreateTests(UserTestCase):
             },
         )
 
-        self.assertContains(response, 'user')
-        self.assertContains(response, 'Bob')
-        self.assertContains(response, 'bob@bob.com')
+        self.assertEqual(response.json(), {
+            'activation': 'user',
+            'username': 'Bob',
+            'email': 'bob@bob.com',
+        })
 
         UserModel.objects.get_by_username('Bob')
         UserModel.objects.get_by_email('bob@bob.com')
@@ -355,9 +359,11 @@ class UserCreateTests(UserTestCase):
             },
         )
 
-        self.assertContains(response, 'admin')
-        self.assertContains(response, 'Bob')
-        self.assertContains(response, 'bob@bob.com')
+        self.assertEqual(response.json(), {
+            'activation': 'admin',
+            'username': 'Bob',
+            'email': 'bob@bob.com',
+        })
 
         UserModel.objects.get_by_username('Bob')
         UserModel.objects.get_by_email('bob@bob.com')
@@ -377,9 +383,11 @@ class UserCreateTests(UserTestCase):
             },
         )
 
-        self.assertContains(response, 'active')
-        self.assertContains(response, 'Bob')
-        self.assertContains(response, 'bob@bob.com')
+        self.assertEqual(response.json(), {
+            'activation': None,
+            'username': 'Bob',
+            'email': 'bob@bob.com',
+        })
 
         UserModel.objects.get_by_username('Bob')