posts are done

This commit is contained in:
2026-05-19 00:08:02 +02:00
parent 202ce22102
commit 2e9e3ed41b
35 changed files with 1528 additions and 272 deletions

View File

@@ -9,7 +9,7 @@ from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiPara
from rest_framework.permissions import IsAuthenticated
from social.hubs.models import Tags
from vontor_cz.pagination import CreatedCursorPagination
from .models import Post, PostContent, PostVote
from .models import Post, PostContent, PostVote, PostSave
from .permissions import CanDeletePost, IsPostAuthorOnly
from .serializers import PostSerializer, PostContentSerializer, PostVoteSerializer, TagAttachSerializer
@@ -67,7 +67,7 @@ class PostViewSet(viewsets.ModelViewSet):
qs = (
Post.objects
.select_related('author', 'hub')
.prefetch_related('tags', 'contents', 'votes')
.prefetch_related('tags', 'contents', 'votes', 'saves')
.annotate(reply_count=Count('replies', distinct=True))
)
hub_id = self.request.query_params.get('hub')
@@ -196,7 +196,7 @@ class PostViewSet(viewsets.ModelViewSet):
base_qs = (
Post.objects
.select_related('author', 'hub')
.prefetch_related('tags', 'contents', 'votes')
.prefetch_related('tags', 'contents', 'votes', 'saves')
.annotate(reply_count=Count('replies', distinct=True))
.filter(reply_to__isnull=True)
)
@@ -241,3 +241,45 @@ class PostViewSet(viewsets.ModelViewSet):
defaults={'vote': ser.validated_data['vote']},
)
return Response(PostVoteSerializer(vote_obj).data)
# ------------------------------------------------------------------
# Save / unsave action
# ------------------------------------------------------------------
@extend_schema(
tags=["posts"],
summary="Toggle save on a post",
description="Saves the post for the current user, or unsaves it if already saved. Returns `{saved: true/false}`.",
responses={200: {'type': 'object', 'properties': {'saved': {'type': 'boolean'}}}},
)
@action(detail=True, methods=['post'], url_path='save')
def save_post(self, request, pk=None):
post = self.get_object()
obj, created = PostSave.objects.get_or_create(post=post, user=request.user)
if not created:
obj.delete()
return Response({'saved': created})
# ------------------------------------------------------------------
# Saved feed
# ------------------------------------------------------------------
@extend_schema(
tags=["posts"],
summary="List posts saved by the current user",
responses={200: PostSerializer(many=True)},
)
@action(detail=False, methods=['get'], url_path='saved')
def saved(self, request):
qs = (
Post.objects
.select_related('author', 'hub')
.prefetch_related('tags', 'contents', 'votes', 'saves')
.annotate(reply_count=Count('replies', distinct=True))
.filter(saves__user=request.user)
.order_by('-saves__created_at')
)
paginator = CreatedCursorPagination()
page = paginator.paginate_queryset(qs, request, view=self)
ser = PostSerializer(page, many=True, context={'request': request})
return paginator.get_paginated_response(ser.data)