|
|
@ -1,14 +1,46 @@ |
|
|
|
|
|
from django.db import transaction |
|
|
from django.db.models import Q |
|
|
from django.db.models import Q |
|
|
|
|
|
from rest_framework import status |
|
|
from rest_framework.authentication import TokenAuthentication |
|
|
from rest_framework.authentication import TokenAuthentication |
|
|
|
|
|
from rest_framework.decorators import action |
|
|
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser |
|
|
from rest_framework.parsers import FormParser, JSONParser, MultiPartParser |
|
|
from rest_framework.permissions import IsAuthenticated |
|
|
from rest_framework.permissions import IsAuthenticated |
|
|
from rest_framework.viewsets import ModelViewSet |
|
|
|
|
|
|
|
|
from rest_framework.response import Response |
|
|
|
|
|
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet |
|
|
|
|
|
|
|
|
from apps.account.permissions import IsSuperAdmin |
|
|
from apps.account.permissions import IsSuperAdmin |
|
|
from utils.pagination import StandardResultsSetPagination |
|
|
from utils.pagination import StandardResultsSetPagination |
|
|
|
|
|
|
|
|
from .models import Video |
|
|
|
|
|
from .serializers_admin import AdminVideoDetailSerializer, AdminVideoListSerializer |
|
|
|
|
|
|
|
|
from .models import PlaylistItem, Video, VideoCategory, VideoCollection, VideoPlaylist |
|
|
|
|
|
from .serializers_admin import ( |
|
|
|
|
|
AdminVideoCategorySerializer, |
|
|
|
|
|
AdminVideoCollectionSerializer, |
|
|
|
|
|
AdminVideoDetailSerializer, |
|
|
|
|
|
AdminVideoListSerializer, |
|
|
|
|
|
AdminVideoPlaylistDetailSerializer, |
|
|
|
|
|
AdminVideoPlaylistItemSerializer, |
|
|
|
|
|
AdminVideoPlaylistListSerializer, |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdminVideoCategoryViewSet(ReadOnlyModelViewSet): |
|
|
|
|
|
serializer_class = AdminVideoCategorySerializer |
|
|
|
|
|
permission_classes = [IsAuthenticated, IsSuperAdmin] |
|
|
|
|
|
authentication_classes = [TokenAuthentication] |
|
|
|
|
|
pagination_class = None |
|
|
|
|
|
|
|
|
|
|
|
def get_queryset(self): |
|
|
|
|
|
return VideoCategory.objects.all().order_by("title") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdminVideoCollectionViewSet(ReadOnlyModelViewSet): |
|
|
|
|
|
serializer_class = AdminVideoCollectionSerializer |
|
|
|
|
|
permission_classes = [IsAuthenticated, IsSuperAdmin] |
|
|
|
|
|
authentication_classes = [TokenAuthentication] |
|
|
|
|
|
pagination_class = None |
|
|
|
|
|
|
|
|
|
|
|
def get_queryset(self): |
|
|
|
|
|
return VideoCollection.objects.all().order_by("display_position", "order", "title") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdminVideoViewSet(ModelViewSet): |
|
|
class AdminVideoViewSet(ModelViewSet): |
|
|
@ -43,3 +75,113 @@ class AdminVideoViewSet(ModelViewSet): |
|
|
queryset = queryset.filter(video_type=video_type) |
|
|
queryset = queryset.filter(video_type=video_type) |
|
|
|
|
|
|
|
|
return queryset.order_by("-created_at") |
|
|
return queryset.order_by("-created_at") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AdminVideoPlaylistViewSet(ModelViewSet): |
|
|
|
|
|
permission_classes = [IsAuthenticated, IsSuperAdmin] |
|
|
|
|
|
authentication_classes = [TokenAuthentication] |
|
|
|
|
|
pagination_class = StandardResultsSetPagination |
|
|
|
|
|
parser_classes = (MultiPartParser, FormParser, JSONParser) |
|
|
|
|
|
|
|
|
|
|
|
def get_serializer_class(self): |
|
|
|
|
|
if self.action == "list": |
|
|
|
|
|
return AdminVideoPlaylistListSerializer |
|
|
|
|
|
return AdminVideoPlaylistDetailSerializer |
|
|
|
|
|
|
|
|
|
|
|
def get_queryset(self): |
|
|
|
|
|
queryset = VideoPlaylist.objects.all().prefetch_related("categories", "collections", "playlist_items__video") |
|
|
|
|
|
|
|
|
|
|
|
search_query = self.request.query_params.get("search") |
|
|
|
|
|
if search_query: |
|
|
|
|
|
queryset = queryset.filter( |
|
|
|
|
|
Q(title__icontains=search_query) |
|
|
|
|
|
| Q(slug__icontains=search_query) |
|
|
|
|
|
| Q(slogan__icontains=search_query) |
|
|
|
|
|
| Q(description__icontains=search_query) |
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
status_filter = self.request.query_params.get("status") |
|
|
|
|
|
if status_filter in {"true", "false"}: |
|
|
|
|
|
queryset = queryset.filter(status=status_filter == "true") |
|
|
|
|
|
|
|
|
|
|
|
category_id = self.request.query_params.get("category") |
|
|
|
|
|
if category_id and category_id != "all": |
|
|
|
|
|
queryset = queryset.filter(categories__id=category_id) |
|
|
|
|
|
|
|
|
|
|
|
collection_id = self.request.query_params.get("collection") |
|
|
|
|
|
if collection_id and collection_id != "all": |
|
|
|
|
|
queryset = queryset.filter(collections__id=collection_id) |
|
|
|
|
|
|
|
|
|
|
|
return queryset.distinct().order_by("order", "-created_at") |
|
|
|
|
|
|
|
|
|
|
|
@action(detail=True, methods=["get", "post"], url_path="items") |
|
|
|
|
|
def items(self, request, pk=None): |
|
|
|
|
|
playlist = self.get_object() |
|
|
|
|
|
|
|
|
|
|
|
if request.method.lower() == "get": |
|
|
|
|
|
items = playlist.playlist_items.select_related("video").order_by("priority", "id") |
|
|
|
|
|
serializer = AdminVideoPlaylistItemSerializer(items, many=True, context={"request": request}) |
|
|
|
|
|
return Response(serializer.data) |
|
|
|
|
|
|
|
|
|
|
|
serializer = AdminVideoPlaylistItemSerializer( |
|
|
|
|
|
data={ |
|
|
|
|
|
**request.data, |
|
|
|
|
|
"playlist": playlist.id, |
|
|
|
|
|
"priority": request.data.get("priority", playlist.playlist_items.count() + 1), |
|
|
|
|
|
}, |
|
|
|
|
|
context={"request": request}, |
|
|
|
|
|
) |
|
|
|
|
|
serializer.is_valid(raise_exception=True) |
|
|
|
|
|
serializer.save() |
|
|
|
|
|
playlist.total_time = playlist.calculate_total_time() |
|
|
|
|
|
playlist.save(update_fields=["total_time"]) |
|
|
|
|
|
return Response(serializer.data, status=status.HTTP_201_CREATED) |
|
|
|
|
|
|
|
|
|
|
|
@action(detail=True, methods=["patch", "delete"], url_path=r"items/(?P<item_id>\d+)") |
|
|
|
|
|
def item_detail(self, request, pk=None, item_id=None): |
|
|
|
|
|
playlist = self.get_object() |
|
|
|
|
|
item = playlist.playlist_items.select_related("video").get(pk=item_id) |
|
|
|
|
|
|
|
|
|
|
|
if request.method.lower() == "delete": |
|
|
|
|
|
item.delete() |
|
|
|
|
|
playlist.total_time = playlist.calculate_total_time() |
|
|
|
|
|
playlist.save(update_fields=["total_time"]) |
|
|
|
|
|
return Response(status=status.HTTP_204_NO_CONTENT) |
|
|
|
|
|
|
|
|
|
|
|
serializer = AdminVideoPlaylistItemSerializer( |
|
|
|
|
|
item, |
|
|
|
|
|
data={**request.data, "playlist": playlist.id}, |
|
|
|
|
|
partial=True, |
|
|
|
|
|
context={"request": request}, |
|
|
|
|
|
) |
|
|
|
|
|
serializer.is_valid(raise_exception=True) |
|
|
|
|
|
serializer.save() |
|
|
|
|
|
playlist.total_time = playlist.calculate_total_time() |
|
|
|
|
|
playlist.save(update_fields=["total_time"]) |
|
|
|
|
|
return Response(serializer.data) |
|
|
|
|
|
|
|
|
|
|
|
@action(detail=True, methods=["post"], url_path="items/reorder") |
|
|
|
|
|
def reorder_items(self, request, pk=None): |
|
|
|
|
|
playlist = self.get_object() |
|
|
|
|
|
item_ids = request.data.get("item_ids", []) |
|
|
|
|
|
if not isinstance(item_ids, list): |
|
|
|
|
|
return Response({"detail": "item_ids must be a list."}, status=status.HTTP_400_BAD_REQUEST) |
|
|
|
|
|
|
|
|
|
|
|
items = list(playlist.playlist_items.filter(id__in=item_ids)) |
|
|
|
|
|
if len(items) != len(item_ids): |
|
|
|
|
|
return Response({"detail": "Some items were not found."}, status=status.HTTP_400_BAD_REQUEST) |
|
|
|
|
|
|
|
|
|
|
|
item_map = {item.id: item for item in items} |
|
|
|
|
|
with transaction.atomic(): |
|
|
|
|
|
for index, item_id in enumerate(item_ids, start=1): |
|
|
|
|
|
item = item_map[item_id] |
|
|
|
|
|
if item.priority != index: |
|
|
|
|
|
item.priority = index |
|
|
|
|
|
item.save(update_fields=["priority"]) |
|
|
|
|
|
|
|
|
|
|
|
serializer = AdminVideoPlaylistItemSerializer( |
|
|
|
|
|
playlist.playlist_items.select_related("video").order_by("priority", "id"), |
|
|
|
|
|
many=True, |
|
|
|
|
|
context={"request": request}, |
|
|
|
|
|
) |
|
|
|
|
|
return Response(serializer.data) |