Login va Register to'girlandi

This commit is contained in:
2025-11-21 16:33:11 +05:00
parent 256e80cc23
commit 3da10c2a7f
9 changed files with 94 additions and 27 deletions

View File

@@ -29,6 +29,7 @@ class CustomUserAdmin(admin.UserAdmin, ModelAdmin):
"groups", "groups",
"user_permissions", "user_permissions",
"role", "role",
"validated_at",
), ),
}, },
), ),

View File

@@ -4,9 +4,16 @@ from django.utils.translation import gettext as _
from rest_framework import exceptions, serializers from rest_framework import exceptions, serializers
OTP_SIZE = env.int("OTP_SIZE", 4) OTP_SIZE = env.int("OTP_SIZE", 4)
class LoginSerializer(serializers.Serializer): class LoginSerializer(serializers.Serializer):
username = serializers.CharField(max_length=255) phone = serializers.CharField(max_length=255)
password = serializers.CharField(max_length=255)
def validate_phone(self, value):
user = get_user_model().objects.filter(phone=value, validated_at__isnull=False).exists()
if not user:
raise exceptions.ValidationError(_("Phone Not Found"))
return value
class RegisterSerializer(serializers.ModelSerializer): class RegisterSerializer(serializers.ModelSerializer):
@@ -20,13 +27,7 @@ class RegisterSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = get_user_model() model = get_user_model()
fields = ["first_name", "last_name", "phone", "password"] fields = ["phone"]
extra_kwargs = {
"first_name": {
"required": True,
},
"last_name": {"required": True},
}
class ConfirmSerializer(serializers.Serializer): class ConfirmSerializer(serializers.Serializer):

View File

@@ -4,7 +4,7 @@ Accounts app urls
from django.urls import path, include from django.urls import path, include
from rest_framework_simplejwt import views as jwt_views from rest_framework_simplejwt import views as jwt_views
from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView, LoginView
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
@@ -12,7 +12,7 @@ router.register("auth", RegisterView, basename="auth")
router.register("auth", ResetPasswordView, basename="reset-password") router.register("auth", ResetPasswordView, basename="reset-password")
router.register("auth", MeView, basename="me") router.register("auth", MeView, basename="me")
router.register("auth", ChangePasswordView, basename="change-password") router.register("auth", ChangePasswordView, basename="change-password")
router.register("login", LoginView, basename="login")
urlpatterns = [ urlpatterns = [
path("", include(router.urls)), path("", include(router.urls)),

View File

@@ -1 +1,2 @@
from .auth import * # noqa from .auth import * # noqa
from .login import * # noqa

View File

@@ -54,7 +54,7 @@ class RegisterView(BaseViewSetMixin, GenericViewSet, UserService):
data = ser.data data = ser.data
phone = data.get("phone") phone = data.get("phone")
# Create pending user # Create pending user
self.create_user(phone, data.get("first_name"), data.get("last_name"), data.get("password")) self.create_user(phone)
self.send_confirmation(phone) # Send confirmation code for sms eskiz.uz self.send_confirmation(phone) # Send confirmation code for sms eskiz.uz
return Response( return Response(
{"detail": _("Sms %(phone)s raqamiga yuborildi") % {"phone": phone}}, {"detail": _("Sms %(phone)s raqamiga yuborildi") % {"phone": phone}},

View File

@@ -0,0 +1,61 @@
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import AllowAny
from rest_framework.decorators import action
from django_core.mixins.base import BaseViewSetMixin
from rest_framework.viewsets import GenericViewSet
from core.services import UserService, SmsService
from ..serializers import LoginSerializer, ConfirmSerializer
from django.utils.translation import gettext_lazy as _
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth import get_user_model
from rest_framework.exceptions import PermissionDenied
from django_core import exceptions
@extend_schema(tags=["Login"])
class LoginView(BaseViewSetMixin, GenericViewSet, UserService):
permission_classes = [AllowAny]
def get_serializer_class(self):
match self.action:
case "send_code":
return LoginSerializer
case "send_confirm":
return ConfirmSerializer
case _:
return LoginSerializer
@action(detail=False, methods=["post"], url_path="send_code")
def send_code(self, request):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
data = ser.validated_data
phone = data.get('phone')
self.send_confirmation(phone)
return Response(
{"detail": _("Sms %(phone)s raqamiga yuborildi") % {"phone": phone}},
status=status.HTTP_202_ACCEPTED,
)
@action(detail=False, methods=["post"], url_path="send_confirm")
def send_confirm(self, request):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
data = ser.validated_data
phone = data.get("phone")
code = data.get("code")
try:
if SmsService.check_confirm(phone, code=code):
token = self.get_token(get_user_model().objects.filter(phone=phone).first())
return Response(
data={
"detail": _("Tasdiqlash ko'di qabul qilindi"),
"token": token,
},
status=status.HTTP_202_ACCEPTED,
)
except exceptions.SmsException as e:
raise PermissionDenied(e) # Response exception for APIException
except Exception as e:
raise PermissionDenied(e) # Api exception for APIException

View File

@@ -1,4 +1,4 @@
#type: ignore # type: ignore
import random import random
from datetime import datetime, timedelta from datetime import datetime, timedelta
@@ -22,16 +22,18 @@ class SmsService:
if env.bool("OTP_PROD", False): if env.bool("OTP_PROD", False):
code = "".join(str(random.randint(0, 9)) for _ in range(env.int("OTP_SIZE", 4))) code = "".join(str(random.randint(0, 9)) for _ in range(env.int("OTP_SIZE", 4)))
else: else:
code = env.int("OTP_DEFAULT", 1111) code = env.int("OTP_DEFAULT", 1111)
print("ishlayapti01")
sms_confirm, status = models.SmsConfirm.objects.get_or_create(phone=phone, defaults={"code": code}) sms_confirm, status = models.SmsConfirm.objects.get_or_create(phone=phone, defaults={"code": code})
print(sms_confirm)
print(status)
sms_confirm.sync_limits() sms_confirm.sync_limits()
print("ishlayapti")
if sms_confirm.resend_unlock_time is not None: if sms_confirm.resend_unlock_time is not None:
expired = sms_confirm.interval(sms_confirm.resend_unlock_time) expired = sms_confirm.interval(sms_confirm.resend_unlock_time)
exception = exceptions.SmsException(f"Resend blocked, try again in {expired}", expired=expired) exception = exceptions.SmsException(f"Resend blocked, try again in {expired}", expired=expired)
raise exception raise exception
print("ishlayapti2")
sms_confirm.code = code sms_confirm.code = code
sms_confirm.try_count = 0 sms_confirm.try_count = 0
@@ -41,9 +43,11 @@ class SmsService:
sms_confirm.resend_unlock_time = datetime.now() + timedelta( sms_confirm.resend_unlock_time = datetime.now() + timedelta(
seconds=models.SmsConfirm.SMS_EXPIRY_SECONDS seconds=models.SmsConfirm.SMS_EXPIRY_SECONDS
) # noqa ) # noqa
print("ishlayapti3")
sms_confirm.save() sms_confirm.save()
SendConfirm.delay(phone, code) SendConfirm.delay(phone, code)
print("ishlayapti4")
return True return True
@staticmethod @staticmethod

View File

@@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
from core.services import sms from core.services import sms
from django.contrib.auth import get_user_model, hashers from django.contrib.auth import get_user_model
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from django_core import exceptions from django_core import exceptions
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
@@ -17,20 +17,19 @@ class UserService(sms.SmsService):
"access": str(refresh.access_token), "access": str(refresh.access_token),
} }
def create_user(self, phone, first_name, last_name, password): def create_user(self, phone):
get_user_model().objects.update_or_create( user, created = get_user_model().objects.update_or_create(
phone=phone, phone=phone,
defaults={ defaults={
"phone": phone, "phone": phone,
"first_name": first_name,
"last_name": last_name,
"password": hashers.make_password(password),
}, },
) )
user.set_unusable_password()
user.save()
def send_confirmation(self, phone) -> bool: def send_confirmation(self, phone) -> bool:
try: try:
self.send_confirm(phone) sms.SmsService.send_confirm(phone)
return True return True
except exceptions.SmsException as e: except exceptions.SmsException as e:
raise PermissionDenied(_("Qayta sms yuborish uchun kuting: {}").format(e.kwargs.get("expired"))) raise PermissionDenied(_("Qayta sms yuborish uchun kuting: {}").format(e.kwargs.get("expired")))

View File

@@ -8,8 +8,6 @@ volumes:
services: services:
nginx: nginx:
env_file:
- .env
networks: networks:
- uzxarid - uzxarid
ports: ports:
@@ -23,6 +21,8 @@ services:
depends_on: depends_on:
- web - web
web: web:
env_file:
- .env
networks: networks:
- uzxarid - uzxarid
build: build: