from django.db import transaction from django.db.models import Q from rest_framework import status from rest_framework.authentication import TokenAuthentication from rest_framework.decorators import action from rest_framework.parsers import FormParser, JSONParser, MultiPartParser from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from apps.account.permissions import IsSuperAdmin from utils.pagination import StandardResultsSetPagination from .models import PlaylistItem, Podcast, PodcastCollection, PodcastCategory, PodcastPlaylist from .serializers_admin import ( AdminPodcastCategorySerializer, AdminPodcastCollectionSerializer, AdminPodcastDetailSerializer, AdminPodcastListSerializer, AdminPodcastPlaylistDetailSerializer, AdminPodcastPlaylistItemSerializer, AdminPodcastPlaylistListSerializer, ) class AdminPodcastCategoryViewSet(ReadOnlyModelViewSet): serializer_class = AdminPodcastCategorySerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): return PodcastCategory.objects.all().order_by("title") class AdminPodcastCollectionViewSet(ReadOnlyModelViewSet): serializer_class = AdminPodcastCollectionSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): return PodcastCollection.objects.all().order_by("display_position", "order", "title") class AdminPodcastViewSet(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 AdminPodcastListSerializer return AdminPodcastDetailSerializer def get_queryset(self): queryset = Podcast.objects.all().prefetch_related("categories", "collections") 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(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) unattached = self.request.query_params.get("unattached") if unattached == "true": queryset = queryset.filter(playlist_appearances__isnull=True) return queryset.distinct().order_by("-created_at") class AdminPodcastPlaylistViewSet(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 AdminPodcastPlaylistListSerializer return AdminPodcastPlaylistDetailSerializer def get_queryset(self): queryset = PodcastPlaylist.objects.all().prefetch_related("categories", "collections", "playlist_items__podcast") 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("podcast").order_by("priority", "id") serializer = AdminPodcastPlaylistItemSerializer(items, many=True, context={"request": request}) return Response(serializer.data) serializer = AdminPodcastPlaylistItemSerializer( 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\d+)") def item_detail(self, request, pk=None, item_id=None): playlist = self.get_object() item = playlist.playlist_items.select_related("podcast").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 = AdminPodcastPlaylistItemSerializer( 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 = AdminPodcastPlaylistItemSerializer( playlist.playlist_items.select_related("podcast").order_by("priority", "id"), many=True, context={"request": request}, ) return Response(serializer.data)