from django.db.models import Q from django.db.models import Q 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 ( Hadis, HadisCategory, HadisCollection, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, HadisSect, HadisTransmitter, BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType, Transmitters, TransmitterReliability, NarratorLayer, OpinionStatus ) from .serializers.serializers_admin import ( AdminHadisCategorySerializer, AdminHadisSectArchiveSerializer, AdminHadisCategoryArchiveSerializer, AdminHadisCorrectionSerializer, AdminHadisDetailSerializer, AdminHadisInterpretationSerializer, AdminHadisCollectionSerializer, AdminHadisListSerializer, AdminHadisStatusSerializer, AdminHadisTagSerializer, AdminBookSubjectAreaSerializer, AdminBookTypeSerializer, AdminBookAuthorSerializer, AdminBookAttributeSerializer, AdminBookReferenceImageSerializer, AdminBookReferenceDocumentSerializer, AdminBookReferenceListSerializer, AdminBookReferenceDetailSerializer, AdminTransmitterListSerializer, AdminTransmitterDetailSerializer, AdminTransmitterReliabilitySerializer, AdminNarratorLayerSerializer, AdminOpinionStatusSerializer, AdminHadisTransmitterSerializer, ) class AdminHadisCategoryViewSet(ReadOnlyModelViewSet): serializer_class = AdminHadisCategorySerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): queryset = HadisCategory.objects.all() source_type = self.request.query_params.get("source_type") if source_type: queryset = queryset.filter(source_type=source_type) return queryset.order_by("order", "id") class DovodiHadisSectViewSet(ModelViewSet): serializer_class = AdminHadisSectArchiveSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = HadisSect.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter( Q(title__icontains=search_query) | Q(description__icontains=search_query) | Q(sect_type__icontains=search_query) ) return queryset.order_by("order", "id") class DovodiHadisCategoryViewSet(ModelViewSet): serializer_class = AdminHadisCategoryArchiveSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = HadisCategory.objects.select_related("parent", "sect") search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter( Q(title__icontains=search_query) | Q(description__icontains=search_query) | Q(slug__icontains=search_query) | Q(source_type__icontains=search_query) ) source_type = self.request.query_params.get("source_type") if source_type: queryset = queryset.filter(source_type=source_type) return queryset.order_by("tree_id", "lft", "order", "id") class AdminHadisStatusViewSet(ModelViewSet): serializer_class = AdminHadisStatusSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = HadisStatus.objects.all() 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) ) return queryset.order_by("order", "id") class AdminHadisTagViewSet(ModelViewSet): serializer_class = AdminHadisTagSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = HadisTag.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter(title__icontains=search_query) return queryset.order_by("id") class AdminHadisCollectionViewSet(ModelViewSet): serializer_class = AdminHadisCollectionSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (MultiPartParser, FormParser, JSONParser) def get_queryset(self): queryset = HadisCollection.objects.all() 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(summary__icontains=search_query) ) status_filter = self.request.query_params.get("status") if status_filter in {"true", "false"}: queryset = queryset.filter(status=status_filter == "true") return queryset.order_by("order", "id") class AdminTransmitterReliabilityViewSet(ReadOnlyModelViewSet): serializer_class = AdminTransmitterReliabilitySerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): return TransmitterReliability.objects.all().order_by("id") class DovodiNarratorLayerViewSet(ModelViewSet): serializer_class = AdminNarratorLayerSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = NarratorLayer.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter( Q(name__icontains=search_query) | Q(description__icontains=search_query) | Q(slug__icontains=search_query) ) return queryset.order_by("number", "id") class DovodiTransmitterReliabilityViewSet(ModelViewSet): serializer_class = AdminTransmitterReliabilitySerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = TransmitterReliability.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter( Q(title__icontains=search_query) | Q(slug__icontains=search_query) ) return queryset.order_by("id") class DovodiOpinionStatusViewSet(ModelViewSet): serializer_class = AdminOpinionStatusSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = OpinionStatus.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter( Q(title__icontains=search_query) | Q(slug__icontains=search_query) ) return queryset.order_by("id") class AdminTransmitterViewSet(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 AdminTransmitterListSerializer return AdminTransmitterDetailSerializer def get_queryset(self): queryset = Transmitters.objects.select_related("reliability") search_query = self.request.query_params.get("search") if search_query: q_filter = ( Q(full_name__icontains=search_query) | Q(kunya__icontains=search_query) | Q(known_as__icontains=search_query) | Q(nickname__icontains=search_query) | Q(origin__icontains=search_query) | Q(lived_in__icontains=search_query) | Q(died_in__icontains=search_query) ) if search_query.isdigit(): q_filter |= Q(legacy_number=int(search_query)) | Q(generation=int(search_query)) queryset = queryset.filter(q_filter) status_filter = self.request.query_params.get("status") if status_filter and status_filter != "all": queryset = queryset.filter(reliability__slug=status_filter) madhhab_filter = self.request.query_params.get("madhhab") if madhhab_filter and madhhab_filter != "all": queryset = queryset.filter(madhhab=madhhab_filter) generation_filter = self.request.query_params.get("generation") if generation_filter and generation_filter != "all": queryset = queryset.filter(generation=generation_filter) return queryset.order_by("id") class AdminHadisViewSet(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 AdminHadisListSerializer return AdminHadisDetailSerializer def get_queryset(self): queryset = Hadis.objects.all().select_related("category", "hadis_status") search_query = self.request.query_params.get("search") if search_query: q_filter = ( Q(title__icontains=search_query) | Q(title_narrator__icontains=search_query) | Q(text__icontains=search_query) | Q(translation__icontains=search_query) | Q(slug__icontains=search_query) ) if search_query.isdigit(): q_filter |= Q(number=int(search_query)) queryset = queryset.filter(q_filter) category_id = self.request.query_params.get("category") if category_id and category_id != "all": queryset = queryset.filter(category_id=category_id) source_type = self.request.query_params.get("source_type") if source_type: queryset = queryset.filter(category__source_type=source_type) status_filter = self.request.query_params.get("status") if status_filter in {"true", "false"}: queryset = queryset.filter(status=status_filter == "true") return queryset.distinct().order_by("-id") class AdminHadisCorrectionViewSet(ModelViewSet): serializer_class = AdminHadisCorrectionSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] parser_classes = (JSONParser, MultiPartParser, FormParser) pagination_class = None def get_queryset(self): queryset = HadisCorrection.objects.all() hadis_id = self.request.query_params.get("hadis_id") if hadis_id: queryset = queryset.filter(hadis_id=hadis_id) return queryset.order_by("priority", "created_at") def perform_create(self, serializer): priority = self.request.data.get("priority", 1) hadis_id = self.request.data.get("hadis") if hadis_id: from django.db.models import F HadisCorrection.objects.filter(hadis_id=hadis_id, priority__gte=priority).update(priority=F("priority") + 1) serializer.save() @action(detail=False, methods=["post"]) def reorder(self, request): correction_ids = request.data.get("correction_ids", []) if not correction_ids: return Response({"error": "correction_ids list is required"}, status=400) for index, correction_id in enumerate(correction_ids, start=1): HadisCorrection.objects.filter(id=correction_id).update(priority=index) return Response({"status": "success"}) class AdminHadisInterpretationViewSet(ModelViewSet): serializer_class = AdminHadisInterpretationSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] parser_classes = (JSONParser, MultiPartParser, FormParser) pagination_class = None def get_queryset(self): queryset = HadisInterpretation.objects.all() category_id = self.request.query_params.get("category_id") if category_id: queryset = queryset.filter(category_id=category_id) return queryset.order_by("priority", "created_at") def perform_create(self, serializer): priority = self.request.data.get("priority", 1) category_id = self.request.data.get("category") if category_id: from django.db.models import F HadisInterpretation.objects.filter(category_id=category_id, priority__gte=priority).update(priority=F("priority") + 1) serializer.save() @action(detail=False, methods=["post"]) def reorder(self, request): interpretation_ids = request.data.get("interpretation_ids", []) if not interpretation_ids: return Response({"error": "interpretation_ids list is required"}, status=400) for index, interpretation_id in enumerate(interpretation_ids, start=1): HadisInterpretation.objects.filter(id=interpretation_id).update(priority=index) return Response({"status": "success"}) class AdminBookSubjectAreaViewSet(ReadOnlyModelViewSet): serializer_class = AdminBookSubjectAreaSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): return BookSubjectArea.objects.all().order_by("id") class AdminBookTypeViewSet(ReadOnlyModelViewSet): serializer_class = AdminBookTypeSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): return BookType.objects.all().order_by("id") class DovodiBookSubjectAreaViewSet(ModelViewSet): serializer_class = AdminBookSubjectAreaSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = BookSubjectArea.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter(title__icontains=search_query) return queryset.order_by("id") class DovodiBookTypeViewSet(ModelViewSet): serializer_class = AdminBookTypeSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = BookType.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter(title__icontains=search_query) return queryset.order_by("id") class AdminBookAuthorViewSet(ModelViewSet): serializer_class = AdminBookAuthorSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): queryset = BookAuthor.objects.all() search_query = self.request.query_params.get("search") if search_query: queryset = queryset.filter(name__icontains=search_query) return queryset.order_by("id") class AdminBookAttributeViewSet(ModelViewSet): serializer_class = AdminBookAttributeSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] pagination_class = None def get_queryset(self): queryset = BookAttribute.objects.all() book_reference_id = self.request.query_params.get("book_reference_id") if book_reference_id: queryset = queryset.filter(book_reference_id=book_reference_id) return queryset.order_by("id") class AdminBookReferenceImageViewSet(ModelViewSet): serializer_class = AdminBookReferenceImageSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] parser_classes = (MultiPartParser, FormParser, JSONParser) pagination_class = None def get_queryset(self): queryset = BookReferenceImage.objects.all() book_reference_id = self.request.query_params.get("book_reference_id") if book_reference_id: queryset = queryset.filter(book_reference_id=book_reference_id) return queryset.order_by("order", "id") class AdminBookReferenceDocumentViewSet(ModelViewSet): serializer_class = AdminBookReferenceDocumentSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] parser_classes = (MultiPartParser, FormParser, JSONParser) pagination_class = None def get_queryset(self): queryset = BookReferenceDocument.objects.all() book_reference_id = self.request.query_params.get("book_reference_id") if book_reference_id: queryset = queryset.filter(book_reference_id=book_reference_id) return queryset.order_by("order", "id") class AdminBookReferenceViewSet(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 AdminBookReferenceListSerializer return AdminBookReferenceDetailSerializer def get_queryset(self): queryset = BookReference.objects.all().prefetch_related("subject_area", "authors", "volumes", "editions").select_related("type") 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(isbn__icontains=search_query) | Q(publisher__icontains=search_query) | Q(description__icontains=search_query) | Q(researcher__icontains=search_query) ) type_id = self.request.query_params.get("type") if type_id and type_id != "all": queryset = queryset.filter(type_id=type_id) subject_area_id = self.request.query_params.get("subject_area") if subject_area_id and subject_area_id != "all": queryset = queryset.filter(subject_area__id=subject_area_id) author_id = self.request.query_params.get("author") if author_id and author_id != "all": queryset = queryset.filter(authors__id=author_id) return queryset.distinct().order_by("-created_at") class AdminCategoryQuranVerseViewSet(ModelViewSet): permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] parser_classes = (JSONParser, MultiPartParser, FormParser) def get_serializer_class(self): from .serializers.serializers_admin import AdminCategoryQuranVerseSerializer return AdminCategoryQuranVerseSerializer def get_queryset(self): from .models.category import CategoryQuranVerse queryset = CategoryQuranVerse.objects.all().prefetch_related("secondary_translations") category_id = self.request.query_params.get("category") if category_id: queryset = queryset.filter(category_id=category_id) return queryset class AdminHadisTransmitterViewSet(ModelViewSet): serializer_class = AdminHadisTransmitterSerializer permission_classes = [IsAuthenticated, IsSuperAdmin] authentication_classes = [TokenAuthentication] parser_classes = (JSONParser, MultiPartParser, FormParser) def get_queryset(self): queryset = HadisTransmitter.objects.all().select_related("transmitter", "narrator_layer", "status") hadis_id = self.request.query_params.get("hadis_id") if hadis_id: queryset = queryset.filter(hadis_id=hadis_id) return queryset.order_by("order") @action(detail=False, methods=["post"]) def reorder(self, request): from rest_framework.decorators import action from rest_framework.response import Response from django.db import transaction hadis_transmitter_ids = request.data.get("hadis_transmitter_ids", []) if not hadis_transmitter_ids: return Response({"error": "hadis_transmitter_ids list is required"}, status=400) with transaction.atomic(): # Pass 1: Set temporary positive offset order indices to avoid duplicate key violations (>= 0) for index, ht_id in enumerate(hadis_transmitter_ids): HadisTransmitter.objects.filter(id=ht_id).update(order=10000 + index) # Pass 2: Set final sequential order indices starting from 0 for index, ht_id in enumerate(hadis_transmitter_ids): HadisTransmitter.objects.filter(id=ht_id).update(order=index) return Response({"status": "success"})