complite auth api
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
from .celery import app as celery_app
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
"celery_app"
|
||||||
|
)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from config.env import env
|
from config.env import env
|
||||||
|
|
||||||
CELERY_BROKER_URL = env.str('REDIS_URL')
|
CELERY_BROKER_URL = 'redis://redis:6379/0'
|
||||||
CELERY_ACCEPT_CONTENT = ['json']
|
CELERY_ACCEPT_CONTENT = ['json']
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = 'json'
|
||||||
CELERY_TIMEZONE = settings.TIME_ZONE
|
CELERY_TIMEZONE = settings.TIME_ZONE
|
||||||
|
|||||||
11
config/conf/redis.py
Normal file
11
config/conf/redis.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from config.env import env
|
||||||
|
|
||||||
|
CACHES = {
|
||||||
|
"default": {
|
||||||
|
"BACKEND": "django_redis.cache.RedisCache",
|
||||||
|
"LOCATION": env("REDIS_URL"),
|
||||||
|
"OPTIONS": {
|
||||||
|
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,3 +140,4 @@ from config.conf.drf_spectacular import *
|
|||||||
from config.conf.rest_framework import *
|
from config.conf.rest_framework import *
|
||||||
from config.conf.simplejwt import *
|
from config.conf.simplejwt import *
|
||||||
from config.conf.celery import *
|
from config.conf.celery import *
|
||||||
|
from config.conf.redis import *
|
||||||
@@ -3,6 +3,9 @@ from django.contrib.auth import get_user_model
|
|||||||
|
|
||||||
from rest_framework import serializers
|
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
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
class LoginSerializer(serializers.Serializer):
|
class LoginSerializer(serializers.Serializer):
|
||||||
@@ -34,9 +37,57 @@ class RegisterSerializer(serializers.Serializer):
|
|||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
new_user = User.objects.create_user(
|
new_user = User.objects.create_user(
|
||||||
phone=validated_data.pop('phone'),
|
phone=validated_data.pop('phone'),
|
||||||
|
is_active=False
|
||||||
)
|
)
|
||||||
new_user.set_password(validated_data.pop('password'))
|
new_user.set_password(validated_data.pop('password'))
|
||||||
new_user.save()
|
new_user.save()
|
||||||
|
create_and_send_sms_code.delay(new_user.id)
|
||||||
return new_user
|
return new_user
|
||||||
|
|
||||||
|
|
||||||
|
class ConfirmUserSerializer(serializers.Serializer):
|
||||||
|
phone = serializers.CharField()
|
||||||
|
code = serializers.IntegerField()
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
try:
|
||||||
|
user = User.objects.get(phone=data.get('phone'))
|
||||||
|
except User.DoesNotExist:
|
||||||
|
raise serializers.ValidationError({"detail": "User not found"})
|
||||||
|
if user.is_active:
|
||||||
|
raise serializers.ValidationError({"detail": "User already activated"})
|
||||||
|
data['user'] = user
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class ChoiseRoleSerializer(serializers.Serializer):
|
||||||
|
phone = serializers.CharField()
|
||||||
|
role = serializers.ChoiceField(choices=ROLE_CHOICES)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
try:
|
||||||
|
user = User.objects.get(phone=data.get("phone"), is_active=False)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
raise serializers.ValidationError({"detail": "user not found"})
|
||||||
|
data['user'] = user
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class CompliteUserProfileSerializer(serializers.Serializer):
|
||||||
|
first_name = serializers.CharField()
|
||||||
|
last_name = serializers.CharField()
|
||||||
|
email = serializers.EmailField()
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
user = User.objects.filter(email=data.get('email')).first()
|
||||||
|
if user:
|
||||||
|
raise serializers.ValidationError({'detail': "User with this email already exists"})
|
||||||
|
return data
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
with transaction.atomic():
|
||||||
|
instance.first_name = validated_data.get('first_name')
|
||||||
|
instance.last_name = validated_data.get('last_name')
|
||||||
|
instance.email = validated_data.get('email')
|
||||||
|
instance.save()
|
||||||
|
return instance
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
from celery import shared_task
|
from celery import shared_task
|
||||||
|
|
||||||
from core.apps.accounts.models.verification_code import VerificationCode
|
from core.apps.accounts.models.verification_code import VerificationCode
|
||||||
|
from core.apps.accounts.models.user import User
|
||||||
from core.services.sms import send_sms_eskiz
|
from core.services.sms import send_sms_eskiz
|
||||||
|
|
||||||
@shared_task
|
@shared_task
|
||||||
def create_and_send_sms_code(user):
|
def create_and_send_sms_code(user):
|
||||||
|
user = User.objects.get(id=user)
|
||||||
code = user.generate_code()
|
code = user.generate_code()
|
||||||
send_sms_eskiz(user.phone, code)
|
send_sms_eskiz(user.phone, code)
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
|
||||||
from core.apps.accounts.views.auth import LoginApiView, RegisterApiView
|
from core.apps.accounts.views.auth import LoginApiView, RegisterApiView, ConfirUserApiView, ChoiceUserRoleApiView, CompliteUserProfileApiView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('auth/', include(
|
path('auth/', include(
|
||||||
[
|
[
|
||||||
path('login/', LoginApiView.as_view(), name='login'),
|
path('login/', LoginApiView.as_view(), name='login'),
|
||||||
path('register/', RegisterApiView.as_view(), name='login'),
|
path('register/', RegisterApiView.as_view(), name='login'),
|
||||||
|
path('confirm_user/', ConfirUserApiView.as_view(), name='confirm-user'),
|
||||||
|
path('choise_user_role/', ChoiceUserRoleApiView.as_view(), name='choise-user-role'),
|
||||||
|
path('complite_user_profile/<str:phone>/', CompliteUserProfileApiView.as_view(), name='complite-user-profile'),
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
]
|
]
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from rest_framework import generics, status, views
|
from rest_framework import generics, status, views
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
@@ -8,6 +9,7 @@ from rest_framework_simplejwt.tokens import RefreshToken
|
|||||||
from drf_spectacular.utils import extend_schema
|
from drf_spectacular.utils import extend_schema
|
||||||
|
|
||||||
from core.apps.accounts.serializers import auth as auth_serializer
|
from core.apps.accounts.serializers import auth as auth_serializer
|
||||||
|
from core.apps.accounts.models.verification_code import VerificationCode
|
||||||
|
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
@@ -30,3 +32,66 @@ class RegisterApiView(generics.CreateAPIView):
|
|||||||
serializer_class = auth_serializer.RegisterSerializer
|
serializer_class = auth_serializer.RegisterSerializer
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=['auth'])
|
||||||
|
class ConfirUserApiView(generics.GenericAPIView):
|
||||||
|
serializer_class = auth_serializer.ConfirmUserSerializer
|
||||||
|
queryset = User.objects.all()
|
||||||
|
permission_classes = []
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
serializer = self.serializer_class(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
user = serializer.validated_data.get('user')
|
||||||
|
code = serializer.validated_data.get('code')
|
||||||
|
code = VerificationCode.objects.filter(user=user, code=code).first()
|
||||||
|
if code:
|
||||||
|
if code.is_expired or code.expiration_time < timezone.now().time():
|
||||||
|
return Response({"success": True, "message": "code is expired"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
if code.is_verify:
|
||||||
|
return Response({"success": True, "message": "code is verified"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
user.save()
|
||||||
|
code.is_verify = True
|
||||||
|
code.is_expired = True
|
||||||
|
code.save()
|
||||||
|
return Response({"success": True, "message": "user activated"}, status=status.HTTP_202_ACCEPTED)
|
||||||
|
return Response({"success": False, "message": "code is wrong"}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
return Response({"success": False, "message": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=['auth'])
|
||||||
|
class ChoiceUserRoleApiView(generics.GenericAPIView):
|
||||||
|
serializer_class = auth_serializer.ChoiseRoleSerializer
|
||||||
|
queryset = User.objects.all()
|
||||||
|
permission_classes = []
|
||||||
|
|
||||||
|
@extend_schema(description="roles -> PP(physcal person) or LP(legal person)")
|
||||||
|
def post(self, request):
|
||||||
|
serializer = self.serializer_class(data=request.data)
|
||||||
|
if serializer.is_valid():
|
||||||
|
user = serializer.validated_data.get('user')
|
||||||
|
role = serializer.validated_data.get('role')
|
||||||
|
user.role = role
|
||||||
|
user.save()
|
||||||
|
return Response({'success': True, 'message': "role is selected"}, status=status.HTTP_200_OK)
|
||||||
|
return Response({'success': False, "message": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=['auth'])
|
||||||
|
class CompliteUserProfileApiView(generics.GenericAPIView):
|
||||||
|
serializer_class = auth_serializer.CompliteUserProfileSerializer
|
||||||
|
queryset = User.objects.all()
|
||||||
|
permission_classes = []
|
||||||
|
|
||||||
|
def put(self, request, phone):
|
||||||
|
user = User.objects.filter(phone=phone, is_active=True).first()
|
||||||
|
if user:
|
||||||
|
serializer = self.serializer_class(data=request.data, instance=user)
|
||||||
|
if serializer.is_valid():
|
||||||
|
serializer.save()
|
||||||
|
token = RefreshToken.for_user(user)
|
||||||
|
return Response({'access_token': str(token.access_token), "refresh_token": str(token), "role": user.role}, status=status.HTTP_200_OK)
|
||||||
|
return Response({'success': False, 'message': serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
return Response({'success': False, "message": "User not found"}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
|||||||
@@ -31,12 +31,30 @@ services:
|
|||||||
command: sh resources/scripts/entrypoint.sh
|
command: sh resources/scripts/entrypoint.sh
|
||||||
environment:
|
environment:
|
||||||
- PYTHONPYCACHEPREFIX=/var/cache/pycache
|
- PYTHONPYCACHEPREFIX=/var/cache/pycache
|
||||||
|
- REDIS_URL=redis://redis:6379/0
|
||||||
|
- CELERY_BROKER_URL=redis://redis:6379/0
|
||||||
|
- CELERY_BACKEND_URL=redis://redis:6379/0
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
- './:/code'
|
- './:/code'
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
- redis
|
- redis
|
||||||
|
|
||||||
|
celery:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: ./docker/Dockerfile.web
|
||||||
|
command: celery -A config worker --loglevel=info
|
||||||
|
environment:
|
||||||
|
- CELERY_BROKER_URL=redis://redis:6379/0
|
||||||
|
depends_on:
|
||||||
|
- redis
|
||||||
|
- web
|
||||||
|
networks:
|
||||||
|
- trustme
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: postgres:16
|
image: postgres:16
|
||||||
networks:
|
networks:
|
||||||
@@ -56,19 +74,7 @@ services:
|
|||||||
- trustme
|
- trustme
|
||||||
restart: always
|
restart: always
|
||||||
image: redis:latest
|
image: redis:latest
|
||||||
|
ports:
|
||||||
|
- 6379:6379
|
||||||
|
|
||||||
celery:
|
|
||||||
networks:
|
|
||||||
- trustme
|
|
||||||
build:
|
|
||||||
context: .
|
|
||||||
dockerfile: ./docker/Dockerfile.web
|
|
||||||
command: celery -A config worker --loglevel=info
|
|
||||||
volumes:
|
|
||||||
- .:/code
|
|
||||||
depends_on:
|
|
||||||
- redis
|
|
||||||
- web
|
|
||||||
environment:
|
|
||||||
CELERY_BROKER_URL: ${REDIS_URL}
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user