gault-millau/apps/utils/views.py

197 lines
8.6 KiB
Python

from collections import namedtuple
from django.conf import settings
from rest_framework import generics
from rest_framework import status
from rest_framework.response import Response
# JWT
# Login base view mixin
class JWTGenericViewMixin(generics.GenericAPIView):
"""JWT view mixin"""
ACCESS_TOKEN_HTTP_ONLY = False
ACCESS_TOKEN_SECURE = False
REFRESH_TOKEN_HTTP_ONLY = False
REFRESH_TOKEN_SECURE = False
LOCALE_HTTP_ONLY = False
LOCALE_SECURE = False
COUNTRY_CODE_HTTP_ONLY = False
COUNTRY_CODE_SECURE = False
COOKIE = namedtuple('COOKIE', ['key', 'value', 'http_only', 'secure', 'max_age'])
def _put_data_in_cookies(self,
access_token: str = None,
refresh_token: str = None,
permanent: bool = None):
"""
cookies it is list that contain namedtuples
cookies would contain key, value and secure parameters.
"""
COOKIES = []
if hasattr(self.request, 'locale'):
COOKIES.append(self.COOKIE(key='locale',
value=self.request.locale,
http_only=self.ACCESS_TOKEN_HTTP_ONLY,
secure=self.LOCALE_SECURE,
max_age=settings.COOKIES_MAX_AGE if permanent else None))
if hasattr(self.request, 'country_code'):
COOKIES.append(self.COOKIE(key='country_code',
value=self.request.country_code,
http_only=self.COUNTRY_CODE_HTTP_ONLY,
secure=self.COUNTRY_CODE_SECURE,
max_age=settings.COOKIES_MAX_AGE if permanent else None))
if access_token:
COOKIES.append(self.COOKIE(key='access_token',
value=access_token,
http_only=self.ACCESS_TOKEN_HTTP_ONLY,
secure=self.ACCESS_TOKEN_SECURE,
max_age=settings.COOKIES_MAX_AGE if permanent else None))
if refresh_token:
COOKIES.append(self.COOKIE(key='refresh_token',
value=refresh_token,
http_only=self.REFRESH_TOKEN_HTTP_ONLY,
secure=self.REFRESH_TOKEN_SECURE,
max_age=settings.COOKIES_MAX_AGE if permanent else None))
return COOKIES
def _put_cookies_in_response(self, cookies: list, response: Response):
"""Update COOKIES in response from namedtuple"""
for cookie in cookies:
# todo: remove config for develop
from os import environ
configuration = environ.get('SETTINGS_CONFIGURATION', None)
if configuration == 'development':
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure,
httponly=cookie.http_only,
max_age=cookie.max_age,
domain='.id-east.ru')
else:
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure,
httponly=cookie.http_only,
max_age=cookie.max_age,)
return response
def _get_tokens_from_cookies(self, request, cookies: dict = None):
"""Get user tokens from cookies and put in namedtuple"""
_cookies = request.COOKIES or cookies
return [self.COOKIE(key='access_token',
value=_cookies.get('access_token'),
http_only=self.ACCESS_TOKEN_HTTP_ONLY,
secure=self.ACCESS_TOKEN_SECURE,
max_age=_cookies.get('max_age')),
self.COOKIE(key='refresh_token',
value=_cookies.get('refresh_token'),
http_only=self.REFRESH_TOKEN_HTTP_ONLY,
secure=self.REFRESH_TOKEN_SECURE,
max_age=_cookies.get('max_age'))]
class JWTListAPIView(JWTGenericViewMixin, generics.ListAPIView):
"""
Concrete view for creating a model instance.
"""
def get(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
response = self.get_paginated_response(serializer.data)
else:
serializer = self.get_serializer(queryset, many=True)
response = Response(serializer.data)
access_token, refresh_token = self._get_tokens_from_cookies(request)
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(access_token=access_token.value,
refresh_token=refresh_token.value),
response=response)
class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView):
"""
Concrete view for creating a model instance.
"""
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
response = Response(serializer.data, status=status.HTTP_201_CREATED)
access_token, refresh_token = self._get_tokens_from_cookies(request)
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(access_token=access_token.value,
refresh_token=refresh_token.value),
response=response)
class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView):
"""
Concrete view for retrieving a model instance.
"""
def get(self, request, *args, **kwargs):
"""Implement GET method"""
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
response = self.get_paginated_response(serializer.data)
else:
serializer = self.get_serializer(queryset, many=True)
response = Response(serializer.data, status.HTTP_200_OK)
access_token, refresh_token = self._get_tokens_from_cookies(request)
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(access_token=access_token,
refresh_token=refresh_token),
response=response)
class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView):
"""
Concrete view for deleting a model instance.
"""
def delete(self, request, *args, **kwargs):
instance = self.get_object()
instance.delete()
response = Response(status=status.HTTP_204_NO_CONTENT)
access_token, refresh_token = self._get_tokens_from_cookies(request)
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(access_token=access_token,
refresh_token=refresh_token),
response=response)
class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView):
"""
Concrete view for updating a model instance.
"""
def put(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
serializer.save()
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
response = Response(serializer.data)
access_token, refresh_token = self._get_tokens_from_cookies(request)
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(access_token=access_token,
refresh_token=refresh_token),
response=response)
def patch(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.put(request, *args, **kwargs)