From f86a94274ddaee40fd882414d70f81475a2e4101 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Fri, 23 Aug 2019 09:42:31 +0300 Subject: [PATCH 1/2] put cookies in request, refactored JWTViewMixin, change endpoint to get news list --- apps/authorization/views/common.py | 216 +++++++----------- apps/collection/serializers/common.py | 5 +- apps/collection/views/common.py | 6 +- apps/location/views.py | 4 +- apps/main/models.py | 8 +- .../migrations/0003_auto_20190822_1221.py | 25 ++ apps/news/models.py | 15 +- apps/news/urls/web.py | 8 +- apps/news/views/common.py | 10 +- apps/translation/views.py | 3 +- apps/utils/middleware.py | 16 ++ apps/utils/views.py | 190 +++++---------- project/settings/base.py | 1 + 13 files changed, 221 insertions(+), 286 deletions(-) create mode 100644 apps/news/migrations/0003_auto_20190822_1221.py create mode 100644 apps/utils/middleware.py diff --git a/apps/authorization/views/common.py b/apps/authorization/views/common.py index f57be4d5..efee7700 100644 --- a/apps/authorization/views/common.py +++ b/apps/authorization/views/common.py @@ -3,9 +3,6 @@ import json from braces.views import CsrfExemptMixin from django.conf import settings -from django.urls import reverse -from django.utils.encoding import force_text -from django.utils.http import urlsafe_base64_decode from django.utils.translation import gettext_lazy as _ from oauth2_provider.oauth2_backends import OAuthLibCore from oauth2_provider.settings import oauth2_settings @@ -19,11 +16,9 @@ from rest_framework_social_oauth2.oauth2_backends import KeepRequestCore from rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer from account.models import User -from authorization import tasks from authorization.models import Application from authorization.serializers import common as serializers from utils import exceptions as utils_exceptions -from utils.models import gm_token_generator from utils.views import (JWTGenericViewMixin, JWTCreateAPIView) @@ -35,24 +30,16 @@ class JWTAuthViewMixin(JWTCreateAPIView): def post(self, request, *args, **kwargs): """Implement POST method""" - _locale = self._get_locale(request) - 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) + 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') + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token), + response=response) # OAuth2 @@ -118,66 +105,52 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin): permission_classes = (permissions.AllowAny, ) serializer_class = serializers.OAuth2Serialzier - def get_jwt_token(self, user: User, - oauth2_access_token: str, - oauth2_refresh_token: str): + def get_jwt_token(self, user: User): """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': 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 + }) - _locale = self._get_locale(request) - 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 + # 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 - # OAuth2 authentication process - url, headers, body, oauth2_status = self.create_token_response(request._request) - body = json.loads(body) + # 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 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() + # 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) + # Create JWT token and put oauth2 token (access, refresh tokens) in payload + token = self.get_jwt_token(user=user) + 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) + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token), + response=response) # JWT @@ -189,19 +162,13 @@ class SignUpView(JWTCreateAPIView): def post(self, request, *args, **kwargs): """Implement POST-method""" - _locale = self._get_locale(request) - try: - locale = self._check_locale(locale=_locale) - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save() - response = Response(status=status.HTTP_201_CREATED) - 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), - response=response) + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + response = Response(status=status.HTTP_201_CREATED) + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale), + response=response) # Login by username|email + password @@ -212,26 +179,18 @@ class LoginByUsernameOrEmailView(JWTAuthViewMixin): def post(self, request, *args, **kwargs): """Implement POST method""" - _locale = self._get_locale(request) - 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') - is_permanent = serializer.validated_data.get('remember') - 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, - permanent=is_permanent), - response=response) + 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') + is_permanent = serializer.validated_data.get('remember') + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token, + permanent=is_permanent), + response=response) # Refresh access_token @@ -241,24 +200,16 @@ class RefreshTokenView(JWTGenericViewMixin): serializer_class = serializers.RefreshTokenSerializer def post(self, request, *args, **kwargs): - _locale = self._get_locale(request) - 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_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) + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + response = Response(serializer.data, status=status.HTTP_201_CREATED) + access_token = serializer.data.get('access_token') + refresh_token = serializer.data.get('refresh_token') + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token), + response=response) # Logout @@ -268,17 +219,10 @@ class LogoutView(JWTGenericViewMixin): def create(self, request, *args, **kwargs): """Override create method""" - _locale = self._get_locale(request) - try: - locale = self._check_locale(locale=_locale) - - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save() - response = Response(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), - response=response) + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + serializer.save() + response = Response(status=status.HTTP_200_OK) + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale), + response=response) diff --git a/apps/collection/serializers/common.py b/apps/collection/serializers/common.py index f1aeee3c..eb5b99b5 100644 --- a/apps/collection/serializers/common.py +++ b/apps/collection/serializers/common.py @@ -1,12 +1,10 @@ from rest_framework import serializers + from collection import models -from location.serializers import CountrySerializer class CollectionSerializer(serializers.ModelSerializer): """Collection serializer""" - country = CountrySerializer() - class Meta: model = models.Collection fields = [ @@ -16,7 +14,6 @@ class CollectionSerializer(serializers.ModelSerializer): 'filters', 'selectors', 'targets', - 'country' ] diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index eb288daf..956ecd07 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -11,10 +11,6 @@ class CollectionViewMixin(generics.GenericAPIView): model = models.Collection queryset = models.Collection.objects.all() - def get_country_code(self): - """Get country_code from cookies.""" - return self.request.COOKIES.get('country_code') - class CollectionItemViewMixin(generics.GenericAPIView): """Mixin for CollectionItem view""" @@ -37,7 +33,7 @@ class CollectionListView(CollectionViewMixin, generics.ListAPIView): def get_queryset(self): """Override get_queryset method""" return models.Collection.objects.published()\ - .by_country_code(code=self.get_country_code()) + .by_country_code(code=self.request.country_code) class CollectionRetrieveView(CollectionViewMixin, generics.RetrieveAPIView): diff --git a/apps/location/views.py b/apps/location/views.py index 3fba32c2..5ca9ec2c 100644 --- a/apps/location/views.py +++ b/apps/location/views.py @@ -1,6 +1,7 @@ """Location app views.""" from rest_framework import generics from rest_framework import permissions + from location import models, serializers from utils.views import JWTGenericViewMixin @@ -13,8 +14,7 @@ class CountryViewMixin(JWTGenericViewMixin, generics.GenericAPIView): permission_classes = (permissions.AllowAny, ) def get_queryset(self): - return models.Country.objects.annotate_localized_fields( - locale=self._get_locale(request=self.request)) + return models.Country.objects.annotate_localized_fields(locale=self.request.locale) class RegionViewMixin(generics.GenericAPIView): diff --git a/apps/main/models.py b/apps/main/models.py index 834db85e..563dbd88 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -1,11 +1,14 @@ """Main app models.""" from django.conf import settings +from django.contrib.postgres.fields import JSONField from django.db import models from django.utils.translation import gettext_lazy as _ -from django.contrib.postgres.fields import JSONField -from main import methods + from location.models import Country +from main import methods from utils.models import ProjectBaseMixin + + # # # class Tag(models.Model): @@ -94,7 +97,6 @@ from utils.models import ProjectBaseMixin class SiteSettings(ProjectBaseMixin): - # todo: mb foreign key? subdomain = models.CharField(max_length=255, db_index=True, unique=True, verbose_name=_('Subdomain')) country = models.OneToOneField(Country, on_delete=models.PROTECT, diff --git a/apps/news/migrations/0003_auto_20190822_1221.py b/apps/news/migrations/0003_auto_20190822_1221.py new file mode 100644 index 00000000..9ba73211 --- /dev/null +++ b/apps/news/migrations/0003_auto_20190822_1221.py @@ -0,0 +1,25 @@ +# Generated by Django 2.2.4 on 2019-08-22 12:21 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0005_auto_20190822_1144'), + ('news', '0002_auto_20190816_1232'), + ] + + operations = [ + migrations.AddField( + model_name='news', + name='country', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='location.Country', verbose_name='country'), + ), + migrations.AddField( + model_name='news', + name='is_publish', + field=models.BooleanField(default=False, verbose_name='Publish status'), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 4d1dd39e..2dc4cbc4 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -27,6 +27,14 @@ class NewsQuerySet(models.QuerySet): """Filter News by type""" return self.filter(news_type__name=news_type) + def by_country_code(self, code): + """Filter collection by country code.""" + return self.filter(country__code=code) + + def published(self): + """Return only published news""" + return self.filter(is_publish=True) + class News(BaseAttributes): """News model.""" @@ -41,7 +49,7 @@ class News(BaseAttributes): default=None, help_text='{"en":"some text"}' ) description = JSONField( - _('subtitle'), null=True, blank=True, + _('description'), null=True, blank=True, default=None, help_text='{"en":"some text"}' ) start = models.DateTimeField(_('start')) @@ -50,6 +58,11 @@ class News(BaseAttributes): address = models.ForeignKey( 'location.Address', verbose_name=_('address'), blank=True, null=True, default=None, on_delete=models.CASCADE) + is_publish = models.BooleanField( + default=False, verbose_name=_('Publish status')) + country = models.ForeignKey( + 'location.Country', blank=True, null=True, + verbose_name=_('country'), on_delete=models.CASCADE) # TODO: metadata_keys - описание ключей для динамического построения полей метаданных # TODO: metadata_values - Описание значений для динамических полей из MetadataKeys diff --git a/apps/news/urls/web.py b/apps/news/urls/web.py index 04203f1a..b70e5b12 100644 --- a/apps/news/urls/web.py +++ b/apps/news/urls/web.py @@ -7,9 +7,9 @@ app_name = 'news' urlpatterns = [ path('', common.NewsList.as_view(), name='news_list'), - path('create/', common.NewsCreate.as_view(), name='news_create'), - path('/', common.NewsDetail.as_view(), name='news_detail'), - path('/update/', common.NewsUpdate.as_view(), name='news_update'), - path('/delete/', common.NewsDelete.as_view(), name='news_delete'), + # path('create/', common.NewsCreate.as_view(), name='news_create'), + # path('/', common.NewsDetail.as_view(), name='news_detail'), + # path('/update/', common.NewsUpdate.as_view(), name='news_update'), + # path('/delete/', common.NewsDelete.as_view(), name='news_delete'), path('type/', common.NewsTypeList.as_view(), name='news_type'), ] diff --git a/apps/news/views/common.py b/apps/news/views/common.py index cc1cce81..6939ec2a 100644 --- a/apps/news/views/common.py +++ b/apps/news/views/common.py @@ -1,4 +1,5 @@ from rest_framework import generics, permissions + from news.models import News, NewsType from news.serializers import common as serializers from utils.views import (JWTGenericViewMixin, @@ -11,8 +12,7 @@ class NewsViewMixin(JWTGenericViewMixin): def get_queryset(self, *args, **kwargs): """Override get_queryset method""" - return News.objects.annotate_localized_fields( - locale=self._get_locale(request=self.request)) + return News.objects.annotate_localized_fields(locale=self.request.locale) class NewsList(NewsViewMixin, JWTListAPIView): @@ -20,6 +20,12 @@ class NewsList(NewsViewMixin, JWTListAPIView): permission_classes = (permissions.AllowAny, ) serializer_class = serializers.NewsSerializer + def get_queryset(self, *args, **kwargs): + """Override get_queryset method""" + return News.objects.annotate_localized_fields(locale=self.request.locale)\ + .published()\ + .by_country_code(code=self.request.country_code) + class NewsCreate(generics.CreateAPIView): """News list view.""" diff --git a/apps/translation/views.py b/apps/translation/views.py index 9ddf9983..01b8ce1d 100644 --- a/apps/translation/views.py +++ b/apps/translation/views.py @@ -1,5 +1,6 @@ """Translation app views.""" from rest_framework import generics, permissions + from translation import models, serializers from utils.views import JWTGenericViewMixin @@ -29,7 +30,7 @@ class SiteInterfaceDictionaryMixin: # todo: refactor this def get_queryset(self): - locale = self._get_locale(self.request) or 'en' + locale = self.request.locale or 'en' return models.SiteInterfaceDictionary.objects.annotate_localized_fields( locale=locale) diff --git a/apps/utils/middleware.py b/apps/utils/middleware.py new file mode 100644 index 00000000..0e59f9eb --- /dev/null +++ b/apps/utils/middleware.py @@ -0,0 +1,16 @@ +from django.utils.deprecation import MiddlewareMixin + + +class CookieMiddleware(MiddlewareMixin): + """Middleware to handle cookies""" + + def process_request(self, request): + # Check locale in cookies if locale not exists in DB return 406 + # if 'locale' not in request.COOKIES or \ + # not Language.objects.by_locale(request.COOKIES.get('locale'))\ + # .exists(): + # return HttpResponse(status=status.HTTP_406_NOT_ACCEPTABLE) + # + # Add to request attrs from cookie + for cookie in request.COOKIES: + setattr(request, cookie, request.COOKIES[cookie]) diff --git a/apps/utils/views.py b/apps/utils/views.py index d9482456..c3a2679e 100644 --- a/apps/utils/views.py +++ b/apps/utils/views.py @@ -1,13 +1,10 @@ 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 - -from translation import models as translation_models -from utils import exceptions from rest_framework_simplejwt import tokens -from django.conf import settings # JWT @@ -15,9 +12,6 @@ from django.conf import settings class JWTGenericViewMixin(generics.GenericAPIView): """JWT view mixin""" - LOCALE_HTTP_ONLY = False - LOCALE_SECURE = False - ACCESS_TOKEN_HTTP_ONLY = False ACCESS_TOKEN_SECURE = False @@ -34,17 +28,6 @@ class JWTGenericViewMixin(generics.GenericAPIView): 'refresh_token': str(token), } - def _get_locale(self, request): - """Get locale from request""" - return request.COOKIES.get('locale') - - 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 = None, refresh_token: str = None, @@ -56,13 +39,6 @@ class JWTGenericViewMixin(generics.GenericAPIView): """ COOKIES = list() - # Create locale namedtuple - _locale = self.COOKIE(key='locale', - value=locale, - http_only=self.LOCALE_HTTP_ONLY, - secure=self.LOCALE_SECURE, - max_age=None if permanent else settings.COOKIES_MAX_AGE) - # Write to cookie access and refresh token with secure flag if access_token and refresh_token: _access_token = self.COOKIE(key='access_token', @@ -76,7 +52,6 @@ class JWTGenericViewMixin(generics.GenericAPIView): secure=self.REFRESH_TOKEN_SECURE, max_age=None if permanent else settings.COOKIES_MAX_AGE) COOKIES.extend((_access_token, _refresh_token)) - COOKIES.append(_locale) return COOKIES def _put_cookies_in_response(self, cookies: list, response: Response): @@ -120,29 +95,20 @@ class JWTListAPIView(JWTGenericViewMixin, generics.ListAPIView): Concrete view for creating a model instance. """ def get(self, request, *args, **kwargs): - _locale = self._get_locale(request=request) - 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) + 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: - return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=locale, - access_token=access_token.value, - refresh_token=refresh_token.value), - response=response) + 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(locale=request.locale, + access_token=access_token.value, + refresh_token=refresh_token.value), + response=response) class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView): @@ -150,24 +116,16 @@ class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView): Concrete view for creating a model instance. """ def post(self, request, *args, **kwargs): - _locale = self._get_locale(request=request) - 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, 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.value, - refresh_token=refresh_token.value), - 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, refresh_token = self._get_tokens_from_cookies(request) + return self._put_cookies_in_response( + cookies=self._put_data_in_cookies(locale=request.locale, + access_token=access_token.value, + refresh_token=refresh_token.value), + response=response) class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView): @@ -176,29 +134,20 @@ class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView): """ def get(self, request, *args, **kwargs): """Implement GET method""" - _locale = self._get_locale(request=request) - 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, status.HTTP_200_OK) - - access_token, refresh_token = self._get_tokens_from_cookies(request) - - except exceptions.LocaleNotExisted: - raise exceptions.LocaleNotExisted(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: - return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=locale, - access_token=access_token, - refresh_token=refresh_token), - response=response) + 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(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token), + response=response) class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView): @@ -206,22 +155,15 @@ class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView): Concrete view for deleting a model instance. """ def delete(self, request, *args, **kwargs): - _locale = self._get_locale(request=request) - try: - locale = self._check_locale(locale=_locale) - instance = self.get_object() - instance.delete() - response = Response(status=status.HTTP_204_NO_CONTENT) - - 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) + 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(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token), + response=response) class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView): @@ -229,30 +171,22 @@ class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView): Concrete view for updating a model instance. """ def put(self, request, *args, **kwargs): - _locale = self._get_locale(request=request) - try: - locale = self._check_locale(locale=_locale) - 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) - 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) + 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(locale=request.locale, + access_token=access_token, + refresh_token=refresh_token), + response=response) def patch(self, request, *args, **kwargs): kwargs['partial'] = True diff --git a/project/settings/base.py b/project/settings/base.py index 7a768d26..2bea0cae 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -81,6 +81,7 @@ INSTALLED_APPS = CONTRIB_APPS + PROJECT_APPS + EXTERNAL_APPS MIDDLEWARE = [ + 'utils.middleware.CookieMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'oauth2_provider.middleware.OAuth2TokenMiddleware', From 0dba806f04d3f940fd50c4cc780d27cccc10eb21 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Fri, 23 Aug 2019 09:47:30 +0300 Subject: [PATCH 2/2] fixed method _put_data_in_cookies --- apps/authorization/views/common.py | 22 ++++++---------------- apps/utils/views.py | 18 ++++++------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/apps/authorization/views/common.py b/apps/authorization/views/common.py index efee7700..8b324bdd 100644 --- a/apps/authorization/views/common.py +++ b/apps/authorization/views/common.py @@ -36,8 +36,7 @@ class JWTAuthViewMixin(JWTCreateAPIView): access_token = serializer.data.get('access_token') refresh_token = serializer.data.get('refresh_token') return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token), response=response) @@ -147,8 +146,7 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin): 'refresh_token': refresh_token}, status=status.HTTP_200_OK) return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token), response=response) @@ -165,10 +163,7 @@ class SignUpView(JWTCreateAPIView): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() - response = Response(status=status.HTTP_201_CREATED) - return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=request.locale), - response=response) + return Response(status=status.HTTP_201_CREATED) # Login by username|email + password @@ -186,8 +181,7 @@ class LoginByUsernameOrEmailView(JWTAuthViewMixin): refresh_token = serializer.data.get('refresh_token') is_permanent = serializer.validated_data.get('remember') return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token, permanent=is_permanent), response=response) @@ -206,8 +200,7 @@ class RefreshTokenView(JWTGenericViewMixin): access_token = serializer.data.get('access_token') refresh_token = serializer.data.get('refresh_token') return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token), response=response) @@ -222,7 +215,4 @@ class LogoutView(JWTGenericViewMixin): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() - response = Response(status=status.HTTP_200_OK) - return self._put_cookies_in_response( - cookies=self._put_data_in_cookies(locale=request.locale), - response=response) + return Response(status=status.HTTP_200_OK) diff --git a/apps/utils/views.py b/apps/utils/views.py index c3a2679e..b8c8e9f5 100644 --- a/apps/utils/views.py +++ b/apps/utils/views.py @@ -28,12 +28,11 @@ class JWTGenericViewMixin(generics.GenericAPIView): 'refresh_token': str(token), } - def _put_data_in_cookies(self, locale: str, + def _put_data_in_cookies(self, access_token: str = None, refresh_token: str = None, permanent: bool = None): """ - 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. """ @@ -105,8 +104,7 @@ class JWTListAPIView(JWTGenericViewMixin, generics.ListAPIView): 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(locale=request.locale, - access_token=access_token.value, + cookies=self._put_data_in_cookies(access_token=access_token.value, refresh_token=refresh_token.value), response=response) @@ -122,8 +120,7 @@ class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView): 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(locale=request.locale, - access_token=access_token.value, + cookies=self._put_data_in_cookies(access_token=access_token.value, refresh_token=refresh_token.value), response=response) @@ -144,8 +141,7 @@ class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView): 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(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token), response=response) @@ -160,8 +156,7 @@ class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView): 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(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token), response=response) @@ -183,8 +178,7 @@ class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView): 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(locale=request.locale, - access_token=access_token, + cookies=self._put_data_in_cookies(access_token=access_token, refresh_token=refresh_token), response=response)