From 9a7f05c66f52060865e8da4b9f5b4e00b045b0ac Mon Sep 17 00:00:00 2001 From: mohsentaba Date: Sat, 13 Jun 2026 15:37:11 +0330 Subject: [PATCH] references endpoints added --- apps/hadis/serializers/serializers_admin.py | 159 +++++++++++++++++++- apps/hadis/urls.py | 12 +- apps/hadis/views_admin.py | 132 +++++++++++++++- 3 files changed, 300 insertions(+), 3 deletions(-) diff --git a/apps/hadis/serializers/serializers_admin.py b/apps/hadis/serializers/serializers_admin.py index 5be3802..ab37968 100644 --- a/apps/hadis/serializers/serializers_admin.py +++ b/apps/hadis/serializers/serializers_admin.py @@ -1,5 +1,8 @@ from rest_framework import serializers -from ..models import Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisSect +from ..models import ( + Hadis, HadisCategory, HadisStatus, HadisTag, HadisCorrection, HadisInterpretation, HadisSect, + BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType +) from .category import LocalizedField @@ -163,3 +166,157 @@ class AdminHadisInterpretationSerializer(serializers.ModelSerializer): "updated_at", ] read_only_fields = ["id", "created_at", "updated_at"] + + +class AbsoluteImageField(serializers.ImageField): + def to_representation(self, value): + if not value: + return None + request = self.context.get("request") + url = value.url if hasattr(value, "url") else str(value) + if request: + return request.build_absolute_uri(url) + return url + + +class AbsoluteFileField(serializers.FileField): + def to_representation(self, value): + if not value: + return None + request = self.context.get("request") + url = value.url if hasattr(value, "url") else str(value) + if request: + return request.build_absolute_uri(url) + return url + + +class AdminBookSubjectAreaSerializer(serializers.ModelSerializer): + class Meta: + model = BookSubjectArea + fields = ["id", "title"] + + +class AdminBookTypeSerializer(serializers.ModelSerializer): + class Meta: + model = BookType + fields = ["id", "title"] + + +class AdminBookAuthorSerializer(serializers.ModelSerializer): + class Meta: + model = BookAuthor + fields = ["id", "name", "birth_year_hijri", "death_year_hijri", "birth_year_miladi", "death_year_miladi"] + + +class AdminBookAttributeSerializer(serializers.ModelSerializer): + class Meta: + model = BookAttribute + fields = ["id", "book_reference", "title", "value"] + + +class AdminBookReferenceImageSerializer(serializers.ModelSerializer): + image = AbsoluteImageField(required=True) + + class Meta: + model = BookReferenceImage + fields = ["id", "book_reference", "image", "volume", "order", "description"] + + +class AdminBookReferenceDocumentSerializer(serializers.ModelSerializer): + file = AbsoluteFileField(required=True) + + class Meta: + model = BookReferenceDocument + fields = ["id", "book_reference", "file", "volume", "title", "order"] + + +class AdminBookReferenceListSerializer(serializers.ModelSerializer): + class Meta: + model = BookReference + fields = [ + "id", + "title", + "slug", + "volume", + "publisher", + "year_of_publication", + "rate", + "created_at", + ] + + +class AdminBookReferenceDetailSerializer(serializers.ModelSerializer): + subject_area_detail = AdminBookSubjectAreaSerializer(source="subject_area", many=True, read_only=True) + type_detail = AdminBookTypeSerializer(source="type", read_only=True) + authors_detail = AdminBookAuthorSerializer(source="authors", many=True, read_only=True) + + subject_area = serializers.PrimaryKeyRelatedField( + queryset=BookSubjectArea.objects.all(), + many=True, + required=False, + ) + type = serializers.PrimaryKeyRelatedField( + queryset=BookType.objects.all(), + required=False, + allow_null=True, + ) + authors = serializers.PrimaryKeyRelatedField( + queryset=BookAuthor.objects.all(), + many=True, + required=False, + ) + + class Meta: + model = BookReference + fields = [ + "id", + "legacy_id", + "source_url", + "title", + "description", + "language", + "isbn", + "volume", + "number_of_volumes", + "year_of_publication", + "number_page", + "slug", + "publisher", + "subject_area", + "subject_area_detail", + "type", + "type_detail", + "order", + "researcher", + "city_of_publication", + "country_of_publication", + "edition_number", + "rate", + "authors", + "authors_detail", + "created_at", + "updated_at", + "share_link", + ] + read_only_fields = ["id", "slug", "created_at", "updated_at", "share_link"] + + def create(self, validated_data): + subject_area = validated_data.pop("subject_area", []) + authors = validated_data.pop("authors", []) + book = super().create(validated_data) + if subject_area: + book.subject_area.set(subject_area) + if authors: + book.authors.set(authors) + return book + + def update(self, instance, validated_data): + subject_area = validated_data.pop("subject_area", None) + authors = validated_data.pop("authors", None) + book = super().update(instance, validated_data) + if subject_area is not None: + book.subject_area.set(subject_area) + if authors is not None: + book.authors.set(authors) + return book + diff --git a/apps/hadis/urls.py b/apps/hadis/urls.py index c6364a1..78ecb9b 100644 --- a/apps/hadis/urls.py +++ b/apps/hadis/urls.py @@ -6,7 +6,10 @@ from .views.transmitter import TransmitterView ,TransmitterDetailView, Transmitt from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView from .views.version import ContentReleaseSyncView from .views.info import HadisInfoView -from .views_admin import AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet +from .views_admin import ( + AdminHadisCategoryViewSet, AdminHadisViewSet, AdminHadisCorrectionViewSet, AdminHadisInterpretationViewSet, AdminHadisStatusViewSet, AdminHadisTagViewSet, + AdminBookSubjectAreaViewSet, AdminBookTypeViewSet, AdminBookAuthorViewSet, AdminBookAttributeViewSet, AdminBookReferenceImageViewSet, AdminBookReferenceDocumentViewSet, AdminBookReferenceViewSet +) from django.views.decorators.cache import cache_page from django.views.decorators.vary import vary_on_headers @@ -21,6 +24,13 @@ admin_router.register(r'corrections', AdminHadisCorrectionViewSet, basename='adm admin_router.register(r'interpretations', AdminHadisInterpretationViewSet, basename='admin-hadis-interpretations') admin_router.register(r'statuses', AdminHadisStatusViewSet, basename='admin-hadis-statuses') admin_router.register(r'tags', AdminHadisTagViewSet, basename='admin-hadis-tags') +admin_router.register(r'references', AdminBookReferenceViewSet, basename='admin-book-references') +admin_router.register(r'subject-areas', AdminBookSubjectAreaViewSet, basename='admin-book-subject-areas') +admin_router.register(r'book-types', AdminBookTypeViewSet, basename='admin-book-types') +admin_router.register(r'book-authors', AdminBookAuthorViewSet, basename='admin-book-authors') +admin_router.register(r'book-attributes', AdminBookAttributeViewSet, basename='admin-book-attributes') +admin_router.register(r'book-images', AdminBookReferenceImageViewSet, basename='admin-book-images') +admin_router.register(r'book-documents', AdminBookReferenceDocumentViewSet, basename='admin-book-documents') urlpatterns = [ # Admin endpoints diff --git a/apps/hadis/views_admin.py b/apps/hadis/views_admin.py index a1ae223..72db2a8 100644 --- a/apps/hadis/views_admin.py +++ b/apps/hadis/views_admin.py @@ -9,7 +9,10 @@ from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet from apps.account.permissions import IsSuperAdmin from utils.pagination import StandardResultsSetPagination -from .models import Hadis, HadisCategory, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag +from .models import ( + Hadis, HadisCategory, HadisCorrection, HadisInterpretation, HadisStatus, HadisTag, + BookReference, BookReferenceImage, BookReferenceDocument, BookAuthor, BookAttribute, BookSubjectArea, BookType +) from .serializers.serializers_admin import ( AdminHadisCategorySerializer, AdminHadisCorrectionSerializer, @@ -18,6 +21,14 @@ from .serializers.serializers_admin import ( AdminHadisListSerializer, AdminHadisStatusSerializer, AdminHadisTagSerializer, + AdminBookSubjectAreaSerializer, + AdminBookTypeSerializer, + AdminBookAuthorSerializer, + AdminBookAttributeSerializer, + AdminBookReferenceImageSerializer, + AdminBookReferenceDocumentSerializer, + AdminBookReferenceListSerializer, + AdminBookReferenceDetailSerializer, ) @@ -138,3 +149,122 @@ class AdminHadisInterpretationViewSet(ModelViewSet): 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 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").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") +