diff --git a/src/chats/models.py b/src/chats/models.py index 52bd67a..47d9140 100644 --- a/src/chats/models.py +++ b/src/chats/models.py @@ -5,9 +5,11 @@ TimeCreateUpdateModel, AccountForeignModel, ) - +from django.contrib.contenttypes.fields import GenericRelation # TODO: change folder path + + def get_group_preview_file_path(instance, *_, **__) -> str: return instance.created.strftime("uploads/chat_previews/%Y/%m/%d/") + str(instance.id) # type: ignore @@ -125,8 +127,8 @@ class Message(UUIDModel, TimeCreateModel, AccountForeignModel): upload_to=get_message_img_file_path, null=True ) # TODO: added extra models FK viewed = models.BooleanField(default=False) - reactions = models.ManyToManyField("reactions.Reaction", related_name="messages") - + reactions = models.ManyToManyField("reactions.ReactionLike", related_name="messages") + like = GenericRelation("reactions.ReactionLike") objects = models.Manager() message_manager = MessageManager() diff --git a/src/profiles/models.py b/src/profiles/models.py index 758c99f..0583aca 100644 --- a/src/profiles/models.py +++ b/src/profiles/models.py @@ -1,11 +1,9 @@ from typing import Optional - from django.db import models from django.urls import reverse from django.conf import settings from service.models import UUIDModel, TimeCreateUpdateModel, AccountOneToOneModel - # choices for Profile.sex field SEX_CHOICES = (("Не выбран", "Не выбран"), ("Мужской", "Мужской"), ("Женский", "Женский"), ("Другой", "Другой")) @@ -74,8 +72,7 @@ class Post(UUIDModel, TimeCreateUpdateModel): # type: ignore photo = models.ImageField( upload_to="uploads/post_img/", verbose_name="Фото", blank=True, null=True ) # TODO add table Post Images - reactions = models.ManyToManyField("reactions.Reaction", related_name="posts") - + reactions = models.ManyToManyField("reactions.ReactionLike", related_name="posts") objects = models.Manager() post_manager = PostManager() diff --git a/src/reactions/mixins.py b/src/reactions/mixins.py new file mode 100644 index 0000000..7e9b697 --- /dev/null +++ b/src/reactions/mixins.py @@ -0,0 +1,34 @@ +from rest_framework.decorators import action +from rest_framework.response import Response +from rest_framework.permissions import AllowAny + +from reactions.serializers import FanSerializer +from reactions.services import add_like, remove_like, get_fans + + +class ReactionsdMixin: + @action(detail=True, methods=['post'], + url_path='like/(P[a-z0-9]+)', + permission_classes=[AllowAny]) + def like(self, request, pk=None, reaction_pk=None): + obj = self.get_object() + reaction_id = self.kwargs['reaction_pk'] + add_like(obj, request.user, reaction_id) + + return Response() + + @action(detail=True, methods=['delete'], url_name='unlike', + url_path='unlike/(?P[a-z0-9]+)', + permission_classes=[AllowAny]) + def unlike(self, request, pk=None, reaction_pk=None): + obj = self.get_object() + reaction_id = self.kwargs['reaction_pk'] + remove_like(obj, request.user, reaction_id) + return Response() + + @action(detail=True, methods=['get'], ) + def get_fans(self, request, pk=None, reaction_pk=None, permission_classes=[AllowAny]): + obj = self.get_object() + fans = get_fans(obj, request.user) + serializer = FanSerializer(fans, many=True) + return Response(serializer.data) diff --git a/src/reactions/models.py b/src/reactions/models.py index e036f4d..76711c2 100644 --- a/src/reactions/models.py +++ b/src/reactions/models.py @@ -1,10 +1,11 @@ from django.db import models - +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.models import ContentType from users.models import Account from service.models import UUIDModel -class Reaction(UUIDModel): +class ReactionLike(UUIDModel): owner = models.ForeignKey( Account, on_delete=models.PROTECT, @@ -16,8 +17,9 @@ class Reaction(UUIDModel): on_delete=models.CASCADE, verbose_name="Варианты реакций из определенного списка", ) - - objects = models.Manager() + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + object_id = models.PositiveIntegerField() + content_object = GenericForeignKey('content_type', 'object_id') class Meta: verbose_name = "Реакция пользователя на пост/сообщение" diff --git a/src/reactions/serializers.py b/src/reactions/serializers.py index 66ee48c..ffd4e7e 100644 --- a/src/reactions/serializers.py +++ b/src/reactions/serializers.py @@ -1,8 +1,8 @@ from rest_framework import serializers from rest_framework.serializers import ModelSerializer -from .fields import Base64ImageField -from .models import Reaction, ReactionItem +from reactions.fields import Base64ImageField +from reactions.models import ReactionLike, ReactionItem class ReactionItemSerializer(ModelSerializer): @@ -18,5 +18,20 @@ class ReactionSerializer(ModelSerializer): owner = serializers.StringRelatedField(many=True, read_only=True) class Meta: - model = Reaction + model = ReactionLike fields = ('id', 'reaction_option', 'owner') + + +class FanSerializer(serializers.ModelSerializer): + content_type = serializers.CharField(source="content_type.name") + content_object = serializers.CharField(source="content_object.id") + + class Meta: + model = ReactionLike + fields = ( + 'id', + 'owner ', + 'content_type', + 'content_object', + 'ReactionItem' + ) diff --git a/src/reactions/services.py b/src/reactions/services.py new file mode 100644 index 0000000..24bf7dc --- /dev/null +++ b/src/reactions/services.py @@ -0,0 +1,28 @@ +from django.contrib.contenttypes.models import ContentType +from reactions.models import ReactionLike + + +def add_like(obj, user, reaction_id=None): + obj_type = ContentType.objects.get_for_model(obj) + like = ReactionLike.objects.get_or_create(content_type=obj_type, + object_id=obj.id, user=user, reaction=reaction_id) + + return like + + +def remove_like(obj, user, reaction_id=None): + obj_type = ContentType.objects.get_for_model(obj) + ReactionLike.objects.filter(content_type=obj_type, object_id=obj.id, + user=user, reaction=reaction_id).delete() + + +def is_fan(obj, user): + obj_type = ContentType.objects.get_for_model(obj) + likes = ReactionLike.objects.filter(content_type=obj_type, + object_id=obj.id, user=user) + + return likes.exists() + + +def get_fans(obj, user): + return ReactionLike.objects.filter(object_id=obj.id, user=user) diff --git a/src/reactions/views.py b/src/reactions/views.py index 352f890..e1046d7 100644 --- a/src/reactions/views.py +++ b/src/reactions/views.py @@ -1,8 +1,8 @@ from rest_framework import mixins, viewsets from rest_framework.permissions import IsAdminUser, IsAuthenticated -from .models import Reaction, ReactionItem -from .serializers import ReactionItemSerializer, ReactionSerializer +from reactions.models import ReactionLike, ReactionItem +from reactions.serializers import ReactionItemSerializer, ReactionSerializer class ReactionItemViewSet(viewsets.ModelViewSet): @@ -13,6 +13,6 @@ class ReactionItemViewSet(viewsets.ModelViewSet): class ReactionViewSet(mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): - queryset = Reaction.objects.all() + queryset = ReactionLike.objects.all() serializer_class = ReactionSerializer permission_classes = [IsAuthenticated]