diff --git a/apps/hadis/serializers/hadis.py b/apps/hadis/serializers/hadis.py index bbb006c..fddaba0 100644 --- a/apps/hadis/serializers/hadis.py +++ b/apps/hadis/serializers/hadis.py @@ -1142,10 +1142,22 @@ class HadisCorrectionSerializer(serializers.ModelSerializer): address = serializers.SerializerMethodField() images = serializers.SerializerMethodField() links = serializers.JSONField(read_only=True) + hadis_info = serializers.SerializerMethodField() class Meta: model = HadisCorrection - fields = ['id', 'title', 'slug', 'narrator', 'description', 'translation', 'share_link', 'bookmark', 'address', 'images', 'links'] + fields = ['id', 'title', 'slug', 'narrator', 'description', 'translation', 'share_link', 'bookmark', 'address', 'images', 'links', 'hadis_info'] + + def get_hadis_info(self, obj): + if obj.hadis: + request = self.context.get('request') + return { + "id": obj.hadis.id, + "number": obj.hadis.number, + "slug": obj.hadis.slug, + "title": get_localized_text(obj.hadis.title, request) if hasattr(obj.hadis, 'title') and obj.hadis.title else f"Hadith {obj.hadis.number}", + } + return None def get_description(self, obj): request = self.context.get('request') diff --git a/apps/hadis/urls.py b/apps/hadis/urls.py index 3ee645b..4825475 100644 --- a/apps/hadis/urls.py +++ b/apps/hadis/urls.py @@ -2,7 +2,7 @@ from django.urls import path, include from rest_framework.routers import SimpleRouter from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView ,test_deploy,debug_headers,HadisCategoryXMindView from .views.hadis import ( - HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView,HadisMainListView, HadisFiltersView, HadisLayersView,PinnedHadisCollectionListView, HadisFiltersSyncAPIView, + HadisCollectionListView, HadisListView, HadisBasicView, HadisDetailView, HadisSyncView, HadisTransmittersView, HadisCorrectionsView, CategoryHadisCorrectionsView, HadisMainListView, HadisFiltersView, HadisLayersView,PinnedHadisCollectionListView, HadisFiltersSyncAPIView, HadisCorrectionDetailView, HadisInterpretationDetailView, HadisInterpretsListView, HadisSourceDetailsView ) from .views.transmitter import ( @@ -101,6 +101,7 @@ urlpatterns = [ # Hadis paths path('category//xmind/', HadisCategoryXMindView.as_view(), name='hadis-category-xmind'), # ← Must be before other category paths + path('category//corrections/', CategoryHadisCorrectionsView.as_view(), name='category-hadis-corrections'), path('category//', HadisListView.as_view(), name='hadis-list'), path('arguments/filters/', HadisFiltersView.as_view(), name='hadis-filters'), path('arguments/', HadisMainListView.as_view(), name='hadis-main-list'), diff --git a/apps/hadis/views/hadis.py b/apps/hadis/views/hadis.py index ef4682f..cf66f0f 100644 --- a/apps/hadis/views/hadis.py +++ b/apps/hadis/views/hadis.py @@ -1,6 +1,8 @@ from rest_framework.authentication import TokenAuthentication -from rest_framework.permissions import IsAuthenticated +from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.generics import ListAPIView, RetrieveAPIView +from drf_yasg.utils import swagger_auto_schema +from drf_yasg import openapi from django.shortcuts import get_object_or_404 from utils.pagination import NoPagination, StandardResultsSetPagination from rest_framework.pagination import PageNumberPagination @@ -657,6 +659,94 @@ class HadisCorrectionsView(ListAPIView): +class CategoryHadisCorrectionsView(ListAPIView): + """ + API view to retrieve all corrections across all hadiths belonging to a specific category + """ + serializer_class = HadisCorrectionSerializer + authentication_classes = [TokenAuthentication] + permission_classes = [AllowAny] + pagination_class = StandardResultsSetPagination + + @swagger_auto_schema( + operation_summary="Get Category Hadis Corrections", + operation_description="Returns all text corrections across all hadiths belonging to a specific category, including hadis_info for each correction.", + tags=['Dobodbi - Hadis (V2)'], + manual_parameters=[ + openapi.Parameter('search', openapi.IN_QUERY, description="Search in text or narrator", type=openapi.TYPE_STRING), + openapi.Parameter('hadis_slug', openapi.IN_QUERY, description="Filter corrections by specific hadith slug", type=openapi.TYPE_STRING), + openapi.Parameter('is_bookmark', openapi.IN_QUERY, description="Filter only bookmarked corrections (requires auth)", type=openapi.TYPE_BOOLEAN), + ] + ) + def get(self, request, *args, **kwargs): + return self.list(request, *args, **kwargs) + + def get_queryset(self): + category_slug = self.kwargs.get('category_slug') + try: + category = HadisCategory.objects.get(slug=category_slug) + category_ids = category.get_descendants(include_self=True).values_list('id', flat=True) + hadis_ids = Hadis.objects.filter( + category_id__in=category_ids, + status=True + ).values_list('id', flat=True) + + queryset = HadisCorrection.objects.filter( + hadis_id__in=hadis_ids + ).select_related('hadis').prefetch_related( + 'references', + 'references__images' + ).order_by('priority', '-created_at') + + # Optional search query filter + search_query = self.request.query_params.get('search', None) + if search_query: + search_conditions = ( + Q(text__icontains=search_query) | + Q(narrator__icontains=search_query) + ) + queryset = queryset.filter(search_conditions) + + # Optional filter by specific hadith slug within this category + hadis_slug = self.request.query_params.get('hadis_slug', None) + if hadis_slug: + queryset = queryset.filter(hadis__slug=hadis_slug) + + # Filter by bookmarks if provided + is_bookmark = self.request.query_params.get('is_bookmark', '').lower() + if is_bookmark == 'true' and self.request.user.is_authenticated: + from apps.bookmark.models.bookmark import Bookmark + bookmarked_ids = Bookmark.objects.filter( + user=self.request.user, + service=Bookmark.ServiceChoices.HADITH_CORRECTION, + status=True + ).values_list('content_id', flat=True) + queryset = queryset.filter(id__in=bookmarked_ids) + + return queryset + except HadisCategory.DoesNotExist: + return HadisCorrection.objects.none() + + def list(self, request, *args, **kwargs): + response = super().list(request, *args, **kwargs) + category_slug = self.kwargs.get('category_slug') + category_obj = HadisCategory.objects.filter(slug=category_slug).first() + category_data = SimpleCategory(category_obj).data if category_obj else None + + if isinstance(response.data, dict): + ordered_data = { + 'count': response.data.get('count', 0), + 'next': response.data.get('next'), + 'previous': response.data.get('previous'), + 'current_category': category_data, + 'results': response.data.get('results', []), + } + response.data = ordered_data + + return response + + + class HadisLayersView(ListAPIView): """ API view to retrieve all narrator layers for a specific hadis