From eb7f044b3be06818d14132b39ae522562f98023b Mon Sep 17 00:00:00 2001 From: mortezaei Date: Thu, 25 Sep 2025 15:00:28 +0330 Subject: [PATCH] feat(account): add web user registration endpoint and serializer - Introduced a new endpoint for web user registration at 'web/register/'. - Created WebUserRegisterSerializer to handle user registration with email and password validation. - Enhanced UserVerifyView to support password handling during user creation and verification. --- apps/account/serializers/user_web.py | 29 ++++++++++++++++++ apps/account/urls.py | 1 + apps/account/views/user.py | 46 +++++++++++++++++++++++++--- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 apps/account/serializers/user_web.py diff --git a/apps/account/serializers/user_web.py b/apps/account/serializers/user_web.py new file mode 100644 index 0000000..dae3e3b --- /dev/null +++ b/apps/account/serializers/user_web.py @@ -0,0 +1,29 @@ +from rest_framework import serializers +from django.contrib.auth.password_validation import validate_password +from apps.account.models import User + + +class WebUserRegisterSerializer(serializers.ModelSerializer): + password = serializers.CharField(write_only=True, validators=[validate_password]) + fcm = serializers.CharField(required=False, allow_blank=True, allow_null=True) + email = serializers.EmailField() + + class Meta: + model = User + fields = ['id', 'fullname', 'email', 'password', 'fcm'] + extra_kwargs = { + 'fullname': {'required': True}, + 'email': {'required': True}, + } + + def validate_email(self, value): + normalized_email = User.objects.normalize_email(value) + if User.objects.filter(email=normalized_email).exists(): + raise serializers.ValidationError("This email is already registered.") + return normalized_email + + def create(self, validated_data): + user = super().create(validated_data) + return user + + diff --git a/apps/account/urls.py b/apps/account/urls.py index adbdbec..d378526 100644 --- a/apps/account/urls.py +++ b/apps/account/urls.py @@ -11,6 +11,7 @@ urlpatterns = [ # URL for user registration, accepts POST requests for creating new user instances. path('register/', views.UserRegisterView.as_view(), name='user-register'), + path('web/register/', views.WebUserRegisterView.as_view(), name='web-user-register'), path('verify/', views.UserVerifyView.as_view(), name='user-verify'), path('login/', views.UserLoginView.as_view(), name='user-login'), path('guest/', views.UserGuestView.as_view(), name='user-guest'), diff --git a/apps/account/views/user.py b/apps/account/views/user.py index 49874c7..68311c0 100644 --- a/apps/account/views/user.py +++ b/apps/account/views/user.py @@ -24,6 +24,7 @@ from rest_framework.exceptions import ValidationError from utils.exceptions import InvaliedCodeVrify, ExpiredCodeException, ServiceUnavailableException from apps.account.models import User from apps.account.serializers import UserRegisterSerializer, UserProfileSerializer, UserVerifySerializer, UserLoginSerializer, UserRecoverPasswordSerializer, UserResetPasswordSerializer, UserGuestSerializer,UserFCMSerializer +from apps.account.serializers.user_web import WebUserRegisterSerializer from utils.redis import RedisManager from utils.exceptions import AppAPIException from utils import send_email, is_valid_email @@ -126,7 +127,7 @@ class UserRegisterView(CreateAPIView): def post(self, request): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - data = serializer.data + data = serializer.validated_data code = RedisManager.generate_otp_code() logger.info(f"phone= {data['email']}") @@ -202,7 +203,7 @@ class UserVerifyView(CreateAPIView): device_id = kwargs.get('device_id') user = User.objects.filter(email=email).first() if user: - if kwargs['password']: + if kwargs.get('password'): user.is_active = True user.deletion_date = None if device_id: @@ -219,11 +220,13 @@ class UserVerifyView(CreateAPIView): if not user: user = User.objects.create(**kwargs) - user.set_password(kwargs['password']) + if kwargs.get('password'): + user.set_password(kwargs['password']) else: user.email = email user.fullname = kwargs['fullname'] - user.set_password(kwargs['password']) + if kwargs.get('password'): + user.set_password(kwargs['password']) if device_id: user.device_id = device_id user.last_login = timezone.now() @@ -232,6 +235,41 @@ class UserVerifyView(CreateAPIView): user.save() return user + + +class WebUserRegisterView(CreateAPIView): + permission_classes = [AllowAny] + serializer_class = WebUserRegisterSerializer + + @swagger_auto_schema( + operation_description="Web registration with password and confirmation", + request_body=WebUserRegisterSerializer, + ) + def post(self, request): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + data = serializer.validated_data + + code = RedisManager.generate_otp_code() + logger.info(f"phone= {data['email']}") + print(f'send {code}/{data["email"]}') + # Store all registration data including password in Redis + RedisManager().add_to_redis(code, **data) + try: + send_email([data['email']], code) + except Exception as exp: + print(f'-exp-register-->{exp}') + return Response( + data={ + "user": { + "id": data.get('id'), + "fullname": data.get('fullname'), + "email": data.get('email'), + }, + "message": "The otp code was sent to the user's email" + }, + status=status.HTTP_202_ACCEPTED, + ) class UserLoginView(CreateAPIView):