From 311a5311bdf72b2755c028510ff9274df6de55cf Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Wed, 29 Oct 2025 13:37:48 +0500 Subject: [PATCH] add new api --- config/settings/base.py | 5 +- core/apps/accounts/serializers/auth.py | 37 +++++++------ .../accounts/serializers/forgot_password.py | 55 +++++++++++++++++++ core/apps/accounts/tasks/user.py | 4 +- core/apps/accounts/urls.py | 10 +++- core/apps/accounts/views/auth.py | 2 +- core/apps/accounts/views/forgot_password.py | 52 ++++++++++++++++++ 7 files changed, 142 insertions(+), 23 deletions(-) create mode 100644 core/apps/accounts/serializers/forgot_password.py create mode 100644 core/apps/accounts/views/forgot_password.py diff --git a/config/settings/base.py b/config/settings/base.py index a72eae2..17f2668 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -162,8 +162,9 @@ CORS_ALLOWED_ORIGINS = [ ] CSRF_TRUSTED_ORIGINS = [ - "http://trustme.felixits.uz" + "https://trustme.felixits.uz", + "http://localhost:8001", ] -SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', env.str("SWAGGER_PROTOCOL", 'https')) +SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', env.str("SWAGGER_PROTOCOL", env.str('','https'))) diff --git a/core/apps/accounts/serializers/auth.py b/core/apps/accounts/serializers/auth.py index 41863b5..e883587 100644 --- a/core/apps/accounts/serializers/auth.py +++ b/core/apps/accounts/serializers/auth.py @@ -1,29 +1,29 @@ -from django.db import transaction from django.contrib.auth import get_user_model +from django.db import transaction from django.utils import timezone - from rest_framework import serializers -from core.apps.accounts.tasks.user import create_and_send_sms_code from core.apps.accounts.enums.user import ROLE_CHOICES from core.apps.accounts.models.verification_code import VerificationCode +from core.apps.accounts.tasks.user import create_and_send_sms_code User = get_user_model() + class LoginSerializer(serializers.Serializer): phone = serializers.CharField() password = serializers.CharField() def validate(self, data): try: - user = User.objects.get(phone=data.get('phone')) + user = User.objects.get(phone=data.get("phone")) except User.DoesNotExist: - raise serializers.ValidationError({'detail': 'User not found'}) - if not user.check_password(data.get('password')): - raise serializers.ValidationError({'detail': 'User not found, password'}) - data['user'] = user + raise serializers.ValidationError({"detail": "User not found"}) + if not user.check_password(data.get("password")): + raise serializers.ValidationError({"detail": "User not found, password"}) + data["user"] = user return data - + class RegisterSerializer(serializers.Serializer): phone = serializers.CharField() @@ -39,7 +39,7 @@ class RegisterSerializer(serializers.Serializer): def validate_email(self, value): if User.objects.filter(email=value).exists(): - raise serializers.ValidationError("User exists with this email") + raise serializers.ValidationError("User exists with this email") return value @@ -48,17 +48,20 @@ class ConfirmUserSerializer(serializers.Serializer): code = serializers.IntegerField() def validate(self, data): - phone = data['phone'] - code = data['code'] + phone = data["phone"] + code = data["code"] confirmation = VerificationCode.objects.filter(code=code, phone=phone).first() if confirmation and confirmation.is_verify: raise serializers.ValidationError("Code is verified") - if confirmation: - if confirmation.is_expired or confirmation.expiration_time < timezone.now().time(): + if confirmation: + if ( + confirmation.is_expired + or confirmation.expiration_time < timezone.now().time() + ): raise serializers.ValidationError("Code is expired") - data['confirmation'] = confirmation + data["confirmation"] = confirmation return data - + class ChoiseRoleSerializer(serializers.Serializer): role = serializers.ChoiceField(choices=ROLE_CHOICES) @@ -67,4 +70,4 @@ class ChoiseRoleSerializer(serializers.Serializer): class UserPhoneListSerializer(serializers.ModelSerializer): class Meta: model = User - fields = ['id', 'phone'] \ No newline at end of file + fields = ["id", "phone"] diff --git a/core/apps/accounts/serializers/forgot_password.py b/core/apps/accounts/serializers/forgot_password.py new file mode 100644 index 0000000..8d364ec --- /dev/null +++ b/core/apps/accounts/serializers/forgot_password.py @@ -0,0 +1,55 @@ +from django.utils import timezone + +from rest_framework import serializers + +from core.apps.accounts.models import User, VerificationCode + + +class SendCodeSerializer(serializers.Serializer): + phone = serializers.CharField() + + def validate(self, data): + user = User.objects.filter(phone=data['phone']).first() + if not user: + raise serializers.ValidationError("User not found") + data['user'] = user + data['phone'] = user.phone + return data + + +class ConfirmPasswordSerializer(serializers.Serializer): + code = serializers.IntegerField() + phone = serializers.CharField() + + def validate(self, data): + phone = data["phone"] + code = data["code"] + confirmation = VerificationCode.objects.filter(code=code, phone=phone).first() + if confirmation and confirmation.is_verify: + raise serializers.ValidationError("Code is verified") + if confirmation: + if ( + confirmation.is_expired + or confirmation.expiration_time < timezone.now().time() + ): + raise serializers.ValidationError("Code is expired") + data["confirmation"] = confirmation + return data + + +class ResetPasswordSerializer(serializers.Serializer): + phone = serializers.CharField() + new_password = serializers.CharField() + + def validate(self, data): + user = User.objects.filter(phone=data['phone']).first() + if not user: + raise serializers + data['user'] = user + return data + + def save(self, **kwargs): + user = self.validated_data.get('user') + user.set_password(self.validated_data.get('new_password')) + user.save() + return super().save(**kwargs) \ No newline at end of file diff --git a/core/apps/accounts/tasks/user.py b/core/apps/accounts/tasks/user.py index 74c1bd1..d04f36c 100644 --- a/core/apps/accounts/tasks/user.py +++ b/core/apps/accounts/tasks/user.py @@ -11,11 +11,11 @@ from core.services.sms import send_sms_eskiz from core.services.sms_via_bot import send_sms_code @shared_task -def create_and_send_sms_code(phone): +def create_and_send_sms_code(phone, type): verification = VerificationCode.objects.create( code=''.join([str(random.randint(1, 100) % 10) for _ in range(4)]), phone=phone, expiration_time=timezone.now() + timedelta(minutes=2) ) # send_sms_eskiz(user.phone, code) - send_sms_code(verification.code, 'auth', verification.phone) + send_sms_code(verification.code, type, verification.phone) diff --git a/core/apps/accounts/urls.py b/core/apps/accounts/urls.py index 9d12cf7..ce5749b 100644 --- a/core/apps/accounts/urls.py +++ b/core/apps/accounts/urls.py @@ -1,6 +1,7 @@ from django.urls import path, include from core.apps.accounts.views.auth import LoginApiView, RegisterApiView, ConfirUserApiView, ChoiceUserRoleApiView, SearchUserPhoneApiView +from core.apps.accounts.views.forgot_password import ConfirmCodeApiView, SendCodeApiView, ResetPasswordApiView urlpatterns = [ path('auth/', include( @@ -15,5 +16,12 @@ urlpatterns = [ [ path('/search/', SearchUserPhoneApiView.as_view()), ] - )) + )), + path('forgot_password/', include( + [ + path('send_code/', SendCodeApiView.as_view()), + path('forgot_password/', ConfirmCodeApiView.as_view()), + path('reset_password/', ResetPasswordApiView.as_view()), + ] + )), ] \ No newline at end of file diff --git a/core/apps/accounts/views/auth.py b/core/apps/accounts/views/auth.py index 0b4c5ec..d9a6731 100644 --- a/core/apps/accounts/views/auth.py +++ b/core/apps/accounts/views/auth.py @@ -41,7 +41,7 @@ class RegisterApiView(generics.GenericAPIView): data['phone'], data['password'], data['first_name'], data['last_name'], data['email'], 300 ) - user_tasks.create_and_send_sms_code.delay(data['phone']) + user_tasks.create_and_send_sms_code.delay(data['phone'], type='auth') return success_message("code is send", 200) return error_message(serializer.errors, 400) diff --git a/core/apps/accounts/views/forgot_password.py b/core/apps/accounts/views/forgot_password.py new file mode 100644 index 0000000..d85b607 --- /dev/null +++ b/core/apps/accounts/views/forgot_password.py @@ -0,0 +1,52 @@ +from rest_framework import generics +from rest_framework.response import Response + +from core.apps.accounts.serializers import forgot_password as serializers +from core.apps.accounts.tasks.user import create_and_send_sms_code + +class SendCodeApiView(generics.GenericAPIView): + serializer_class = serializers.SendCodeSerializer + queryset = None + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(raise_exception=True): + data = serializer.data + create_and_send_sms_code.delay(data['phone'], 'forgot password') + return Response({"success": True, "message": "Kod yuborildi"}, status=201) + return Response({"success": False, "message": 'Kod yuborilmadi'}, status=400) + + +class ConfirmCodeApiView(generics.GenericAPIView): + serializer_class = serializers.ConfirmPasswordSerializer + queryset = None + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response( + { + 'success': True, + "message": "tasdiqlandi" + } + ) + return Response({'success': True, "message": serializer.errors}) + + +class ResetPasswordApiView(generics.GenericAPIView): + serializer_class = serializers.ResetPasswordSerializer + queryset = None + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response( + { + 'success': True, + "message": "ozgartirildi" + } + ) + return Response({'success': True, "message": serializer.errors}) + \ No newline at end of file