Browse Source

Add HadisCategoryXMindView API endpoint and Swagger documentation

- Implemented HadisCategoryXMindView to retrieve a mind-map JSON structure for specific hadis categories.
- Added Swagger documentation detailing the endpoint's features, usage, and response structure.
- Updated URL routing to include the new endpoint for XMind format retrieval.
- Enhanced the HadisCategoryXMindView to support multi-language content and bookmark status for authenticated users.
master
Mohsen Taba 4 months ago
parent
commit
bcc2cf1104
  1. 132
      apps/hadis/docs.py
  2. 3
      apps/hadis/urls.py
  3. 102
      apps/hadis/views/category.py

132
apps/hadis/docs.py

@ -2540,3 +2540,135 @@ content_release_sync_swagger = swagger_auto_schema(
)
}
)
# Swagger documentation for HadisCategoryXMindView
hadis_category_xmind_swagger = swagger_auto_schema(
operation_description="""
Retrieve a mind-map JSON structure (XMind format) for a specific category and its hadiths.
**Key Features:**
- Returns XMind-compatible JSON structure for mind-map visualization
- Root node represents the category
- Child nodes represent all hadiths in that category
- Supports multi-language content based on query parameter or Accept-Language header
- Includes bookmark status for each hadith (if user is authenticated)
- Returns all hadiths without pagination (suitable for mind-map visualization)
**Structure:**
- `rootTopic`: The main category node
- `id`: Category identifier (format: "cat-{category_id}")
- `title`: Localized category title
- `structureClass`: XMind structure type (org.xmind.ui.map.unbalanced for right-branching)
- `children.attached`: Array of hadith nodes
- Each hadith node contains:
- `id`: Hadith ID
- `slug`: URL-friendly identifier
- `title`: Localized hadith title
- `title_narrator`: Narrator information
- `text`: Original Arabic text
- `translation`: Translated text in requested language
- `share_link`: Direct link to the hadith
- `is_bookmarked`: Boolean indicating if user has bookmarked this hadith
**Usage:**
- Use this endpoint to generate mind-map visualizations of hadith categories
- The response format is compatible with XMind and similar mind-mapping tools
- Language can be specified via `?lang=` query parameter or Accept-Language header
- Bookmark status is only available for authenticated users
**Note:**
- This endpoint returns ALL hadiths in the category (no pagination)
- For categories with 1000+ hadiths, consider client-side limiting
- Only active (status=True) hadiths are included
""",
operation_summary="Get Category Mind-Map Structure (XMind Format)",
tags=['Dobodbi - Hadis'],
manual_parameters=[
openapi.Parameter(
'category_slug',
openapi.IN_PATH,
description="Unique slug identifier of the Hadis category. Must be a valid category slug that exists in the system.",
type=openapi.TYPE_STRING,
required=True,
example='cat-l3-25-7f5bcb'
),
openapi.Parameter(
'lang',
openapi.IN_QUERY,
description="Language code for content localization. Supported codes: 'en' (English), 'fa' (Persian), 'ar' (Arabic), 'ur' (Urdu), 'ru' (Russian). Defaults to 'en' if not specified. Can also be set via Accept-Language header.",
type=openapi.TYPE_STRING,
required=False,
default='en',
enum=['en', 'fa', 'ar', 'ur', 'ru']
),
openapi.Parameter(
'Accept-Language',
openapi.IN_HEADER,
description="Alternative way to specify language code. If both query parameter and header are provided, query parameter takes precedence.",
type=openapi.TYPE_STRING,
required=False,
default='en',
enum=['en', 'fa', 'ar', 'ur', 'ru']
)
],
responses={
status.HTTP_200_OK: openapi.Response(
description="Successfully retrieved mind-map structure for the specified category",
examples={
"application/json": {
"rootTopic": {
"id": "cat-25",
"title": "Book of Faith",
"structureClass": "org.xmind.ui.map.unbalanced",
"children": {
"attached": [
{
"id": 1,
"slug": "hadis-intention-and-actions",
"title": "The Intention",
"title_narrator": "From Umar ibn al-Khattab",
"text": "إنما الأعمال بالنيات وإنما لكل امرئ ما نوى",
"translation": "Actions are but by intention, and every man shall have only what he intended",
"share_link": "http://example.com/hadis/hadis-intention-and-actions",
"is_bookmarked": False
},
{
"id": 2,
"slug": "hadis-gabriel-hadith",
"title": "The Hadith of Gabriel",
"title_narrator": "From Abu Hurairah",
"text": "بينما نحن عند رسول الله صلى الله عليه وسلم ذات يوم",
"translation": "While we were sitting with the Messenger of Allah (peace be upon him) one day",
"share_link": "http://example.com/hadis/hadis-gabriel-hadith",
"is_bookmarked": True
},
{
"id": 3,
"slug": "hadis-islam-faith-excellence",
"title": "Islam, Faith, and Excellence",
"title_narrator": "From Abu Hurairah",
"text": "عن أبي هريرة رضي الله عنه قال: قال رسول الله صلى الله عليه وسلم",
"translation": "Narrated Abu Hurairah: The Messenger of Allah (peace be upon him) said",
"share_link": "http://example.com/hadis/hadis-islam-faith-excellence",
"is_bookmarked": False
}
]
}
}
}
}
),
status.HTTP_404_NOT_FOUND: openapi.Response(
description="Category not found. The provided category_slug does not exist in the system.",
examples={
"application/json": {
"detail": "Not found."
}
}
),
status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response(
description="Internal server error"
)
}
)

3
apps/hadis/urls.py

@ -1,5 +1,5 @@
from django.urls import path
from .views.category import HadisCategorySectListView, HadisCategoryTreeView, CategoriesView, CategoriesBySectView, HadisCategorySelectBySectView, HadisCategorySelectBySectSourceView , HadisCategoryTreeNormalView ,test_deploy,debug_headers
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
from .views.transmitter import TransmitterView ,TransmitterDetailView, TransmitterSyncView,TransmitterOpinionView, TransmitterOriginalTextView, TransmitterFiltersView
from .views.reference import BookDetailView, BookReferencesView, BookReferenceSyncView, BookAttributeView
@ -32,6 +32,7 @@ urlpatterns = [
path('categories/', CategoriesView.as_view(), name='categories'), # ← Least specific LAST
# Hadis paths
path('category/<str:category_slug>/xmind/', HadisCategoryXMindView.as_view(), name='hadis-category-xmind'), # ← Must be before other category paths
path('category/<str:category_slug>/', HadisListView.as_view(), name='hadis-list'),
path('arguments/', cached_view(HadisMainListView.as_view()), name='hadis-main-list'),
path('arguments/filters/', cached_view(HadisFiltersView.as_view()), name='hadis-filters'),

102
apps/hadis/views/category.py

@ -5,6 +5,7 @@ from utils.pagination import NoPagination
from django.db.models import Q
from utils.pagination import StandardResultsSetPagination
from ..models import HadisSect, HadisCategory,Hadis
from apps.bookmark.serializers.bookmark import BookmarkStatusSerializer
from ..serializers import (
HadisCategorySectListSerializer,
HadisCategoryTreeSerializer,
@ -20,7 +21,8 @@ from ..docs import (
categories_list_swagger,
categories_by_sect_swagger,
categories_tree_by_sect_swagger,
categories_tree_by_sect_source_swagger
categories_tree_by_sect_source_swagger,
hadis_category_xmind_swagger
)
@ -402,4 +404,100 @@ def debug_headers(request):
'SECURE_PROXY_SSL_HEADER_SETTING': getattr(settings, 'SECURE_PROXY_SSL_HEADER', None),
}
return JsonResponse({'headers': headers, 'debug': scheme_debug})
return JsonResponse({'headers': headers, 'debug': scheme_debug})
from rest_framework.views import APIView
class HadisCategoryXMindView(APIView):
"""
Returns a mind-map JSON structure for a specific category and its hadiths.
Root -> Category
Children -> Hadiths
"""
def get_localized_text(self, json_field, lang):
"""Helper to extract text from your JSON structure"""
if not json_field or not isinstance(json_field, list):
return "Unknown"
# 1. Try specific language
for item in json_field:
if item.get('language_code') == lang:
return item.get('text', '')
# 2. Fallback to English
for item in json_field:
if item.get('language_code') == 'en':
return item.get('text', '')
# 3. Fallback to first available
if len(json_field) > 0:
return json_field[0].get('text', '')
return "Unknown"
@hadis_category_xmind_swagger
def get(self, request, category_slug):
# 1. Determine Language (support ?lang=ru or Accept-Language header)
lang = request.query_params.get('lang','en')
# 2. Get the Category (Root Node)
category = get_object_or_404(HadisCategory, slug=category_slug)
root_title = self.get_localized_text(category.title, lang)
# 3. Get the Hadiths (Child Nodes)
# Note: Mind maps generally show ALL nodes, so we avoid pagination here.
# If you have 1000+ hadiths, consider limiting this query (e.g., [:50]).
hadiths = Hadis.objects.filter(
category=category,
status=True
).order_by('number').only('id', 'number', 'title', 'title_narrator', 'translation', 'text', 'slug', 'share_link')
# 4. Get user for bookmark check
user = request.user if request and hasattr(request, 'user') else None
if user and user.is_anonymous:
user = None
# 5. Build Child Nodes List
children_nodes = []
for hadis in hadiths:
# Get Title
hadis_title = self.get_localized_text(hadis.title, lang)
hadis_title_narrator = self.get_localized_text(hadis.title_narrator, lang)
hadis_translation = self.get_localized_text(hadis.translation, lang)
# Get bookmark status
bookmark_info = BookmarkStatusSerializer.get_bookmark_info(
obj=hadis,
user=user,
service='hadith'
)
is_bookmarked = bookmark_info.get('is_bookmarked', False)
children_nodes.append({
"id": hadis.id,
"slug": hadis.slug,
"title": hadis_title,
"title_narrator": hadis_title_narrator,
"text": hadis.text,
"translation": hadis_translation,
"share_link": hadis.share_link,
"is_bookmarked": is_bookmarked,
# Optional: Add 'href' if you want XMind to handle links,
# but usually the frontend handles the 'click' event based on ID.
})
# 6. Construct XMind JSON Structure
data = {
"rootTopic": {
"id": f"cat-{category.id}",
"title": root_title,
"structureClass": "org.xmind.ui.map.unbalanced", # Standard right-branching map
"children": {
"attached": children_nodes
}
}
}
return Response(data)
Loading…
Cancel
Save