From f86357e0417308e208871205d492500eb9d6743e Mon Sep 17 00:00:00 2001 From: Anatoly Date: Wed, 15 Jan 2020 22:31:17 +0300 Subject: [PATCH] fix comments --- .../commands/add_status_to_comments.py | 18 +++++++++ .../comment/migrations/0008_comment_status.py | 18 +++++++++ apps/comment/models.py | 38 ++++++++++++++++++- apps/comment/serializers/common.py | 23 ++++------- apps/comment/transfer_data.py | 1 + apps/establishment/serializers/common.py | 16 +++++--- apps/establishment/views/web.py | 8 ++-- apps/product/serializers/common.py | 16 +++++--- apps/product/views/common.py | 10 ++--- apps/transfer/serializers/comments.py | 16 +++++++- 10 files changed, 124 insertions(+), 40 deletions(-) create mode 100644 apps/comment/management/commands/add_status_to_comments.py create mode 100644 apps/comment/migrations/0008_comment_status.py diff --git a/apps/comment/management/commands/add_status_to_comments.py b/apps/comment/management/commands/add_status_to_comments.py new file mode 100644 index 00000000..932e80df --- /dev/null +++ b/apps/comment/management/commands/add_status_to_comments.py @@ -0,0 +1,18 @@ +from django.core.management.base import BaseCommand +from comment.models import Comment +from tqdm import tqdm + + +class Command(BaseCommand): + help = 'Add status to comments from is_publish_ flag.' + + def handle(self, *args, **kwargs): + to_update = [] + + for comment in tqdm(Comment.objects.all()): + if hasattr(comment, 'is_publish') and hasattr(comment, 'status'): + comment.status = Comment.PUBLISHED if comment.is_publish else Comment.WAITING + to_update.append(comment) + + Comment.objects.bulk_update(to_update, ('status', )) + self.stdout.write(self.style.WARNING(f'Updated {len(to_update)} objects.')) diff --git a/apps/comment/migrations/0008_comment_status.py b/apps/comment/migrations/0008_comment_status.py new file mode 100644 index 00000000..8441d81e --- /dev/null +++ b/apps/comment/migrations/0008_comment_status.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.7 on 2020-01-15 13:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('comment', '0007_comment_site'), + ] + + operations = [ + migrations.AddField( + model_name='comment', + name='status', + field=models.PositiveSmallIntegerField(choices=[(0, 'Waiting'), (1, 'Published'), (2, 'Rejected'), (3, 'Deleted')], default=0, verbose_name='status'), + ), + ] diff --git a/apps/comment/models.py b/apps/comment/models.py index fa27d3f9..7844b29c 100644 --- a/apps/comment/models.py +++ b/apps/comment/models.py @@ -16,6 +16,10 @@ class CommentQuerySet(ContentTypeQuerySetMixin): """Return comments by author""" return self.filter(user=user) + def published(self): + """Return only published comments.""" + return self.filter(status=self.model.PUBLISHED) + def annotate_is_mine_status(self, user): """Annotate belonging status""" return self.annotate(is_mine=models.Case( @@ -27,16 +31,48 @@ class CommentQuerySet(ContentTypeQuerySetMixin): output_field=models.BooleanField() )) + def public(self, user): + """ + Return QuerySet by rules: + 1 With status PUBLISHED + 2 With status WAITING if comment author is + """ + qs = self.published() + if isinstance(user, User): + waiting_ids = list( + self.filter(status=self.model.WAITING, user=user) + .values_list('id', flat=True)) + published_ids = list(qs.values_list('id', flat=True)) + waiting_ids.extend(published_ids) + qs = self.filter(id__in=tuple(waiting_ids)) + return qs + class Comment(ProjectBaseMixin): """Comment model.""" + + WAITING = 0 + PUBLISHED = 1 + REJECTED = 2 + DELETED = 3 + + STATUSES = ( + (WAITING, _('Waiting')), + (PUBLISHED, _('Published')), + (REJECTED, _('Rejected')), + (DELETED, _('Deleted')), + ) + text = models.TextField(verbose_name=_('Comment text')) mark = models.PositiveIntegerField(blank=True, null=True, default=None, verbose_name=_('Mark')) user = models.ForeignKey('account.User', related_name='comments', on_delete=models.CASCADE, verbose_name=_('User')) old_id = models.IntegerField(null=True, blank=True, default=None) is_publish = models.BooleanField(default=False, verbose_name=_('Publish status')) + status = models.PositiveSmallIntegerField(choices=STATUSES, + default=WAITING, + verbose_name=_('status')) site = models.ForeignKey('main.SiteSettings', blank=True, null=True, - on_delete=models.SET_NULL, verbose_name=_('site')) + on_delete=models.SET_NULL, verbose_name=_('site')) content_type = models.ForeignKey(generic.ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') diff --git a/apps/comment/serializers/common.py b/apps/comment/serializers/common.py index 8e35d3dc..1060f47f 100644 --- a/apps/comment/serializers/common.py +++ b/apps/comment/serializers/common.py @@ -4,13 +4,15 @@ from rest_framework import serializers from comment.models import Comment -class CommentSerializer(serializers.ModelSerializer): +class CommentBaseSerializer(serializers.ModelSerializer): """Comment serializer""" nickname = serializers.CharField(read_only=True, source='user.username') is_mine = serializers.BooleanField(read_only=True) profile_pic = serializers.URLField(read_only=True, source='user.cropped_image_url') + status_display = serializers.CharField(read_only=True, + source='get_status_display') class Meta: """Serializer for model Comment""" @@ -23,19 +25,10 @@ class CommentSerializer(serializers.ModelSerializer): 'text', 'mark', 'nickname', - 'profile_pic' - ] - - -class CommentRUDSerializer(CommentSerializer): - """Retrieve/Update/Destroy comment serializer.""" - class Meta(CommentSerializer.Meta): - """Meta class.""" - fields = [ - 'id', - 'created', - 'text', - 'mark', - 'nickname', 'profile_pic', + 'status', + 'status_display', ] + extra_kwargs = { + 'status': {'read_only': True}, + } diff --git a/apps/comment/transfer_data.py b/apps/comment/transfer_data.py index c9d07585..a03cd163 100644 --- a/apps/comment/transfer_data.py +++ b/apps/comment/transfer_data.py @@ -20,6 +20,7 @@ def transfer_comments(): 'mark', 'establishment_id', 'account_id', + 'state', ) serialized_data = CommentSerializer(data=list(queryset.values()), many=True) diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 1d0317f4..9ce576e5 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -450,7 +450,7 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer): class MobileEstablishmentDetailSerializer(EstablishmentDetailSerializer): """Serializer for Establishment model for mobiles.""" - last_comment = comment_serializers.CommentRUDSerializer(allow_null=True) + last_comment = comment_serializers.CommentBaseSerializer(allow_null=True) class Meta(EstablishmentDetailSerializer.Meta): """Meta class.""" @@ -482,13 +482,11 @@ class EstablishmentSimilarSerializer(EstablishmentBaseSerializer): ] -class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer): +class EstablishmentCommentBaseSerializer(comment_serializers.CommentBaseSerializer): """Create comment serializer""" - mark = serializers.IntegerField() - class Meta: + class Meta(comment_serializers.CommentBaseSerializer.Meta): """Serializer for model Comment""" - model = comment_models.Comment fields = [ 'id', 'created', @@ -496,8 +494,14 @@ class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer 'mark', 'nickname', 'profile_pic', + 'status', + 'status_display', ] + +class EstablishmentCommentCreateSerializer(EstablishmentCommentBaseSerializer): + """Extended EstablishmentCommentBaseSerializer.""" + def validate(self, attrs): """Override validate method""" # Check establishment object @@ -517,7 +521,7 @@ class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer return super().create(validated_data) -class EstablishmentCommentRUDSerializer(comment_serializers.CommentSerializer): +class EstablishmentCommentRUDSerializer(comment_serializers.CommentBaseSerializer): """Retrieve/Update/Destroy comment serializer.""" class Meta: diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index a84c5647..6ce8428b 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -5,7 +5,6 @@ from django.shortcuts import get_object_or_404 from rest_framework import generics, permissions from comment import models as comment_models -from comment.serializers import CommentRUDSerializer from establishment import filters, models, serializers from main import methods from utils.pagination import PortionPagination @@ -188,18 +187,17 @@ class EstablishmentCommentListView(generics.ListAPIView): """View for return list of establishment comments.""" permission_classes = (permissions.AllowAny,) - serializer_class = serializers.EstablishmentCommentCreateSerializer + serializer_class = serializers.EstablishmentCommentBaseSerializer def get_queryset(self): """Override get_queryset method""" - establishment = get_object_or_404(models.Establishment, slug=self.kwargs['slug']) - return establishment.comments.order_by('-created') + return establishment.comments.public(self.request.user).order_by('-created') class EstablishmentCommentRUDView(generics.RetrieveUpdateDestroyAPIView): """View for retrieve/update/destroy establishment comment.""" - serializer_class = CommentRUDSerializer + serializer_class = serializers.EstablishmentCommentBaseSerializer queryset = models.Establishment.objects.all() def get_object(self): diff --git a/apps/product/serializers/common.py b/apps/product/serializers/common.py index e85bebe9..63766f69 100644 --- a/apps/product/serializers/common.py +++ b/apps/product/serializers/common.py @@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from comment.models import Comment -from comment.serializers import CommentSerializer +from comment.serializers import CommentBaseSerializer from establishment.serializers import EstablishmentProductShortSerializer from establishment.serializers.common import _EstablishmentAddressShortSerializer from location.serializers import WineOriginRegionBaseSerializer,\ @@ -200,13 +200,11 @@ class ProductFavoritesCreateSerializer(FavoritesCreateSerializer): return super().create(validated_data) -class ProductCommentCreateSerializer(CommentSerializer): - """Create comment serializer""" - mark = serializers.IntegerField() +class ProductCommentBaseSerializer(CommentBaseSerializer): + """Create comment serializer.""" - class Meta: + class Meta(CommentBaseSerializer.Meta): """Serializer for model Comment""" - model = Comment fields = [ 'id', 'created', @@ -214,8 +212,14 @@ class ProductCommentCreateSerializer(CommentSerializer): 'mark', 'nickname', 'profile_pic', + 'status', + 'status_display', ] + +class ProductCommentCreateSerializer(ProductCommentBaseSerializer): + """Serializer for creating comments for product.""" + def validate(self, attrs): """Override validate method""" # Check product object diff --git a/apps/product/views/common.py b/apps/product/views/common.py index 8b0567b2..802d04bf 100644 --- a/apps/product/views/common.py +++ b/apps/product/views/common.py @@ -4,12 +4,10 @@ from django.shortcuts import get_object_or_404 from rest_framework import generics, permissions from comment.models import Comment -from comment.serializers import CommentRUDSerializer +from comment.serializers import CommentBaseSerializer from product import filters, serializers from product.models import Product, ProductType from utils.views import FavoritesCreateDestroyMixinView -from utils.pagination import PortionPagination -from django.conf import settings class ProductBaseView(generics.GenericAPIView): @@ -81,17 +79,17 @@ class ProductCommentListView(generics.ListAPIView): """View for return list of product comments.""" permission_classes = (permissions.AllowAny,) - serializer_class = serializers.ProductCommentCreateSerializer + serializer_class = serializers.ProductCommentBaseSerializer def get_queryset(self): """Override get_queryset method""" product = get_object_or_404(Product, slug=self.kwargs['slug']) - return product.comments.order_by('-created') + return product.comments.public(self.request.user).order_by('-created') class ProductCommentRUDView(generics.RetrieveUpdateDestroyAPIView): """View for retrieve/update/destroy product comment.""" - serializer_class = CommentRUDSerializer + serializer_class = serializers.ProductCommentBaseSerializer queryset = Product.objects.all() def get_object(self): diff --git a/apps/transfer/serializers/comments.py b/apps/transfer/serializers/comments.py index 73c90802..8322f89f 100644 --- a/apps/transfer/serializers/comments.py +++ b/apps/transfer/serializers/comments.py @@ -10,6 +10,7 @@ class CommentSerializer(serializers.Serializer): mark = serializers.DecimalField(max_digits=4, decimal_places=2, allow_null=True) account_id = serializers.IntegerField() establishment_id = serializers.CharField() + state = serializers.CharField() def validate(self, data): data.update({ @@ -18,14 +19,18 @@ class CommentSerializer(serializers.Serializer): 'mark': self.get_mark(data), 'content_object': self.get_content_object(data), 'user': self.get_account(data), + 'status': self.get_status(data), }) data.pop('establishment_id') data.pop('account_id') + data.pop('state') return data def create(self, validated_data): try: - return Comment.objects.create(**validated_data) + comment, _ = Comment.objects.get_or_create(old_id=validated_data.get('old_id'), + defaults=validated_data) + return comment except Exception as e: raise ValueError(f"Error creating comment with {validated_data}: {e}") @@ -48,3 +53,12 @@ class CommentSerializer(serializers.Serializer): if not data['mark']: return None return data['mark'] * -1 if data['mark'] < 0 else data['mark'] + + @staticmethod + def get_status(data): + if data.get('state'): + state = data.get('state') + if state == 'published': + return Comment.PUBLISHED + elif state == 'deleted': + return Comment.DELETED