version 0.0.11: added new model and CRUD endpoints to them; refactored auth app

This commit is contained in:
Anatoly 2019-08-15 11:59:10 +03:00
parent 033674c5b2
commit d5a14ef8c2
21 changed files with 438 additions and 157 deletions

View File

@ -40,12 +40,12 @@ class UserQuerySet(models.QuerySet):
"""Filter only active users."""
return self.filter(is_active=switcher)
def by_access_token(self, token):
def by_oauth2_access_token(self, token):
"""Find user by access token"""
return self.filter(oauth2_provider_accesstoken__token=token,
oauth2_provider_accesstoken__expires__gt=timezone.now())
def by_refresh_token(self, token):
def by_oauth2_refresh_token(self, token):
"""Find user by access token"""
return self.filter(oauth2_provider_refreshtoken__token=token,
oauth2_provider_refreshtoken__expires__gt=timezone.now())

View File

@ -1,3 +1,7 @@
from django.contrib import admin
from authorization import models
# Register your models here.
@admin.register(models.BlacklistedAccessToken)
class BlacklistedAccessTokenAdmin(admin.ModelAdmin):
"""Admin for BlackListedAccessToken"""

View File

@ -24,7 +24,7 @@ class BaseAuthSerializerMixin(serializers.Serializer):
source = serializers.ChoiceField(choices=Application.SOURCES)
class JWTBaseMixin(serializers.Serializer):
class JWTBaseSerializerMixin(serializers.Serializer):
"""
Mixin for JWT authentication.
Uses in serializers when need give in response access and refresh token
@ -43,8 +43,8 @@ class JWTBaseMixin(serializers.Serializer):
def to_representation(self, instance):
"""Override to_representation method"""
token = self.get_token()
setattr(instance, 'refresh_token', str(token))
setattr(instance, 'access_token', str(token.access_token))
setattr(instance, 'refresh_token', str(token))
return super().to_representation(instance)
@ -60,7 +60,7 @@ class ClassicAuthSerializerMixin(BaseAuthSerializerMixin):
# Serializers
class SignupSerializer(JWTBaseMixin, serializers.ModelSerializer):
class SignupSerializer(JWTBaseSerializerMixin, serializers.ModelSerializer):
"""Signup serializer serializer mixin"""
# REQUEST
username = serializers.CharField(
@ -100,7 +100,7 @@ class SignupSerializer(JWTBaseMixin, serializers.ModelSerializer):
return obj
class LoginByUsernameOrEmailSerializer(JWTBaseMixin, serializers.ModelSerializer):
class LoginByUsernameOrEmailSerializer(JWTBaseSerializerMixin, serializers.ModelSerializer):
"""Serializer for login user"""
username_or_email = serializers.CharField(write_only=True)
password = serializers.CharField(write_only=True)
@ -164,22 +164,28 @@ class LogoutSerializer(serializers.ModelSerializer):
class Meta:
model = BlacklistedAccessToken
fields = '__all__'
read_only_fields = [
'jti', 'token', 'user'
]
fields = (
'user',
'token',
'jti'
)
read_only_fields = (
'user',
'token',
'jti'
)
def create(self, validated_data, *args, **kwargs):
"""Override create method"""
def validate(self, attrs):
"""Override validated data"""
request = self.context.get('request')
token = request._request.headers.get('Authorization')\
token = request._request.headers.get('Authorization') \
.split(' ')[::-1][0]
access_token = tokens.AccessToken(token)
# Prepare validated data
validated_data['user'] = request.user
validated_data['token'] = access_token.token
validated_data['jti'] = access_token.payload.get('jti')
return super().create(validated_data)
attrs['user'] = request.user
attrs['token'] = access_token.token
attrs['jti'] = access_token.payload.get('jti')
return attrs
# OAuth

View File

@ -1,6 +1,5 @@
"""Common views for application Account"""
import json
from collections import namedtuple
from braces.views import CsrfExemptMixin
from django.conf import settings
@ -20,12 +19,36 @@ from account.models import User
from authorization.models import Application
from authorization.serializers import common as serializers
from utils import exceptions as utils_exceptions
# JWT
from utils.views import JWTViewMixin
# Mixins
# JWTAuthView mixin
class JWTAuthViewMixin(JWTViewMixin):
"""Mixin for authentication views"""
def post(self, request, *args, **kwargs):
"""Implement POST method"""
_locale = request.COOKIES.get('locale')
try:
locale = self._check_locale(locale=_locale)
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
response = Response(serializer.data, status=status.HTTP_200_OK)
access_token = serializer.data.get('access_token')
refresh_token = serializer.data.get('refresh_token')
except utils_exceptions.LocaleNotExisted:
raise utils_exceptions.LocaleNotExisted(locale=_locale)
else:
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(locale=locale,
access_token=access_token,
refresh_token=refresh_token),
response=response)
# OAuth2
class BaseOAuth2ViewMixin(generics.GenericAPIView):
"""BaseMixin for classic auth views"""
@ -74,53 +97,8 @@ class OAuth2ViewMixin(CsrfExemptMixin, OAuthLibMixin, BaseOAuth2ViewMixin):
raise utils_exceptions.ServiceError()
# JWT
# Login base view mixin
class JWTViewMixin(generics.GenericAPIView):
"""JWT view mixin"""
def _handle_cookies(self, request, access_token, refresh_token):
"""
CHECK locale in cookies and PUT access and refresh tokens there.
cookies it is list that contain namedtuples
cookies would contain key, value and secure parameters.
"""
cookies = list()
COOKIE = namedtuple('COOKIE', ['key', 'value', 'secure'])
if 'locale' in request.COOKIES:
# Write locale in cookie
_locale = COOKIE(key='locale', value=request.COOKIES.get('locale'), secure=False)
cookies.append(_locale)
# Write to cookie access and refresh token with secure flag
_access_token = COOKIE(key='access_token', value=access_token, secure=True)
_refresh_token = COOKIE(key='refresh_token', value=refresh_token, secure=True)
cookies.extend([_access_token, _refresh_token])
return cookies
def _put_cookies_in_response(self, cookies: list, response: Response):
"""Update COOKIES in response obj"""
for cookie in cookies:
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure)
return response
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
response = Response(serializer.data, status=status.HTTP_200_OK)
access_token = serializer.data.get('access_token')
refresh_token = serializer.data.get('access_token')
return self._put_cookies_in_response(
cookies=self._handle_cookies(request, access_token, refresh_token),
response=response)
# Serializers
# Sign in via Facebook
class OAuth2SignUpView(OAuth2ViewMixin, JWTViewMixin):
class OAuth2SignUpView(OAuth2ViewMixin, JWTAuthViewMixin):
"""
Implements an endpoint to convert a provider token to an access token
@ -135,96 +113,112 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTViewMixin):
serializer_class = serializers.OAuth2Serialzier
def get_jwt_token(self, user: User,
access_token: str,
refresh_token: str):
oauth2_access_token: str,
oauth2_refresh_token: str):
"""Get JWT token"""
token = jwt_tokens.RefreshToken.for_user(user)
# Adding additional information about user to payload
token['user'] = user.get_user_info()
# Adding OAuth2 tokens to payloads
token['oauth2_fb'] = {'access_token': access_token,
'refresh_token': refresh_token}
token['oauth2_fb'] = {'access_token': oauth2_access_token,
'refresh_token': oauth2_refresh_token}
return token
def post(self, request, *args, **kwargs):
# Preparing request data
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
request_data = self.prepare_request_data(serializer.validated_data)
request_data.update({
'grant_type': settings.OAUTH2_SOCIAL_AUTH_GRANT_TYPE,
'backend': settings.OAUTH2_SOCIAL_AUTH_BACKEND_NAME
})
# Use the rest framework `.data` to fake the post body of the django request.
request._request.POST = request._request.POST.copy()
for key, value in request_data.items():
request._request.POST[key] = value
_locale = request.COOKIES.get('locale')
try:
locale = self._check_locale(locale=_locale)
# Preparing request data
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
request_data = self.prepare_request_data(serializer.validated_data)
request_data.update({
'grant_type': settings.OAUTH2_SOCIAL_AUTH_GRANT_TYPE,
'backend': settings.OAUTH2_SOCIAL_AUTH_BACKEND_NAME
})
# Use the rest framework `.data` to fake the post body of the django request.
request._request.POST = request._request.POST.copy()
for key, value in request_data.items():
request._request.POST[key] = value
url, headers, body, oauth2_status = self.create_token_response(request._request)
body = json.loads(body)
# Get JWT token
if oauth2_status != status.HTTP_200_OK:
raise ValueError('status isn\'t 200')
user = User.objects.by_access_token(token=body.get('access_token'))\
.first()
token = self.get_jwt_token(user=user,
access_token=body.get('access_token'),
refresh_token=body.get('refresh_token'))
refresh_token = str(token)
access_token = str(token.access_token)
response = Response(data={'refresh_token': refresh_token,
'access_token': access_token},
status=status.HTTP_200_OK)
return self._put_cookies_in_response(
cookies=self._handle_cookies(request, access_token, refresh_token),
response=response)
# OAuth2 authentication process
url, headers, body, oauth2_status = self.create_token_response(request._request)
body = json.loads(body)
# Get JWT token
if oauth2_status != status.HTTP_200_OK:
raise ValueError('status isn\'t 200')
# Get authenticated user
user = User.objects.by_oauth2_access_token(token=body.get('access_token'))\
.first()
# Create JWT token and put oauth2 token (access, refresh tokens) in payload
token = self.get_jwt_token(user=user,
oauth2_access_token=body.get('access_token'),
oauth2_refresh_token=body.get('refresh_token'))
access_token = str(token.access_token)
refresh_token = str(token)
response = Response(data={'access_token': access_token,
'refresh_token': refresh_token},
status=status.HTTP_200_OK)
except utils_exceptions.LocaleNotExisted:
raise utils_exceptions.LocaleNotExisted(locale=_locale)
else:
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(locale=locale,
access_token=access_token,
refresh_token=refresh_token),
response=response)
# JWT
# Sign in via username and password
class SignUpView(JWTViewMixin):
class SignUpView(JWTAuthViewMixin):
"""View for classic signup"""
permission_classes = (permissions.AllowAny, )
serializer_class = serializers.SignupSerializer
def post(self, request, *args, **kwargs):
"""Implement POST-method"""
_locale = request.COOKIES.get('locale')
try:
locale = self._check_locale(locale=_locale)
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 = serializer.data.get('access_token')
refresh_token = serializer.data.get('access_token')
return self._put_cookies_in_response(
cookies=self._handle_cookies(request, access_token, refresh_token),
response=response)
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 = serializer.data.get('access_token')
refresh_token = serializer.data.get('refresh_token')
except utils_exceptions.LocaleNotExisted:
raise utils_exceptions.LocaleNotExisted(locale=_locale)
else:
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(
locale=locale,
access_token=access_token,
refresh_token=refresh_token),
response=response)
# Login by username|email + password
class LoginByUsernameOrEmailView(JWTViewMixin):
class LoginByUsernameOrEmailView(JWTAuthViewMixin):
"""Login by email and password"""
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.LoginByUsernameOrEmailSerializer
# Refresh access_token
class RefreshTokenView(JWTViewMixin):
class RefreshTokenView(JWTAuthViewMixin):
"""Refresh access_token"""
permission_classes = (permissions.IsAuthenticated,)
serializer_class = serializers.RefreshTokenSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
response = Response(serializer.validated_data, status=status.HTTP_200_OK)
access_token = serializer.data.get('access_token')
refresh_token = serializer.data.get('access_token')
return self._put_cookies_in_response(
cookies=self._handle_cookies(request, access_token, refresh_token),
response=response)
# Logout
class LogoutView(generics.CreateAPIView):

View File

@ -1,5 +1,6 @@
from rest_framework import serializers
from location import models
from django.contrib.gis.geos import Point
class CountrySerializer(serializers.ModelSerializer):
@ -48,8 +49,8 @@ class CitySerializer(serializers.ModelSerializer):
class AddressSerializer(serializers.ModelSerializer):
"""Address serializer."""
city = CitySerializer()
longitude = serializers.DecimalField(max_digits=10, decimal_places=6)
latitude = serializers.DecimalField(max_digits=10, decimal_places=6)
geo_lon = serializers.FloatField(allow_null=True)
geo_lat = serializers.FloatField(allow_null=True)
class Meta:
model = models.Address
@ -59,14 +60,26 @@ class AddressSerializer(serializers.ModelSerializer):
'street_name_2',
'number',
'postal_code',
'longitude',
'latitude'
'geo_lon',
'geo_lat'
]
# def validate(self, attrs):
# geo_lat = attrs.pop('geo_lat') if 'geo_lat' in attrs else None
# geo_lon = attrs.pop('geo_lon') if 'geo_lon' in attrs else None
# if geo_lat and geo_lon:
# # Point(longitude, latitude)
# attrs['coordinates'] = Point(geo_lon, geo_lat)
# return attrs
def validate(self, attrs):
# if geo_lat and geo_lon was sent
geo_lat = attrs.pop('geo_lat') if 'geo_lat' in attrs else None
geo_lon = attrs.pop('geo_lon') if 'geo_lon' in attrs else None
if geo_lat and geo_lon:
# Point(longitude, latitude)
attrs['location'] = Point(geo_lat, geo_lon)
return attrs
def to_representation(self, instance):
"""Override to_representation method"""
if instance.coordinates and isinstance(instance.coordinates, Point):
# Point(longitude, latitude)
setattr(instance, 'geo_lat', instance.coordinates.x)
setattr(instance, 'geo_lon', instance.coordinates.y)
else:
setattr(instance, 'geo_lat', float(0))
setattr(instance, 'geo_lon', float(0))
return super().to_representation(instance)

View File

@ -6,27 +6,27 @@ from location import views
app_name = 'location'
urlpatterns = [
path('country/list/', views.CountryListView.as_view(), name='country-list'),
path('country/create/', views.CountryCreateView.as_view(), name='country-create'),
path('country/<int:pk>/detail/', views.CountryRetrieveView.as_view(), name='country-retrieve'),
path('country/<int:pk>/delete/', views.CountryDestroyView.as_view(), name='country-destroy'),
path('country/<int:pk>/update/', views.CountryUpdateView.as_view(), name='country-update'),
path('country/', views.CountryListView.as_view(), name='country_list'),
path('country/create/', views.CountryCreateView.as_view(), name='country_create'),
path('country/<int:pk>/', views.CountryRetrieveView.as_view(), name='country_retrieve'),
path('country/<int:pk>/delete/', views.CountryDestroyView.as_view(), name='country_destroy'),
path('country/<int:pk>/update/', views.CountryUpdateView.as_view(), name='country_update'),
path('region/list/', views.RegionListView.as_view(), name='region-list'),
path('region/create/', views.RegionCreateView.as_view(), name='region-create'),
path('region/<int:pk>/detail/', views.RegionRetrieveView.as_view(), name='region-retrieve'),
path('region/<int:pk>/delete/', views.RegionDestroyView.as_view(), name='region-destroy'),
path('region/<int:pk>/update/', views.RegionUpdateView.as_view(), name='region-update'),
path('region/', views.RegionListView.as_view(), name='region_list'),
path('region/create/', views.RegionCreateView.as_view(), name='region_create'),
path('region/<int:pk>/', views.RegionRetrieveView.as_view(), name='region_retrieve'),
path('region/<int:pk>/delete/', views.RegionDestroyView.as_view(), name='region_destroy'),
path('region/<int:pk>/update/', views.RegionUpdateView.as_view(), name='region_update'),
path('city/list/', views.CityListView.as_view(), name='city-list'),
path('city/create/', views.CityCreateView.as_view(), name='city-create'),
path('city/<int:pk>/detail/', views.CityRetrieveView.as_view(), name='city-retrieve'),
path('city/<int:pk>/delete/', views.CityDestroyView.as_view(), name='city-destroy'),
path('city/<int:pk>/update/', views.CityUpdateView.as_view(), name='city-update'),
path('city/', views.CityListView.as_view(), name='city_list'),
path('city/create/', views.CityCreateView.as_view(), name='city_create'),
path('city/<int:pk>/', views.CityRetrieveView.as_view(), name='city_retrieve'),
path('city/<int:pk>/delete/', views.CityDestroyView.as_view(), name='city_destroy'),
path('city/<int:pk>/update/', views.CityUpdateView.as_view(), name='city_update'),
path('address/list/', views.AddressListView.as_view(), name='address-list'),
path('address/create/', views.AddressCreateView.as_view(), name='address-create'),
path('address/<int:pk>/detail/', views.AddressRetrieveView.as_view(), name='address-retrieve'),
path('address/<int:pk>/delete/', views.AddressDestroyView.as_view(), name='address-destroy'),
path('address/<int:pk>/update/', views.AddressUpdateView.as_view(), name='address-update'),
path('address/', views.AddressListView.as_view(), name='address_list'),
path('address/create/', views.AddressCreateView.as_view(), name='address_create'),
path('address/<int:pk>/', views.AddressRetrieveView.as_view(), name='address_retrieve'),
path('address/<int:pk>/delete/', views.AddressDestroyView.as_view(), name='address_destroy'),
path('address/<int:pk>/update/', views.AddressUpdateView.as_view(), name='address_update'),
]

View File

@ -1,9 +1,10 @@
from rest_framework import generics, permissions
from news.models import News
from news.serializers import common as serializers
from utils.views import JWTViewMixin
class NewsList(generics.ListAPIView):
class NewsList(JWTViewMixin, generics.ListAPIView):
"""News list view."""
queryset = News.objects.all()
permission_classes = (permissions.AllowAny, )

View File

View File

@ -0,0 +1,7 @@
from django.contrib import admin
from translation.models import Language
@admin.register(Language)
class LanguageAdmin(admin.ModelAdmin):
"""Language admin."""

7
apps/translation/apps.py Normal file
View File

@ -0,0 +1,7 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _
class TranslationConfig(AppConfig):
name = 'translation'
verbose_name = _('Translation')

View File

@ -0,0 +1,26 @@
# Generated by Django 2.2.4 on 2019-08-14 13:35
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Language',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='Language title')),
('locale', models.CharField(max_length=10, verbose_name='Locale identifier')),
],
options={
'verbose_name': 'Language',
'verbose_name_plural': 'Languages',
},
),
]

View File

View File

@ -0,0 +1,33 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
class LanguageQuerySet(models.QuerySet):
"""QuerySet for model Language"""
def by_locale(self, locale: str) -> models.QuerySet:
"""Filter by locale"""
return self.filter(locale=locale)
def by_title(self, title: str) -> models.QuerySet:
"""Filter by title"""
return self.filter(title=title)
class Language(models.Model):
"""Language model."""
title = models.CharField(max_length=255,
verbose_name=_('Language title'))
locale = models.CharField(max_length=10,
verbose_name=_('Locale identifier'))
objects = LanguageQuerySet.as_manager()
class Meta:
verbose_name = _('Language')
verbose_name_plural = _('Languages')
def __str__(self):
"""String method"""
return f'{self.title} ({self.locale})'

View File

@ -0,0 +1,14 @@
from rest_framework import serializers
from translation import models
class LanguageSerializer(serializers.ModelSerializer):
"""Serializer for model Language"""
class Meta:
model = models.Language
fields = [
'id',
'title',
'locale'
]

View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

18
apps/translation/urls.py Normal file
View File

@ -0,0 +1,18 @@
from django.urls import path
from translation import views
app_name = 'translation'
urlpatterns = [
path('language/', views.LanguageListView.as_view(),
name='language_list'),
path('language/create/', views.LanguageCreateView.as_view(),
name='language_create'),
path('language/<int:pk>/update/', views.LanguageUpdateView.as_view(),
name='language_update'),
path('language/<int:pk>/destroy/', views.LanguageDestroyView.as_view(),
name='language_destroy'),
path('language/<int:pk>/', views.LanguageRetrieveView.as_view(),
name='language_retrieve'),
]

40
apps/translation/views.py Normal file
View File

@ -0,0 +1,40 @@
from rest_framework import generics
from translation import models
from translation import serializers
from rest_framework import permissions
from utils.views import JWTViewMixin
# Mixins
class LanguageViewMixin(generics.GenericAPIView):
"""Mixin for Language views"""
model = models.Language
queryset = models.Language.objects.all()
# Views
class LanguageListView(LanguageViewMixin, JWTViewMixin, generics.ListAPIView):
"""List view for model Language"""
permission_classes = (permissions.AllowAny, )
serializer_class = serializers.LanguageSerializer
class LanguageCreateView(LanguageViewMixin, generics.CreateAPIView):
"""Create view for model Language"""
permission_classes = (permissions.AllowAny, )
serializer_class = serializers.LanguageSerializer
class LanguageRetrieveView(LanguageViewMixin, generics.RetrieveAPIView):
"""Retrieve view for model Language"""
serializer_class = serializers.LanguageSerializer
class LanguageUpdateView(LanguageViewMixin, generics.UpdateAPIView):
"""Update view for model Language"""
serializer_class = serializers.LanguageSerializer
class LanguageDestroyView(LanguageViewMixin, generics.DestroyAPIView):
"""Destroy view for model Language"""
serializer_class = serializers.LanguageSerializer

View File

@ -47,3 +47,17 @@ class EmailSendingError(exceptions.APIException):
'detail': self.default_detail % recipient,
}
super().__init__()
class LocaleNotExisted(exceptions.APIException):
"""The exception should be thrown when passed locale isn't in model Language
"""
status_code = status.HTTP_400_BAD_REQUEST
default_detail = _('Locale not found in database (%s)')
def __init__(self, locale: str = None):
if locale:
self.default_detail = {
'detail': self.default_detail % locale
}
super().__init__()

View File

@ -1,3 +1,101 @@
from rest_framework import generics
from collections import namedtuple
from translation import models as translation_models
from utils import exceptions
from rest_framework.response import Response
# JWT
# Login base view mixin
class JWTViewMixin(generics.GenericAPIView):
"""JWT view mixin"""
ACCESS_TOKEN_HTTP = True
ACCESS_TOKEN_SECURE = False
REFRESH_TOKEN_HTTP = True
REFRESH_TOKEN_SECURE = False
COOKIE = namedtuple('COOKIE', ['key', 'value', 'http', 'secure'])
def _check_locale(self, locale: str):
locale_qs = translation_models.Language.objects.by_locale(locale=locale)
if not locale_qs.exists():
raise exceptions.LocaleNotExisted()
return locale
def _put_data_in_cookies(self,
locale: str,
access_token: str,
refresh_token: str):
"""
CHECK locale in cookies and PUT access and refresh tokens there.
cookies it is list that contain namedtuples
cookies would contain key, value and secure parameters.
"""
COOKIES = list()
# Create locale namedtuple
locale = self.COOKIE(key='locale',
value=locale,
http=True,
secure=False)
COOKIES.append(locale)
# Write to cookie access and refresh token with secure flag
_access_token = self.COOKIE(key='access_token',
value=access_token,
http=self.ACCESS_TOKEN_HTTP,
secure=self.ACCESS_TOKEN_SECURE)
_refresh_token = self.COOKIE(key='refresh_token',
value=refresh_token,
http=self.REFRESH_TOKEN_HTTP,
secure=self.REFRESH_TOKEN_SECURE)
COOKIES.extend((_access_token, _refresh_token))
return COOKIES
def _put_cookies_in_response(self, cookies: list, response: Response):
"""Update COOKIES in response from namedtuple"""
for cookie in cookies:
response.set_cookie(key=cookie.key,
value=cookie.value,
secure=cookie.secure)
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=self.ACCESS_TOKEN_HTTP,
secure=self.ACCESS_TOKEN_SECURE),
self.COOKIE(key='refresh_token',
value=_cookies.get('refresh_token'),
http=self.REFRESH_TOKEN_HTTP,
secure=self.REFRESH_TOKEN_SECURE)]
def get(self, request, *args, **kwargs):
"""Implement GET method"""
_locale = request.COOKIES.get('locale')
try:
locale = self._check_locale(locale=_locale)
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)
except exceptions.LocaleNotExisted:
raise exceptions.LocaleNotExisted(locale=_locale)
else:
return self._put_cookies_in_response(
cookies=self._put_data_in_cookies(locale=locale,
access_token=access_token,
refresh_token=refresh_token),
response=response)

View File

@ -56,6 +56,7 @@ PROJECT_APPS = [
'authorization.apps.AuthorizationConfig',
'location.apps.LocationConfig',
'news.apps.NewsConfig',
'translation.apps.TranslationConfig',
]

View File

@ -24,6 +24,7 @@ from rest_framework import permissions
# URL platform patterns
from project.urls import web as web_urlpatterns
from location import urls as location_urls
from translation import urls as translation_urls
schema_view = get_schema_view(
@ -60,6 +61,7 @@ urlpatterns = [
path('admin/', admin.site.urls),
path('api/web/', include(web_urlpatterns)),
path('api/location/', include(location_urls.urlpatterns)),
path('api/translation/', include(translation_urls.urlpatterns)),
]
urlpatterns = urlpatterns + \