diff --git a/apps/authentication/api/v1/api.py b/apps/authentication/api/v1/api.py index 640d76b..01bc80f 100644 --- a/apps/authentication/api/v1/api.py +++ b/apps/authentication/api/v1/api.py @@ -1,7 +1,6 @@ import typing from rest_framework.permissions import AllowAny from apps.authentication.api.v1.serializers.jwt import CustomizedTokenObtainPairSerializer -from rest_framework_simplejwt.authentication import JWTAuthentication from rest_framework.decorators import action, permission_classes from apps.authentication import permissions as auth_permissions from apps.authentication.api.v1.serializers.serializer import ( @@ -14,6 +13,8 @@ from apps.authentication.api.v1.serializers.serializer import ( ) from rest_framework_simplejwt.views import TokenObtainPairView from apps.authorization.api.v1 import api as authorize_view +from rest_framework.permissions import IsAuthenticated +from apps.authentication.tools import get_token_jti from rest_framework.viewsets import ModelViewSet from apps.authentication.models import ( User, @@ -24,16 +25,14 @@ from apps.authentication.models import ( BankAccountInformation, BlacklistedAccessToken ) -from django.db import transaction from rest_framework.response import Response from common.tools import CustomOperations +from rest_framework.views import APIView from django.core.cache import cache from rest_framework import status +from django.db import transaction from common.sms import send_sms import random -from rest_framework.views import APIView -from rest_framework.permissions import IsAuthenticated -from apps.authentication.tools import get_token_jti class CustomizedTokenObtainPairView(TokenObtainPairView): @@ -41,24 +40,6 @@ class CustomizedTokenObtainPairView(TokenObtainPairView): serializer_class = CustomizedTokenObtainPairSerializer -class LogoutView(APIView): - permission_classes = [IsAuthenticated] - - def post(self, request): - token_str = request.auth # access token from header - jti, user_id = get_token_jti(str(token_str)) - - if not jti: - return Response({'detail': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) - - BlacklistedAccessToken.objects.get_or_create(jti=jti, defaults={ - 'token': token_str, - 'user_id': user_id, - }) - - return Response({'detail': 'Access token blacklisted.'}, status=status.HTTP_200_OK) - - class UserViewSet(ModelViewSet): """ Crud operations for user model """ queryset = User.objects.all() @@ -307,3 +288,23 @@ class GeneralOTPViewSet(ModelViewSet): if entered_code == cached_code: return Response(status=status.HTTP_200_OK) return Response(status=status.HTTP_403_FORBIDDEN) + + +class LogoutView(APIView): + """ logout user """ + + permission_classes = [IsAuthenticated] + + def post(self, request): # noqa + token_str = request.auth # access token from header + jti, user_id = get_token_jti(str(token_str)) + + if not jti: + return Response({'detail': 'Invalid token'}, status=status.HTTP_400_BAD_REQUEST) + + BlacklistedAccessToken.objects.get_or_create(jti=jti, defaults={ + 'token': token_str, + 'user_id': user_id, + }) + + return Response({'detail': 'Access token blacklisted.'}, status=status.HTTP_200_OK) diff --git a/apps/authentication/exceptions.py b/apps/authentication/exceptions.py index 76d8a87..8fe7a57 100644 --- a/apps/authentication/exceptions.py +++ b/apps/authentication/exceptions.py @@ -4,6 +4,8 @@ from rest_framework import status class TokenBlackListedException(APIException): + """ exception for blocked access tokens """ + status_code = status.HTTP_401_UNAUTHORIZED default_detail = _('unauthorized') default_code = 'unauthorized' diff --git a/apps/authentication/middlewares.py b/apps/authentication/middlewares.py index f8dfbff..89ebdd0 100644 --- a/apps/authentication/middlewares.py +++ b/apps/authentication/middlewares.py @@ -1,14 +1,11 @@ -from django.utils.deprecation import MiddlewareMixin from .models import BlacklistedAccessToken from apps.authentication.tools import get_token_jti -from rest_framework.exceptions import AuthenticationFailed -from apps.authentication.exceptions import TokenBlackListedException -from rest_framework.response import Response from django.http import JsonResponse -from rest_framework import status class BlockedTokenMiddleware: + """ Check blocked access token authentication """ + def __init__(self, get_response): self.get_response = get_response diff --git a/apps/authentication/tools.py b/apps/authentication/tools.py index f615271..33ab824 100644 --- a/apps/authentication/tools.py +++ b/apps/authentication/tools.py @@ -2,6 +2,8 @@ from rest_framework_simplejwt.tokens import AccessToken def get_token_jti(token_str): + """ get generated jwt id (jti) for every token """ + try: token = AccessToken(token_str) return token['jti'], token['user_id'] diff --git a/apps/authorization/api/v1/serializers.py b/apps/authorization/api/v1/serializers.py index 03b6e58..f0b6bfd 100644 --- a/apps/authorization/api/v1/serializers.py +++ b/apps/authorization/api/v1/serializers.py @@ -13,6 +13,8 @@ import itertools class PageSerializer(serializers.ModelSerializer): + """ Serialize every front-end page """ + class Meta: model = Page fields = [ @@ -22,6 +24,8 @@ class PageSerializer(serializers.ModelSerializer): class PermissionSerializer(serializers.ModelSerializer): + """ Serialize permissions """ + class Meta: model = Permissions fields = [ @@ -34,17 +38,19 @@ class PermissionSerializer(serializers.ModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) - representation['name'] = 'Hello' + representation['page'] = instance.page.name return representation @classmethod def permissions_structure_output(cls, permissions: list) -> typing.Any: """ set a structure for permissions """ - structure = {} - for permission in permissions: - if permission.page.name not in structure.keys(): - structure.update( + structure = [] + pages_list = [] + for counter, permission in enumerate(permissions): + if permission.page.name not in pages_list: + pages_list.append(permission.page.name) + structure.append( {f'{permission.page.name}': itertools.chain(*list( permission.page.permission_page.all().values_list('name'))) }) @@ -52,6 +58,8 @@ class PermissionSerializer(serializers.ModelSerializer): class RoleSerializer(serializers.ModelSerializer): + """ Serialize roles of user """ + class Meta: model = Role fields = [ @@ -78,6 +86,8 @@ class RoleSerializer(serializers.ModelSerializer): class UserRelationSerializer(serializers.ModelSerializer): + """ Serialize relations of user like: organizations, roles, permissions """ + class Meta: model = UserRelations fields = [ @@ -108,11 +118,9 @@ class UserRelationSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): """ update user relation object """ if validated_data.get('role'): - instance.role = Role.objects.get(id=validated_data.get('role', instance.role)) + instance.role = validated_data.get('role', instance.role.id) if validated_data.get('organization'): - instance.organization = Organization.objects.get( - id=validated_data.get('organization', instance.organization) - ) + instance.organization = validated_data.get('organization', instance.organization.id) instance.save() instance.permissions.clear() instance.permissions.add(*(validated_data.get('permissions', instance.permissions)))