From 66a0fef6bbbf0532a1987dddb1d64d44de96641e Mon Sep 17 00:00:00 2001 From: gzbender Date: Wed, 29 Aug 2018 19:10:36 +0500 Subject: [PATCH] =?UTF-8?q?LIL-642=20=D0=9D=D0=B5=20=D1=83=D1=87=D0=B8?= =?UTF-8?q?=D1=82=D1=8B=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B3=D0=BE=D0=BB=D0=BE?= =?UTF-8?q?=D1=81=D0=B0=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=B9=20(is=5Factive=20false)=20=D0=B2=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BD=D0=BA=D1=83=D1=80=D1=81=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/serializers/contest.py | 15 ++++++++---- api/v1/serializers/course.py | 21 +++------------- api/v1/views.py | 24 +++++++++++++++++++ apps/content/models.py | 7 ++++++ .../templates/content/contest_work.html | 2 +- apps/content/views.py | 8 ++++--- apps/school/templates/summer/promo.html | 2 +- project/templates/blocks/about.html | 2 +- project/urls.py | 2 +- web/src/components/ContestWorks.vue | 8 +++++-- web/src/components/blocks/Likes.vue | 9 ++++++- 11 files changed, 68 insertions(+), 32 deletions(-) diff --git a/api/v1/serializers/contest.py b/api/v1/serializers/contest.py index dc5b88fd..9d2e63c4 100644 --- a/api/v1/serializers/contest.py +++ b/api/v1/serializers/contest.py @@ -1,3 +1,4 @@ +from django.contrib.auth import get_user_model from rest_framework import serializers from api.v1.serializers.content import ContentSerializer, ContentCreateSerializer, ImageObjectSerializer @@ -5,6 +6,8 @@ from api.v1.serializers.mixins import DispatchContentMixin from apps.content.models import (Contest, ContestWork) +User = get_user_model() + class ContestSerializer(serializers.ModelSerializer): cover = ImageObjectSerializer() @@ -12,7 +15,8 @@ class ContestSerializer(serializers.ModelSerializer): class Meta: model = Contest - fields = '__all__' + fields = ['title', 'description', 'slug', 'cover', + 'date_start', 'date_end', 'active', 'content', 'finished'] class ContestCreateSerializer(DispatchContentMixin, serializers.ModelSerializer): @@ -52,11 +56,14 @@ class ContestWorkSerializer(serializers.ModelSerializer): 'created_at', 'likes', 'user_liked', 'img_width', 'img_height'] def get_likes(self, instance): - return instance.likes.count() + return instance.likes.filter(user__is_active=True).count() def get_user_liked(self, instance): - user = self.context['request'].user - return instance.likes.filter(user=user).exists() if user.is_authenticated else False + # FIXME + user = self.context['request'].query_params.get('current_user') + if user: + user = User.objects.get(pk=user) + return instance.likes.filter(user=user).exists() if user else False class ContestWorkCreateSerializer(serializers.ModelSerializer): diff --git a/api/v1/serializers/course.py b/api/v1/serializers/course.py index fe06ca53..4382aae4 100644 --- a/api/v1/serializers/course.py +++ b/api/v1/serializers/course.py @@ -71,14 +71,10 @@ class LikeSerializer(serializers.ModelSerializer): class LikeCreateSerializer(serializers.ModelSerializer): - OBJ_TYPE_CONTEST_WORK = 'contest_work' - - obj_type = serializers.CharField(required=True) - obj_id = serializers.IntegerField(required=True) class Meta: model = Like - fields = ['user', 'obj_type', 'obj_id'] + fields = ['user'] def create(self, validated_data): # FIXME @@ -86,20 +82,9 @@ class LikeCreateSerializer(serializers.ModelSerializer): user = validated_data.get('user') else: user = self.context['request'].user - if not user: # FIXME and user.is_authenticated): - return Like() - obj_type = validated_data.pop('obj_type') - obj_id = validated_data.pop('obj_id') client_ip, is_routable = get_client_ip(self.context['request']) - if obj_type == self.OBJ_TYPE_CONTEST_WORK: - contest_work = ContestWork.objects.get(pk=obj_id) - # FIXME in prod: fixed - if contest_work.user == user or contest_work.likes.filter(user=user).exists(): - # if contest_work.likes.filter(user=user).exists(): - return Like() - like = Like.objects.create(user=user, ip=client_ip) - contest_work.likes.add(like) - return like + like = Like.objects.create(user=user, ip=client_ip) + return like def to_representation(self, instance): return LikeSerializer(instance, context=self.context).to_representation(instance) diff --git a/api/v1/views.py b/api/v1/views.py index cfe857fb..2389a4db 100644 --- a/api/v1/views.py +++ b/api/v1/views.py @@ -131,6 +131,8 @@ class MaterialViewSet(ExtendedModelViewSet): class LikeViewSet(ExtendedModelViewSet): + OBJ_TYPE_CONTEST_WORK = 'contest_work' + queryset = Like.objects.select_related('user').all() serializer_class = LikeCreateSerializer serializer_class_map = { @@ -143,6 +145,28 @@ class LikeViewSet(ExtendedModelViewSet): # FIXME authentication_classes = [] + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + obj_type = request.data.get('obj_type') + obj_id = request.data.get('obj_id') + user = serializer.validated_data.get('user') + if not user.is_active: # FIXME and user.is_authenticated): + return Response(status=status.HTTP_403_FORBIDDEN) + if obj_type == self.OBJ_TYPE_CONTEST_WORK: + contest_work = ContestWork.objects.get(pk=obj_id) + if contest_work.user == user: + return Response({'error': u'Нельзя голосовать за свою работу'}, status=status.HTTP_400_BAD_REQUEST) + if contest_work.likes.filter(user=user).exists(): + return Response({'error': u'Вы уже голосовали за эту работу'}, status=status.HTTP_400_BAD_REQUEST) + if contest_work.contest.finished: + return Response({'error': u'Голосование закончено'}, status=status.HTTP_400_BAD_REQUEST) + instance = serializer.save() + if obj_type == self.OBJ_TYPE_CONTEST_WORK: + contest_work.likes.add(instance) + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + class CategoryViewSet(ExtendedModelViewSet): queryset = Category.objects.order_by('-id') diff --git a/apps/content/models.py b/apps/content/models.py index 197e1e7d..1fec0880 100644 --- a/apps/content/models.py +++ b/apps/content/models.py @@ -1,7 +1,10 @@ +from datetime import datetime, time from urllib.parse import urlparse +from django.conf import settings from django.db import models from django.contrib.auth import get_user_model from django.urls import reverse_lazy +from django.utils import timezone from imagekit.models import ImageSpecField from imagekit.processors import ResizeToCover @@ -167,6 +170,10 @@ class Contest(models.Model): active = models.BooleanField(default=True) # TODO? baner + @property + def finished(self): + return datetime(2018, 8, 29, 21) < timezone.now() + def save(self, *args, **kwargs): if self.active: Contest.objects.filter(active=True).update(active=False) diff --git a/apps/content/templates/content/contest_work.html b/apps/content/templates/content/contest_work.html index 5184faae..e4ade33d 100644 --- a/apps/content/templates/content/contest_work.html +++ b/apps/content/templates/content/contest_work.html @@ -35,7 +35,7 @@
+ {% if user_liked %}:user-liked="true"{% endif %} likes="{{ likes_count }}">
diff --git a/apps/content/views.py b/apps/content/views.py index ff3a4deb..4d350cca 100644 --- a/apps/content/views.py +++ b/apps/content/views.py @@ -14,10 +14,11 @@ from apps.course.models import ContestWorkComment @method_decorator(login_required, name='dispatch') class ContestEditView(TemplateView): template_name = 'content/contest_edit.html' + query_pk_and_slug = True - def get(self, request, pk=None, lesson=None): - if pk: - self.object = get_object_or_404(Contest, pk=pk) + def get(self, request, slug=None, lesson=None): + if slug: + self.object = get_object_or_404(Contest, slug=slug) else: self.object = Contest() @@ -58,6 +59,7 @@ class ContestWorkView(DetailView): context['user_liked'] = self.object.likes.filter(user=self.request.user).exists() \ if self.request.user.is_authenticated else False + context['likes_count'] = self.object.likes.filter(user__is_active=True).count() return context diff --git a/apps/school/templates/summer/promo.html b/apps/school/templates/summer/promo.html index a07fc442..7878c9ef 100644 --- a/apps/school/templates/summer/promo.html +++ b/apps/school/templates/summer/promo.html @@ -46,7 +46,7 @@ -
12 уроков
+
7 дисциплин
В разных техниках
diff --git a/project/templates/blocks/about.html b/project/templates/blocks/about.html index c25391cd..de379799 100644 --- a/project/templates/blocks/about.html +++ b/project/templates/blocks/about.html @@ -30,7 +30,7 @@
-
12 уроков
+
7 дисциплин
В разных техниках
diff --git a/project/urls.py b/project/urls.py index 9e6f5992..60a492c4 100644 --- a/project/urls.py +++ b/project/urls.py @@ -84,7 +84,7 @@ urlpatterns = [ path('school/', include(('apps.school.urls', 'school'))), path('test', TemplateView.as_view(template_name='templates/lilcity/test.html'), name='test'), path('contest/create', ContestEditView.as_view(), name='contest_create'), - path('contest//edit', ContestEditView.as_view(), name='contest_edit'), + path('contest//edit', ContestEditView.as_view(), name='contest_edit'), path('contest//', ContestView.as_view(), name='contest'), path('contest-work//', ContestWorkView.as_view(), name='contest_work'), path('contest-work//comment', contest_work_comment, name='contest_work_comment'), diff --git a/web/src/components/ContestWorks.vue b/web/src/components/ContestWorks.vue index 18bb1fc8..c9d377b7 100644 --- a/web/src/components/ContestWorks.vue +++ b/web/src/components/ContestWorks.vue @@ -61,8 +61,12 @@ methods: { load() { this.loading = true; - api.get(`/api/v1/contest-works/?contest=${this.contestId}&page=${this.page}`) - .then((response) => { + api.get(`/api/v1/contest-works/?contest=${this.contestId}&page=${this.page}¤t_user=${this.$root.store.user.id}`, { + headers: { + 'Authorization': `Token ${this.$root.store.accessToken}`, + } + }) + .then(response => { this.loading = false; this.loaded = true; if(this.page > 1){ diff --git a/web/src/components/blocks/Likes.vue b/web/src/components/blocks/Likes.vue index d1807254..8b3ef4c8 100644 --- a/web/src/components/blocks/Likes.vue +++ b/web/src/components/blocks/Likes.vue @@ -10,6 +10,7 @@