Use hub 'name' in routes & add top-post sorting
Switch hub endpoints to use the hub `name` slug and update frontend routes/clients accordingly. Backend: HubViewSet now uses lookup_field='name'; PostViewSet list supports `sort=top` with vote_score annotation and time windows/custom ranges, and a new TopPostsCursorPagination was added. Frontend: routes changed from `/hub/:id` to `/h/:name`, the generated hubs API was updated from id->name, and the hub feed client accepts `sort`, `time`, `start`, and `end` params (query key updated). Also adds new homepage UI components (HeroSection, DroneSection) and navbar improvements (scroll state, auto-close mobile menu on route changes, and small icon/class tweaks).
This commit is contained in:
@@ -58,6 +58,7 @@ from .serializers import HubPermissionSerializer, HubSerializer, TagsSerializer,
|
||||
class HubViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = HubSerializer
|
||||
permission_classes = [CanEditHub]
|
||||
lookup_field = 'name'
|
||||
filterset_fields = ['is_public', 'owner']
|
||||
search_fields = ['name', 'description']
|
||||
ordering_fields = ['name']
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
from django.db.models import Count, Q
|
||||
from datetime import timedelta
|
||||
|
||||
from django.db.models import Count, Q, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.utils import timezone
|
||||
from rest_framework import status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied, ValidationError
|
||||
@@ -8,7 +12,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 vontor_cz.pagination import CreatedCursorPagination, TopPostsCursorPagination
|
||||
from .models import Post, PostContent, PostVote, PostSave
|
||||
from .permissions import CanDeletePost, IsPostAuthorOnly
|
||||
from .serializers import PostSerializer, PostContentSerializer, PostVoteSerializer, TagAttachSerializer
|
||||
@@ -78,6 +82,51 @@ class PostViewSet(viewsets.ModelViewSet):
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(author=self.request.user)
|
||||
|
||||
_TIME_WINDOWS = {
|
||||
'1h': timedelta(hours=1),
|
||||
'6h': timedelta(hours=6),
|
||||
'day': timedelta(days=1),
|
||||
'week': timedelta(weeks=1),
|
||||
'month': timedelta(days=30),
|
||||
'year': timedelta(days=365),
|
||||
}
|
||||
|
||||
def _get_cutoff(self, time_param):
|
||||
"""Return a datetime cutoff for the given time window, or None for 'all'."""
|
||||
if time_param in self._TIME_WINDOWS:
|
||||
return timezone.now() - self._TIME_WINDOWS[time_param]
|
||||
return None
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
sort = request.query_params.get('sort', 'newest')
|
||||
time_param = request.query_params.get('time', 'all')
|
||||
|
||||
qs = self.filter_queryset(self.get_queryset())
|
||||
|
||||
# Time filter
|
||||
if time_param == 'custom':
|
||||
start = request.query_params.get('start')
|
||||
end = request.query_params.get('end')
|
||||
if start:
|
||||
qs = qs.filter(created_at__date__gte=start)
|
||||
if end:
|
||||
qs = qs.filter(created_at__date__lte=end)
|
||||
else:
|
||||
cutoff = self._get_cutoff(time_param)
|
||||
if cutoff:
|
||||
qs = qs.filter(created_at__gte=cutoff)
|
||||
|
||||
if sort == 'top':
|
||||
qs = qs.annotate(vote_score=Coalesce(Sum('votes__vote'), 0)).order_by('-vote_score', '-id')
|
||||
paginator = TopPostsCursorPagination()
|
||||
else:
|
||||
qs = qs.order_by('-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)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Media upload action
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user