Tag Assignment - organization OTP

This commit is contained in:
2025-05-28 14:56:59 +03:30
parent 44d3960f94
commit c3c13ef21e
5 changed files with 149 additions and 3 deletions

View File

@@ -1,5 +1,5 @@
import typing import typing
from rest_framework.permissions import AllowAny
from apps.authentication.api.v1.serializers.jwt import CustomizedTokenObtainPairSerializer from apps.authentication.api.v1.serializers.jwt import CustomizedTokenObtainPairSerializer
from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework.decorators import action, permission_classes from rest_framework.decorators import action, permission_classes
@@ -26,7 +26,10 @@ from apps.authentication.models import (
from django.db import transaction from django.db import transaction
from rest_framework.response import Response from rest_framework.response import Response
from common.tools import CustomOperations from common.tools import CustomOperations
from django.core.cache import cache
from rest_framework import status from rest_framework import status
from common.sms import send_sms
import random
class CustomizedTokenObtainPairView(TokenObtainPairView): class CustomizedTokenObtainPairView(TokenObtainPairView):
@@ -138,6 +141,20 @@ class UserViewSet(ModelViewSet):
else: else:
return Response(serializer.errors, status=status.HTTP_403_FORBIDDEN) return Response(serializer.errors, status=status.HTTP_403_FORBIDDEN)
@action(
methods=['get'],
detail=False,
url_name='profile',
url_path='profile',
name='profile',
permission_classes=[AllowAny]
)
def profile(self, request):
serializer = authorize_view.UserRelationSerializer(
authorize_view.UserRelations.objects.get(user=request.user)
)
return Response(serializer.data, status.HTTP_200_OK)
class CityViewSet(ModelViewSet): class CityViewSet(ModelViewSet):
""" Crud operations for city model """ # """ Crud operations for city model """ #
@@ -195,3 +212,76 @@ class BankAccountViewSet(ModelViewSet):
""" Crud operations for bank account model """ # """ Crud operations for bank account model """ #
queryset = BankAccountInformation.objects.all() queryset = BankAccountInformation.objects.all()
serializer_class = BankAccountSerializer serializer_class = BankAccountSerializer
class GeneralOTPViewSet(ModelViewSet):
""" general OTP user authorization """
user_relations_queryset = authorize_view.UserRelations.objects.all()
organization_queryset = Organization.objects.all()
user_queryset = User.objects.all()
user_serializer = UserSerializer
organization_serializer = OrganizationSerializer
user_relations_serializer = authorize_view.UserRelationSerializer
@classmethod
def get_user_mobile(cls, data: dict) -> typing.Any:
""" find user mobile in multiple modes like from organization """
if data['get_mobile_type'] == 'organization':
# get user mobile by his/her organization
user_mobile = cls.user_relations_queryset.filter(
organization_id=int(data['object_id']),
role__role_name='Management').first().user.mobile
return user_mobile
if data['get_mobile_type'] == 'general':
return data['mobile']
@action(
methods=['post'],
detail=False,
url_path='send_otp',
url_name='send_otp',
name='send_otp'
)
@transaction.atomic
def send_otp(self, request):
"""
This module is for sending otp in whole project and different parts
like send otp code to user by organization or by general user mobile
"""
mobile = self.get_user_mobile(
data=request.data
)
# generate random integer and message for otp code
random_number = random.randint(10000, 99999)
message = f'کد احراز شما : {random_number}' # noqa
# caching code
if 'timeout' in request.data.keys():
cache.set(f"{random_number}", str(random_number), timeout=60 * int(request.data['timeout']))
else:
cache.set(f"{random_number}", str(random_number), timeout=60 * 3)
sms_response = send_sms(mobile=mobile, message=message)
return Response(status=status.HTTP_200_OK)
@action(
methods=['post'],
detail=False,
url_name='check_otp',
url_path='check_otp',
name='check_otp'
)
def check_otp(self, request):
""" Check sent otp code to user """
entered_code = request.data['code']
cached_code = cache.get(entered_code)
if entered_code == cached_code:
return Response(status=status.HTTP_200_OK)
return Response(status=status.HTTP_403_FORBIDDEN)

View File

@@ -12,7 +12,8 @@ from .api import (
CityViewSet, CityViewSet,
ProvinceViewSet, ProvinceViewSet,
OrganizationViewSet, OrganizationViewSet,
OrganizationTypeViewSet OrganizationTypeViewSet,
GeneralOTPViewSet
) )
router = DefaultRouter() router = DefaultRouter()
@@ -21,6 +22,7 @@ router.register(r'city', CityViewSet, basename='city')
router.register(r'province', ProvinceViewSet, basename='province') router.register(r'province', ProvinceViewSet, basename='province')
router.register(r'organization', OrganizationViewSet, basename='organization') router.register(r'organization', OrganizationViewSet, basename='organization')
router.register(r'organization-type', OrganizationTypeViewSet, basename='organization_type') router.register(r'organization-type', OrganizationTypeViewSet, basename='organization_type')
router.register(r'otp', GeneralOTPViewSet, basename='otp')
urlpatterns = [ urlpatterns = [
path('login/', CustomizedTokenObtainPairView.as_view(), name='token_obtain_pair'), path('login/', CustomizedTokenObtainPairView.as_view(), name='token_obtain_pair'),

View File

@@ -6,6 +6,7 @@ from apps.core.models import BaseModel
from crum import get_current_user from crum import get_current_user
from django.db import models from django.db import models
from jdatetime import datetime from jdatetime import datetime
import random
class Tag(BaseModel): class Tag(BaseModel):
@@ -85,6 +86,7 @@ class TagAssignment(BaseModel):
)[3] + str( )[3] + str(
datetime.now().month datetime.now().month
) )
self.serial_random_part = random.randint(1000, 9999)
if not self.serial: if not self.serial:
self.serial = f"" \ self.serial = f"" \
f"{self.serial_sender_part}" \ f"{self.serial_sender_part}" \

View File

@@ -12,6 +12,7 @@ from django.db import transaction
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from apps.tag import permissions as tag_permissions from apps.tag import permissions as tag_permissions
from apps.authorization import models as authorize_models from apps.authorization import models as authorize_models
from apps.authentication.api.v1.api import GeneralOTPViewSet
from apps.tag.tools import tag_code_serial_scanning from apps.tag.tools import tag_code_serial_scanning
from apps.tag import exceptions as tag_exceptions from apps.tag import exceptions as tag_exceptions
from common.helpers import detect_file_extension from common.helpers import detect_file_extension
@@ -110,6 +111,7 @@ class TagViewSet(viewsets.ModelViewSet):
class TagAssignmentViewSet(viewsets.ModelViewSet): class TagAssignmentViewSet(viewsets.ModelViewSet):
""" assignment of tags """ """ assignment of tags """
queryset = tag_models.TagAssignment.objects.all() queryset = tag_models.TagAssignment.objects.all()
user_relations_queryset = authorize_models.UserRelations.objects.all()
serializer_class = TagAssignmentSerializer serializer_class = TagAssignmentSerializer
@transaction.atomic @transaction.atomic
@@ -120,6 +122,12 @@ class TagAssignmentViewSet(viewsets.ModelViewSet):
if serializer.is_valid(raise_exception=True): if serializer.is_valid(raise_exception=True):
tag_assignment = serializer.save() tag_assignment = serializer.save()
# get assigner organization code
assigner_organization_code = self.user_relations_queryset.get(
user=request.user).organization.type.code # noqa
tag_assignment.serial_sender_part = assigner_organization_code # noqa
tag_assignment.save()
# get tags by species number like: 2 tags of species code 4 # get tags by species number like: 2 tags of species code 4
tags_to_allocate = request.data['allocated_tags'] tags_to_allocate = request.data['allocated_tags']
for tag in tags_to_allocate: for tag in tags_to_allocate:
@@ -140,7 +148,7 @@ class TagAssignmentViewSet(viewsets.ModelViewSet):
status='W', status='W',
species_code=tag['species_code'] species_code=tag['species_code']
).save() # noqa ).save() # noqa
tag_to_allocate.status = 'W' # change tag status from free to waiting tag_to_allocate.status = ' ' # change tag status from free to waiting
tag_to_allocate.save() tag_to_allocate.save()
return Response(serializer.data, status.HTTP_201_CREATED) return Response(serializer.data, status.HTTP_201_CREATED)
@@ -207,6 +215,29 @@ class TagAssignmentViewSet(viewsets.ModelViewSet):
allocated_tag.delete() allocated_tag.delete()
return Response(status.HTTP_200_OK) return Response(status.HTTP_200_OK)
@action(
methods=['post'],
detail=False,
url_path='otp_verification',
url_name='otp_verification',
name='otp_verification'
)
def otp_verification(self, request):
""" OTP verification for organization """
if request.data['type'] == 'send':
otp_response = GeneralOTPViewSet().send_otp(request)
if otp_response.status_code == 200:
return Response(otp_response.status_code, status=status.HTTP_200_OK)
else:
return Response(otp_response.status_code, status=status.HTTP_403_FORBIDDEN)
if request.data['type'] == 'check':
check_response = GeneralOTPViewSet().check_otp(request)
if check_response.status_code == 200:
return Response(check_response.status_code, status=status.HTTP_200_OK)
else:
return Response(check_response.status_code, status=status.HTTP_403_FORBIDDEN)
@action( @action(
methods=['put'], methods=['put'],
detail=True, detail=True,

21
common/sms.py Normal file
View File

@@ -0,0 +1,21 @@
import typing
import requests
USERNAME_SMS = 'hamedan' # noqa # Sahand Sms username
PASSWORD_SMS = 'hamedan12345' # noqa # Sahand sms password
def send_sms(mobile: str = None, message: str = None) -> typing.Any:
""" send sms to a number with custom message """
url = f"http://webservice.sahandsms.com/newsmswebservice.asmx/SendPostUrl?" \
f"username={USERNAME_SMS}&password={PASSWORD_SMS}" \
f"&from=30002501&to={mobile}&message={message}"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.request('GET', url, headers=headers)
print(response)
if __name__ == "__main__":
send_sms(mobile="09389657326", message="12345")