From d853960d2ef79ba1a8df8fedd2f6b644afa62cd7 Mon Sep 17 00:00:00 2001 From: alex Date: Tue, 5 Nov 2019 17:52:36 +0300 Subject: [PATCH] create, delete, get favorite news --- apps/favorites/urls.py | 2 ++ apps/favorites/views.py | 22 ++++++++++++++++++---- apps/news/models.py | 2 +- apps/news/serializers.py | 33 ++++++++++++++++++++++++++++++++- apps/news/tests.py | 20 +++++++++++++++++--- apps/news/urls/web.py | 1 + apps/news/views.py | 27 ++++++++++++++++++++++----- 7 files changed, 93 insertions(+), 14 deletions(-) diff --git a/apps/favorites/urls.py b/apps/favorites/urls.py index ad4c6e9d..9ca814c9 100644 --- a/apps/favorites/urls.py +++ b/apps/favorites/urls.py @@ -10,4 +10,6 @@ urlpatterns = [ name='establishment-list'), path('products/', views.FavoritesProductListView.as_view(), name='product-list'), + path('news/', views.FavoritesNewsListView.as_view(), + name='news-list'), ] diff --git a/apps/favorites/views.py b/apps/favorites/views.py index d2973142..ce06863d 100644 --- a/apps/favorites/views.py +++ b/apps/favorites/views.py @@ -3,6 +3,9 @@ from rest_framework import generics from establishment.models import Establishment from establishment.filters import EstablishmentFilter from establishment.serializers import EstablishmentBaseSerializer +from news.filters import NewsListFilterSet +from news.models import News +from news.serializers import NewsBaseSerializer from product.models import Product from product.serializers import ProductBaseSerializer from product.filters import ProductFilterSet @@ -25,8 +28,8 @@ class FavoritesEstablishmentListView(generics.ListAPIView): def get_queryset(self): """Override get_queryset method""" - return Establishment.objects.filter(favorites__user=self.request.user)\ - .order_by('-favorites') + return Establishment.objects.filter(favorites__user=self.request.user) \ + .order_by('-favorites') class FavoritesProductListView(generics.ListAPIView): @@ -37,5 +40,16 @@ class FavoritesProductListView(generics.ListAPIView): def get_queryset(self): """Override get_queryset method""" - return Product.objects.filter(favorites__user=self.request.user)\ - .order_by('-favorites') + return Product.objects.filter(favorites__user=self.request.user) \ + .order_by('-favorites') + + +class FavoritesNewsListView(generics.ListAPIView): + """List views for news in favorites.""" + + serializer_class = NewsBaseSerializer + filter_class = NewsListFilterSet + + def get_queryset(self): + """Override get_queryset method""" + return News.objects.filter(favorites__user=self.request.user).order_by('-favorites') diff --git a/apps/news/models.py b/apps/news/models.py index 9a0c19d8..73a8c369 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -159,7 +159,7 @@ class News(BaseAttributes, TranslatedFieldsMixin): verbose_name=_('Tags')) gallery = models.ManyToManyField('gallery.Image', through='news.NewsGallery') ratings = generic.GenericRelation(Rating) - + favorites = generic.GenericRelation(to='favorites.Favorites') agenda = models.ForeignKey('news.Agenda', blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('agenda')) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 40495e2c..95ec21b8 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -8,7 +8,8 @@ from location import models as location_models from location.serializers import CountrySimpleSerializer, AddressBaseSerializer from news import models from tag.serializers import TagBaseSerializer -from utils.serializers import TranslatedField, ProjectModelSerializer +from utils import exceptions as utils_exceptions +from utils.serializers import TranslatedField, ProjectModelSerializer, FavoritesCreateSerializer class AgendaSerializer(ProjectModelSerializer): @@ -293,3 +294,33 @@ class NewsBackOfficeGallerySerializer(serializers.ModelSerializer): attrs['image'] = image return attrs + + +class NewsFavoritesCreateSerializer(FavoritesCreateSerializer): + """Serializer to favorite object w/ model News.""" + + def validate(self, attrs): + """Overridden validate method""" + # Check establishment object + news_qs = models.News.objects.filter(slug=self.slug) + + # Check establishment obj by slug from lookup_kwarg + if not news_qs.exists(): + raise serializers.ValidationError({'detail': _('Object not found.')}) + else: + news = news_qs.first() + + # Check existence in favorites + if news.favorites.filter(user=self.user).exists(): + raise utils_exceptions.FavoritesError() + + attrs['news'] = news + return attrs + + def create(self, validated_data, *args, **kwargs): + """Overridden create method""" + validated_data.update({ + 'user': self.user, + 'content_object': validated_data.pop('news') + }) + return super().create(validated_data) diff --git a/apps/news/tests.py b/apps/news/tests.py index 77dbca8e..532a6efc 100644 --- a/apps/news/tests.py +++ b/apps/news/tests.py @@ -9,6 +9,8 @@ from news.models import NewsType, News from account.models import User, Role, UserRole from translation.models import Language from location.models import Country + + # Create your tests here. @@ -67,7 +69,7 @@ class NewsTestCase(BaseTestCase): super().setUp() def test_news_post(self): - test_news ={ + test_news = { "title": {"en-GB": "Test news POST"}, "news_type_id": self.test_news_type.id, "description": {"en-GB": "Description test news"}, @@ -108,9 +110,21 @@ class NewsTestCase(BaseTestCase): 'description': {"en-GB": "Description test news!"}, 'slug': self.test_news.slug, 'start': self.test_news.start, - 'news_type_id':self.test_news.news_type_id, + 'news_type_id': self.test_news.news_type_id, 'country_id': self.country_ru.id } response = self.client.put(url, data=data, format='json') - self.assertEqual(response.status_code, status.HTTP_200_OK) \ No newline at end of file + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_web_favorite_create_delete(self): + data = { + "user": self.user.id, + "object_id": self.test_news.id + } + + response = self.client.post(f'/api/web/news/slug/{self.test_news.slug}/favorites/', data=data) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + + response = self.client.delete(f'/api/web/news/slug/{self.test_news.slug}/favorites/', format='json') + self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) diff --git a/apps/news/urls/web.py b/apps/news/urls/web.py index 80fcf072..fdfe8a66 100644 --- a/apps/news/urls/web.py +++ b/apps/news/urls/web.py @@ -8,4 +8,5 @@ urlpatterns = [ path('', views.NewsListView.as_view(), name='list'), path('types/', views.NewsTypeListView.as_view(), name='type'), path('slug//', views.NewsDetailView.as_view(), name='rud'), + path('slug//favorites/', views.NewsFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites') ] diff --git a/apps/news/views.py b/apps/news/views.py index c65c5297..6c2374bc 100644 --- a/apps/news/views.py +++ b/apps/news/views.py @@ -20,8 +20,8 @@ class NewsMixinView: def get_queryset(self, *args, **kwargs): """Override get_queryset method.""" qs = models.News.objects.published() \ - .with_base_related() \ - .order_by('-is_highlighted', '-created') + .with_base_related() \ + .order_by('-is_highlighted', '-created') country_code = self.request.country_code if country_code: qs = qs.by_country_code(country_code) @@ -51,7 +51,7 @@ class NewsTypeListView(generics.ListAPIView): """NewsType list view.""" pagination_class = None - permission_classes = (permissions.AllowAny, ) + permission_classes = (permissions.AllowAny,) queryset = models.NewsType.objects.all() serializer_class = serializers.NewsTypeSerializer @@ -70,7 +70,7 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView, serializer_class = serializers.NewsBackOfficeBaseSerializer create_serializers_class = serializers.NewsBackOfficeDetailSerializer - permission_classes = [IsCountryAdmin|IsContentPageManager] + permission_classes = [IsCountryAdmin | IsContentPageManager] def get_serializer_class(self): """Override serializer class.""" @@ -146,9 +146,26 @@ class NewsBackOfficeRUDView(NewsBackOfficeMixinView, """Resource for detailed information about news for back-office users.""" serializer_class = serializers.NewsBackOfficeDetailSerializer - permission_classes = [IsCountryAdmin|IsContentPageManager] + permission_classes = [IsCountryAdmin | IsContentPageManager] def get(self, request, pk, *args, **kwargs): add_rating(remote_addr=request.META.get('REMOTE_ADDR'), pk=pk, model='news', app_label='news') return self.retrieve(request, *args, **kwargs) + + +class NewsFavoritesCreateDestroyView(generics.CreateAPIView, generics.DestroyAPIView): + """View for create/destroy news from favorites.""" + + serializer_class = serializers.NewsFavoritesCreateSerializer + lookup_field = 'slug' + + def get_object(self): + """ + Returns the object the view is displaying. + """ + news = get_object_or_404(models.News, slug=self.kwargs['slug']) + favorites = get_object_or_404(news.favorites.filter(user=self.request.user)) + # May raise a permission denied + self.check_object_permissions(self.request, favorites) + return favorites