from rest_framework.generics import ListAPIView from rest_framework.response import Response from django.shortcuts import get_object_or_404 from utils.pagination import NoPagination from ..models import HadisSect, HadisCategory from ..serializers import HadisCategorySectListSerializer, HadisCategoryTreeSerializer, CategorySerializer , HadisCategorySelectSerializer from ..docs import ( hadis_sect_list_swagger, hadis_category_tree_swagger, categories_list_swagger, categories_by_sect_swagger, categories_tree_by_sect_swagger, categories_tree_by_sect_source_swagger ) class HadisCategorySectListView(ListAPIView): """ API view to list all HadisSects grouped by sect_type (shia/sunni) """ queryset = HadisSect.objects.filter(is_active=True).order_by('order') serializer_class = HadisCategorySectListSerializer pagination_class = NoPagination @hadis_sect_list_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def list(self, request, *args, **kwargs): queryset = self.get_queryset() response = super().list(request, *args, **kwargs) lang = request.LANGUAGE_CODE # Group sects by type grouped_data = { 'shia': [], 'sunni': [] } for sect in queryset: sect_data = { 'id': sect.id, 'title': sect.title, } if sect.sect_type == HadisSect.SectType.SHIA: grouped_data['shia'].append(sect_data) elif sect.sect_type == HadisSect.SectType.SUNNI: grouped_data['sunni'].append(sect_data) # Create response with count and results response_data = { 'count': queryset.count(), 'results': grouped_data } return Response(response_data) class HadisCategoryTreeView(ListAPIView): """ API view to get all HadisCategory tree structure grouped by sect and source_type Returns all categories in a tree structure """ serializer_class = HadisCategoryTreeSerializer pagination_class = NoPagination @hadis_category_tree_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def get_queryset(self): return HadisCategory.objects.filter( parent__isnull=True, sect__is_active=True ).order_by('sect__order', 'order') def list(self, request, *args, **kwargs): queryset = self.get_queryset() grouped_data = {} serializer_instance = HadisCategoryTreeSerializer(context={'request': request}) # گروه‌بندی بر اساس sect_type (shia/sunni) for category in queryset: sect_type = category.sect.sect_type if sect_type not in grouped_data: # ایجاد گروه برای هر sect_type grouped_data[sect_type] = { 'sects': {}, 'categories': {} } # اضافه کردن اطلاعات sect به گروه sect_type sect_id = str(category.sect.id) if sect_id not in grouped_data[sect_type]['sects']: grouped_data[sect_type]['sects'][sect_id] = { 'id': category.sect.id, 'sect_type': category.sect.sect_type, 'title': category.sect.title, 'description': category.sect.description, 'order': category.sect.order } # گروه‌بندی categories بر اساس source_type if category.source_type not in grouped_data[sect_type]['categories']: grouped_data[sect_type]['categories'][category.source_type] = [] category_data = self.build_enhanced_category_tree(category, serializer_instance) grouped_data[sect_type]['categories'][category.source_type].append(category_data) def count_children(children_list): count = 0 for item in children_list: count += 1 if 'children' in item and item['children']: count += count_children(item['children']) return count total_count = 0 for sect_type_data in grouped_data.values(): for source_categories in sect_type_data['categories'].values(): for item in source_categories: total_count += 1 if 'children' in item and item['children']: total_count += count_children(item['children']) response_data = { 'count': total_count, 'results': grouped_data } return Response(response_data) def build_enhanced_category_tree(self, category, serializer_instance): """Build enhanced category tree with father category info and hadis details""" base_data = serializer_instance.to_dict(category) # Enhance children with additional information enhanced_children = [] for child_data in base_data.get('children', []): enhanced_child = self.enhance_child_data(child_data, category, serializer_instance) enhanced_children.append(enhanced_child) base_data['children'] = enhanced_children return base_data def enhance_child_data(self, child_data, parent_category, serializer_instance): """Enhance child data with father category info and hadis details""" from ..models import Hadis # Add father category information child_data['father_category'] = { 'id': parent_category.id, 'name': parent_category.title, 'sect_id': parent_category.sect.id, 'sect_type': parent_category.sect.sect_type, 'source_type': parent_category.source_type } # If this child has no children but has hadis, add hadis details if not child_data.get('children', []) and child_data.get('has_hadis', False): try: # Get the category object from ..models import HadisCategory child_category = HadisCategory.objects.get(id=child_data['id']) # Get hadis for this category hadis_list = Hadis.objects.filter( category=child_category, status=True ).order_by('number') hadis_details = [] for hadis in hadis_list: hadis_detail = { 'id': hadis.id, 'title': hadis.title, 'title_narrator': hadis.title_narrator, 'text': hadis.text, 'translation': hadis.get_translation( self.request.LANGUAGE_CODE if hasattr(self, 'request') and self.request else 'en' ), 'share_link': hadis.share_link } hadis_details.append(hadis_detail) child_data['hadis_details'] = hadis_details except Exception as e: # If there's any error, just continue without hadis details pass # Recursively enhance children's children if child_data.get('children', []): enhanced_grandchildren = [] try: from ..models import HadisCategory child_category = HadisCategory.objects.get(id=child_data['id']) for grandchild_data in child_data['children']: enhanced_grandchild = self.enhance_child_data(grandchild_data, child_category, serializer_instance) enhanced_grandchildren.append(enhanced_grandchild) except: # If there's an error, keep original children enhanced_grandchildren = child_data['children'] child_data['children'] = enhanced_grandchildren return child_data class HadisCategoryTreeNormalView(ListAPIView): """ Normal (paginated) tree view for HadisCategory. Unlike the sync view, this simply returns the root categories (filtered to active sects) with their nested children, and uses the project's default pagination. """ serializer_class = HadisCategoryTreeSerializer @hadis_category_tree_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def get_queryset(self): return HadisCategory.objects.filter( parent__isnull=True, sect__is_active=True ).order_by('sect__order', 'order') class HadisCategorySelectBySectView(ListAPIView): """ Tree view for HadisCategory filtered by sect_type and category slug. Returns the children categories of the specified category (by slug) within the sect_type. """ serializer_class = HadisCategorySelectSerializer @categories_tree_by_sect_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def get_queryset(self): sect_type = self.kwargs.get('sect_type') slug = self.kwargs.get('slug') # Find the parent category by slug and sect_type try: parent_category = HadisCategory.objects.get( slug=slug, sect__sect_type=sect_type, sect__is_active=True ) except HadisCategory.DoesNotExist: return HadisCategory.objects.none() # Return children of this category, filtered as before return HadisCategory.objects.filter( parent=parent_category, sect__sect_type=sect_type, sect__is_active=True ).order_by('order') class HadisCategorySelectBySectSourceView(ListAPIView): """ Tree view for HadisCategory filtered by sect_type, category slug and source_type. Returns the children categories of the specified category (by slug) within the sect_type, filtered by source_type. """ serializer_class = HadisCategorySelectSerializer @categories_tree_by_sect_source_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def get_queryset(self): sect_type = self.kwargs.get('sect_type') slug = self.kwargs.get('slug') source_type = self.kwargs.get('source_type') # Find the parent category by slug and sect_type try: parent_category = HadisCategory.objects.get( slug=slug, sect__sect_type=sect_type, sect__is_active=True ) except HadisCategory.DoesNotExist: return HadisCategory.objects.none() # Return children of this category, filtered by source_type return HadisCategory.objects.filter( parent=parent_category, sect__sect_type=sect_type, sect__is_active=True, source_type=source_type ).order_by('order') class CategoriesView(ListAPIView): """ API view to list all HadisCategories """ queryset = HadisCategory.objects.all() serializer_class = CategorySerializer @categories_list_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) def list(self, request, *args, **kwargs): return super().list(request, *args, **kwargs) class CategoriesBySectView(ListAPIView): """ API view to list HadisCategories filtered by sect_type """ serializer_class = CategorySerializer def get_queryset(self): sect_type = self.kwargs.get('sect_type') return HadisCategory.objects.filter(sect__sect_type=sect_type) @categories_by_sect_swagger def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)