Merge branch 'feature/news' into 'develop'
Feature/news See merge request gm/gm-backend!1
This commit is contained in:
commit
be21cfaf77
|
|
@ -3,9 +3,6 @@ import json
|
||||||
|
|
||||||
from braces.views import CsrfExemptMixin
|
from braces.views import CsrfExemptMixin
|
||||||
from django.conf import settings
|
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 django.utils.translation import gettext_lazy as _
|
||||||
from oauth2_provider.oauth2_backends import OAuthLibCore
|
from oauth2_provider.oauth2_backends import OAuthLibCore
|
||||||
from oauth2_provider.settings import oauth2_settings
|
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 rest_framework_social_oauth2.oauth2_endpoints import SocialTokenServer
|
||||||
|
|
||||||
from account.models import User
|
from account.models import User
|
||||||
from authorization import tasks
|
|
||||||
from authorization.models import Application
|
from authorization.models import Application
|
||||||
from authorization.serializers import common as serializers
|
from authorization.serializers import common as serializers
|
||||||
from utils import exceptions as utils_exceptions
|
from utils import exceptions as utils_exceptions
|
||||||
from utils.models import gm_token_generator
|
|
||||||
from utils.views import (JWTGenericViewMixin,
|
from utils.views import (JWTGenericViewMixin,
|
||||||
JWTCreateAPIView)
|
JWTCreateAPIView)
|
||||||
|
|
||||||
|
|
@ -35,22 +30,13 @@ class JWTAuthViewMixin(JWTCreateAPIView):
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""Implement POST method"""
|
"""Implement POST method"""
|
||||||
_locale = self._get_locale(request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
response = Response(serializer.data, status=status.HTTP_200_OK)
|
response = Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
access_token = serializer.data.get('access_token')
|
access_token = serializer.data.get('access_token')
|
||||||
refresh_token = serializer.data.get('refresh_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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token),
|
refresh_token=refresh_token),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -118,23 +104,14 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin):
|
||||||
permission_classes = (permissions.AllowAny, )
|
permission_classes = (permissions.AllowAny, )
|
||||||
serializer_class = serializers.OAuth2Serialzier
|
serializer_class = serializers.OAuth2Serialzier
|
||||||
|
|
||||||
def get_jwt_token(self, user: User,
|
def get_jwt_token(self, user: User):
|
||||||
oauth2_access_token: str,
|
|
||||||
oauth2_refresh_token: str):
|
|
||||||
"""Get JWT token"""
|
"""Get JWT token"""
|
||||||
token = jwt_tokens.RefreshToken.for_user(user)
|
token = jwt_tokens.RefreshToken.for_user(user)
|
||||||
# Adding additional information about user to payload
|
# Adding additional information about user to payload
|
||||||
token['user'] = user.get_user_info()
|
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
|
return token
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
|
||||||
_locale = self._get_locale(request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
# Preparing request data
|
# Preparing request data
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
@ -143,6 +120,7 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin):
|
||||||
'grant_type': settings.OAUTH2_SOCIAL_AUTH_GRANT_TYPE,
|
'grant_type': settings.OAUTH2_SOCIAL_AUTH_GRANT_TYPE,
|
||||||
'backend': settings.OAUTH2_SOCIAL_AUTH_BACKEND_NAME
|
'backend': settings.OAUTH2_SOCIAL_AUTH_BACKEND_NAME
|
||||||
})
|
})
|
||||||
|
|
||||||
# Use the rest framework `.data` to fake the post body of the django request.
|
# Use the rest framework `.data` to fake the post body of the django request.
|
||||||
request._request.POST = request._request.POST.copy()
|
request._request.POST = request._request.POST.copy()
|
||||||
for key, value in request_data.items():
|
for key, value in request_data.items():
|
||||||
|
|
@ -161,21 +139,14 @@ class OAuth2SignUpView(OAuth2ViewMixin, JWTGenericViewMixin):
|
||||||
.first()
|
.first()
|
||||||
|
|
||||||
# Create JWT token and put oauth2 token (access, refresh tokens) in payload
|
# Create JWT token and put oauth2 token (access, refresh tokens) in payload
|
||||||
token = self.get_jwt_token(user=user,
|
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)
|
access_token = str(token.access_token)
|
||||||
refresh_token = str(token)
|
refresh_token = str(token)
|
||||||
response = Response(data={'access_token': access_token,
|
response = Response(data={'access_token': access_token,
|
||||||
'refresh_token': refresh_token},
|
'refresh_token': refresh_token},
|
||||||
status=status.HTTP_200_OK)
|
status=status.HTTP_200_OK)
|
||||||
except utils_exceptions.LocaleNotExisted:
|
|
||||||
raise utils_exceptions.LocaleNotExisted(locale=_locale)
|
|
||||||
else:
|
|
||||||
return self._put_cookies_in_response(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token),
|
refresh_token=refresh_token),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -189,19 +160,10 @@ class SignUpView(JWTCreateAPIView):
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""Implement POST-method"""
|
"""Implement POST-method"""
|
||||||
_locale = self._get_locale(request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
response = Response(status=status.HTTP_201_CREATED)
|
return 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)
|
|
||||||
|
|
||||||
|
|
||||||
# Login by username|email + password
|
# Login by username|email + password
|
||||||
|
|
@ -212,23 +174,14 @@ class LoginByUsernameOrEmailView(JWTAuthViewMixin):
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
"""Implement POST method"""
|
"""Implement POST method"""
|
||||||
_locale = self._get_locale(request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
response = Response(serializer.data, status=status.HTTP_200_OK)
|
response = Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
access_token = serializer.data.get('access_token')
|
access_token = serializer.data.get('access_token')
|
||||||
refresh_token = serializer.data.get('refresh_token')
|
refresh_token = serializer.data.get('refresh_token')
|
||||||
is_permanent = serializer.validated_data.get('remember')
|
is_permanent = serializer.validated_data.get('remember')
|
||||||
except utils_exceptions.LocaleNotExisted:
|
|
||||||
raise utils_exceptions.LocaleNotExisted(locale=_locale)
|
|
||||||
else:
|
|
||||||
return self._put_cookies_in_response(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token,
|
refresh_token=refresh_token,
|
||||||
permanent=is_permanent),
|
permanent=is_permanent),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
@ -241,22 +194,13 @@ class RefreshTokenView(JWTGenericViewMixin):
|
||||||
serializer_class = serializers.RefreshTokenSerializer
|
serializer_class = serializers.RefreshTokenSerializer
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
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 = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
response = Response(serializer.data, status=status.HTTP_201_CREATED)
|
response = Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
access_token = serializer.data.get('access_token')
|
access_token = serializer.data.get('access_token')
|
||||||
refresh_token = serializer.data.get('refresh_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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token),
|
refresh_token=refresh_token),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -268,17 +212,7 @@ class LogoutView(JWTGenericViewMixin):
|
||||||
|
|
||||||
def create(self, request, *args, **kwargs):
|
def create(self, request, *args, **kwargs):
|
||||||
"""Override create method"""
|
"""Override create method"""
|
||||||
_locale = self._get_locale(request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
|
|
||||||
serializer = self.get_serializer(data=request.data)
|
serializer = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
response = Response(status=status.HTTP_200_OK)
|
return 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)
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from collection import models
|
from collection import models
|
||||||
from location.serializers import CountrySerializer
|
|
||||||
|
|
||||||
|
|
||||||
class CollectionSerializer(serializers.ModelSerializer):
|
class CollectionSerializer(serializers.ModelSerializer):
|
||||||
"""Collection serializer"""
|
"""Collection serializer"""
|
||||||
country = CountrySerializer()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Collection
|
model = models.Collection
|
||||||
fields = [
|
fields = [
|
||||||
|
|
@ -16,7 +14,6 @@ class CollectionSerializer(serializers.ModelSerializer):
|
||||||
'filters',
|
'filters',
|
||||||
'selectors',
|
'selectors',
|
||||||
'targets',
|
'targets',
|
||||||
'country'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,6 @@ class CollectionViewMixin(generics.GenericAPIView):
|
||||||
model = models.Collection
|
model = models.Collection
|
||||||
queryset = models.Collection.objects.all()
|
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):
|
class CollectionItemViewMixin(generics.GenericAPIView):
|
||||||
"""Mixin for CollectionItem view"""
|
"""Mixin for CollectionItem view"""
|
||||||
|
|
@ -37,7 +33,7 @@ class CollectionListView(CollectionViewMixin, generics.ListAPIView):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
"""Override get_queryset method"""
|
"""Override get_queryset method"""
|
||||||
return models.Collection.objects.published()\
|
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):
|
class CollectionRetrieveView(CollectionViewMixin, generics.RetrieveAPIView):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"""Location app views."""
|
"""Location app views."""
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
|
|
||||||
from location import models, serializers
|
from location import models, serializers
|
||||||
from utils.views import JWTGenericViewMixin
|
from utils.views import JWTGenericViewMixin
|
||||||
|
|
||||||
|
|
@ -13,8 +14,7 @@ class CountryViewMixin(JWTGenericViewMixin, generics.GenericAPIView):
|
||||||
permission_classes = (permissions.AllowAny, )
|
permission_classes = (permissions.AllowAny, )
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return models.Country.objects.annotate_localized_fields(
|
return models.Country.objects.annotate_localized_fields(locale=self.request.locale)
|
||||||
locale=self._get_locale(request=self.request))
|
|
||||||
|
|
||||||
|
|
||||||
class RegionViewMixin(generics.GenericAPIView):
|
class RegionViewMixin(generics.GenericAPIView):
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
"""Main app models."""
|
"""Main app models."""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.postgres.fields import JSONField
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
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 location.models import Country
|
||||||
|
from main import methods
|
||||||
from utils.models import ProjectBaseMixin
|
from utils.models import ProjectBaseMixin
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# class Tag(models.Model):
|
# class Tag(models.Model):
|
||||||
|
|
@ -94,7 +97,6 @@ from utils.models import ProjectBaseMixin
|
||||||
|
|
||||||
class SiteSettings(ProjectBaseMixin):
|
class SiteSettings(ProjectBaseMixin):
|
||||||
|
|
||||||
# todo: mb foreign key?
|
|
||||||
subdomain = models.CharField(max_length=255, db_index=True, unique=True,
|
subdomain = models.CharField(max_length=255, db_index=True, unique=True,
|
||||||
verbose_name=_('Subdomain'))
|
verbose_name=_('Subdomain'))
|
||||||
country = models.OneToOneField(Country, on_delete=models.PROTECT,
|
country = models.OneToOneField(Country, on_delete=models.PROTECT,
|
||||||
|
|
|
||||||
25
apps/news/migrations/0003_auto_20190822_1221.py
Normal file
25
apps/news/migrations/0003_auto_20190822_1221.py
Normal file
|
|
@ -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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -27,6 +27,14 @@ class NewsQuerySet(models.QuerySet):
|
||||||
"""Filter News by type"""
|
"""Filter News by type"""
|
||||||
return self.filter(news_type__name=news_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):
|
class News(BaseAttributes):
|
||||||
"""News model."""
|
"""News model."""
|
||||||
|
|
@ -41,7 +49,7 @@ class News(BaseAttributes):
|
||||||
default=None, help_text='{"en":"some text"}'
|
default=None, help_text='{"en":"some text"}'
|
||||||
)
|
)
|
||||||
description = JSONField(
|
description = JSONField(
|
||||||
_('subtitle'), null=True, blank=True,
|
_('description'), null=True, blank=True,
|
||||||
default=None, help_text='{"en":"some text"}'
|
default=None, help_text='{"en":"some text"}'
|
||||||
)
|
)
|
||||||
start = models.DateTimeField(_('start'))
|
start = models.DateTimeField(_('start'))
|
||||||
|
|
@ -50,6 +58,11 @@ class News(BaseAttributes):
|
||||||
address = models.ForeignKey(
|
address = models.ForeignKey(
|
||||||
'location.Address', verbose_name=_('address'), blank=True,
|
'location.Address', verbose_name=_('address'), blank=True,
|
||||||
null=True, default=None, on_delete=models.CASCADE)
|
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_keys - описание ключей для динамического построения полей метаданных
|
||||||
# TODO: metadata_values - Описание значений для динамических полей из MetadataKeys
|
# TODO: metadata_values - Описание значений для динамических полей из MetadataKeys
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ app_name = 'news'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', common.NewsList.as_view(), name='news_list'),
|
path('', common.NewsList.as_view(), name='news_list'),
|
||||||
path('create/', common.NewsCreate.as_view(), name='news_create'),
|
# path('create/', common.NewsCreate.as_view(), name='news_create'),
|
||||||
path('<int:pk>/', common.NewsDetail.as_view(), name='news_detail'),
|
# path('<int:pk>/', common.NewsDetail.as_view(), name='news_detail'),
|
||||||
path('<int:pk>/update/', common.NewsUpdate.as_view(), name='news_update'),
|
# path('<int:pk>/update/', common.NewsUpdate.as_view(), name='news_update'),
|
||||||
path('<int:pk>/delete/', common.NewsDelete.as_view(), name='news_delete'),
|
# path('<int:pk>/delete/', common.NewsDelete.as_view(), name='news_delete'),
|
||||||
path('type/', common.NewsTypeList.as_view(), name='news_type'),
|
path('type/', common.NewsTypeList.as_view(), name='news_type'),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
from rest_framework import generics, permissions
|
from rest_framework import generics, permissions
|
||||||
|
|
||||||
from news.models import News, NewsType
|
from news.models import News, NewsType
|
||||||
from news.serializers import common as serializers
|
from news.serializers import common as serializers
|
||||||
from utils.views import (JWTGenericViewMixin,
|
from utils.views import (JWTGenericViewMixin,
|
||||||
|
|
@ -11,8 +12,7 @@ class NewsViewMixin(JWTGenericViewMixin):
|
||||||
|
|
||||||
def get_queryset(self, *args, **kwargs):
|
def get_queryset(self, *args, **kwargs):
|
||||||
"""Override get_queryset method"""
|
"""Override get_queryset method"""
|
||||||
return News.objects.annotate_localized_fields(
|
return News.objects.annotate_localized_fields(locale=self.request.locale)
|
||||||
locale=self._get_locale(request=self.request))
|
|
||||||
|
|
||||||
|
|
||||||
class NewsList(NewsViewMixin, JWTListAPIView):
|
class NewsList(NewsViewMixin, JWTListAPIView):
|
||||||
|
|
@ -20,6 +20,12 @@ class NewsList(NewsViewMixin, JWTListAPIView):
|
||||||
permission_classes = (permissions.AllowAny, )
|
permission_classes = (permissions.AllowAny, )
|
||||||
serializer_class = serializers.NewsSerializer
|
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):
|
class NewsCreate(generics.CreateAPIView):
|
||||||
"""News list view."""
|
"""News list view."""
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
"""Translation app views."""
|
"""Translation app views."""
|
||||||
from rest_framework import generics, permissions
|
from rest_framework import generics, permissions
|
||||||
|
|
||||||
from translation import models, serializers
|
from translation import models, serializers
|
||||||
from utils.views import JWTGenericViewMixin
|
from utils.views import JWTGenericViewMixin
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ class SiteInterfaceDictionaryMixin:
|
||||||
|
|
||||||
# todo: refactor this
|
# todo: refactor this
|
||||||
def get_queryset(self):
|
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(
|
return models.SiteInterfaceDictionary.objects.annotate_localized_fields(
|
||||||
locale=locale)
|
locale=locale)
|
||||||
|
|
||||||
|
|
|
||||||
16
apps/utils/middleware.py
Normal file
16
apps/utils/middleware.py
Normal file
|
|
@ -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])
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from translation import models as translation_models
|
|
||||||
from utils import exceptions
|
|
||||||
from rest_framework_simplejwt import tokens
|
from rest_framework_simplejwt import tokens
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
|
|
||||||
# JWT
|
# JWT
|
||||||
|
|
@ -15,9 +12,6 @@ from django.conf import settings
|
||||||
class JWTGenericViewMixin(generics.GenericAPIView):
|
class JWTGenericViewMixin(generics.GenericAPIView):
|
||||||
"""JWT view mixin"""
|
"""JWT view mixin"""
|
||||||
|
|
||||||
LOCALE_HTTP_ONLY = False
|
|
||||||
LOCALE_SECURE = False
|
|
||||||
|
|
||||||
ACCESS_TOKEN_HTTP_ONLY = False
|
ACCESS_TOKEN_HTTP_ONLY = False
|
||||||
ACCESS_TOKEN_SECURE = False
|
ACCESS_TOKEN_SECURE = False
|
||||||
|
|
||||||
|
|
@ -34,35 +28,16 @@ class JWTGenericViewMixin(generics.GenericAPIView):
|
||||||
'refresh_token': str(token),
|
'refresh_token': str(token),
|
||||||
}
|
}
|
||||||
|
|
||||||
def _get_locale(self, request):
|
def _put_data_in_cookies(self,
|
||||||
"""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,
|
access_token: str = None,
|
||||||
refresh_token: str = None,
|
refresh_token: str = None,
|
||||||
permanent: bool = None):
|
permanent: bool = None):
|
||||||
"""
|
"""
|
||||||
CHECK locale in cookies and PUT access and refresh tokens there.
|
|
||||||
cookies it is list that contain namedtuples
|
cookies it is list that contain namedtuples
|
||||||
cookies would contain key, value and secure parameters.
|
cookies would contain key, value and secure parameters.
|
||||||
"""
|
"""
|
||||||
COOKIES = list()
|
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
|
# Write to cookie access and refresh token with secure flag
|
||||||
if access_token and refresh_token:
|
if access_token and refresh_token:
|
||||||
_access_token = self.COOKIE(key='access_token',
|
_access_token = self.COOKIE(key='access_token',
|
||||||
|
|
@ -76,7 +51,6 @@ class JWTGenericViewMixin(generics.GenericAPIView):
|
||||||
secure=self.REFRESH_TOKEN_SECURE,
|
secure=self.REFRESH_TOKEN_SECURE,
|
||||||
max_age=None if permanent else settings.COOKIES_MAX_AGE)
|
max_age=None if permanent else settings.COOKIES_MAX_AGE)
|
||||||
COOKIES.extend((_access_token, _refresh_token))
|
COOKIES.extend((_access_token, _refresh_token))
|
||||||
COOKIES.append(_locale)
|
|
||||||
return COOKIES
|
return COOKIES
|
||||||
|
|
||||||
def _put_cookies_in_response(self, cookies: list, response: Response):
|
def _put_cookies_in_response(self, cookies: list, response: Response):
|
||||||
|
|
@ -120,12 +94,7 @@ class JWTListAPIView(JWTGenericViewMixin, generics.ListAPIView):
|
||||||
Concrete view for creating a model instance.
|
Concrete view for creating a model instance.
|
||||||
"""
|
"""
|
||||||
def get(self, request, *args, **kwargs):
|
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())
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
|
|
||||||
page = self.paginate_queryset(queryset)
|
page = self.paginate_queryset(queryset)
|
||||||
if page is not None:
|
if page is not None:
|
||||||
serializer = self.get_serializer(page, many=True)
|
serializer = self.get_serializer(page, many=True)
|
||||||
|
|
@ -133,14 +102,9 @@ class JWTListAPIView(JWTGenericViewMixin, generics.ListAPIView):
|
||||||
else:
|
else:
|
||||||
serializer = self.get_serializer(queryset, many=True)
|
serializer = self.get_serializer(queryset, many=True)
|
||||||
response = Response(serializer.data)
|
response = Response(serializer.data)
|
||||||
|
|
||||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token.value,
|
||||||
access_token=access_token.value,
|
|
||||||
refresh_token=refresh_token.value),
|
refresh_token=refresh_token.value),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -150,22 +114,13 @@ class JWTCreateAPIView(JWTGenericViewMixin, generics.CreateAPIView):
|
||||||
Concrete view for creating a model instance.
|
Concrete view for creating a model instance.
|
||||||
"""
|
"""
|
||||||
def post(self, request, *args, **kwargs):
|
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 = self.get_serializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
|
|
||||||
response = Response(serializer.data, status=status.HTTP_201_CREATED)
|
response = Response(serializer.data, status=status.HTTP_201_CREATED)
|
||||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token.value,
|
||||||
access_token=access_token.value,
|
|
||||||
refresh_token=refresh_token.value),
|
refresh_token=refresh_token.value),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -176,10 +131,6 @@ class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView):
|
||||||
"""
|
"""
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
"""Implement GET method"""
|
"""Implement GET method"""
|
||||||
_locale = self._get_locale(request=request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
|
|
||||||
queryset = self.filter_queryset(self.get_queryset())
|
queryset = self.filter_queryset(self.get_queryset())
|
||||||
page = self.paginate_queryset(queryset)
|
page = self.paginate_queryset(queryset)
|
||||||
if page is not None:
|
if page is not None:
|
||||||
|
|
@ -188,15 +139,9 @@ class JWTRetrieveAPIView(JWTGenericViewMixin, generics.RetrieveAPIView):
|
||||||
else:
|
else:
|
||||||
serializer = self.get_serializer(queryset, many=True)
|
serializer = self.get_serializer(queryset, many=True)
|
||||||
response = Response(serializer.data, status.HTTP_200_OK)
|
response = Response(serializer.data, status.HTTP_200_OK)
|
||||||
|
|
||||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token),
|
refresh_token=refresh_token),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -206,20 +151,12 @@ class JWTDestroyAPIView(JWTGenericViewMixin, generics.DestroyAPIView):
|
||||||
Concrete view for deleting a model instance.
|
Concrete view for deleting a model instance.
|
||||||
"""
|
"""
|
||||||
def delete(self, request, *args, **kwargs):
|
def delete(self, request, *args, **kwargs):
|
||||||
_locale = self._get_locale(request=request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
instance.delete()
|
instance.delete()
|
||||||
response = Response(status=status.HTTP_204_NO_CONTENT)
|
response = Response(status=status.HTTP_204_NO_CONTENT)
|
||||||
|
|
||||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token),
|
refresh_token=refresh_token),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
@ -229,28 +166,19 @@ class JWTUpdateAPIView(JWTGenericViewMixin, generics.UpdateAPIView):
|
||||||
Concrete view for updating a model instance.
|
Concrete view for updating a model instance.
|
||||||
"""
|
"""
|
||||||
def put(self, request, *args, **kwargs):
|
def put(self, request, *args, **kwargs):
|
||||||
_locale = self._get_locale(request=request)
|
|
||||||
try:
|
|
||||||
locale = self._check_locale(locale=_locale)
|
|
||||||
partial = kwargs.pop('partial', False)
|
partial = kwargs.pop('partial', False)
|
||||||
instance = self.get_object()
|
instance = self.get_object()
|
||||||
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
serializer = self.get_serializer(instance, data=request.data, partial=partial)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
serializer.save()
|
serializer.save()
|
||||||
|
|
||||||
if getattr(instance, '_prefetched_objects_cache', None):
|
if getattr(instance, '_prefetched_objects_cache', None):
|
||||||
# If 'prefetch_related' has been applied to a queryset, we need to
|
# If 'prefetch_related' has been applied to a queryset, we need to
|
||||||
# forcibly invalidate the prefetch cache on the instance.
|
# forcibly invalidate the prefetch cache on the instance.
|
||||||
instance._prefetched_objects_cache = {}
|
instance._prefetched_objects_cache = {}
|
||||||
|
|
||||||
response = Response(serializer.data)
|
response = Response(serializer.data)
|
||||||
access_token, refresh_token = self._get_tokens_from_cookies(request)
|
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(
|
return self._put_cookies_in_response(
|
||||||
cookies=self._put_data_in_cookies(locale=locale,
|
cookies=self._put_data_in_cookies(access_token=access_token,
|
||||||
access_token=access_token,
|
|
||||||
refresh_token=refresh_token),
|
refresh_token=refresh_token),
|
||||||
response=response)
|
response=response)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ INSTALLED_APPS = CONTRIB_APPS + PROJECT_APPS + EXTERNAL_APPS
|
||||||
|
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
|
'utils.middleware.CookieMiddleware',
|
||||||
'django.middleware.security.SecurityMiddleware',
|
'django.middleware.security.SecurityMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'oauth2_provider.middleware.OAuth2TokenMiddleware',
|
'oauth2_provider.middleware.OAuth2TokenMiddleware',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user