from django import forms from django.contrib import admin from django.utils.translation import gettext_lazy as _ from unfold.admin import ModelAdmin, TabularInline from unfold.contrib.forms.widgets import WysiwygWidget from unfold.decorators import display, action from unfold.widgets import UnfoldAdminTextInputWidget, UnfoldAdminTextareaWidget from utils.multilang_json_widget import MultiLanguageJSONWidget, MultiLanguageAddressWidget, LinksJSONWidget from utils.json_editor_field import JsonEditorWidget import json from utils.admin import dovoodi_admin_site from ..models import ( Hadis, HadisReference, HadisTag, HadisStatus, ReferenceImage, HadisCollection, HadisInCollection, HadisCorrection ) # Custom Forms for JSON Fields class HadisAdminForm(forms.ModelForm): """Custom form for Hadis with JSON editor widgets""" class Meta: model = Hadis fields = '__all__' widgets = { 'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget), 'title_narrator': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget), 'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), 'translation': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), 'address': MultiLanguageAddressWidget(), 'links': LinksJSONWidget(), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Schema for explanation JSON field (title is an array of objects with title and detail) explanation_schema = { "type": "array", "title": "Explanations", "items": { "type": "object", "title": "Explanation", "properties": { "language_code": { "type": "string", "title": "Language Code", "enum": ["en", "fa", "ar", "ur", "ru"], "options": { "enum_titles": ["English", "Persian", "Arabic", "Urdu", "Russian"] } }, "title": { "type": "array", "title": "Explanation Items", "items": { "type": "object", "title": "Explanation Item", "properties": { "title": { "type": "string", "title": "Title" }, "detail": { "type": "string", "title": "Detail", "format": "textarea" } }, "required": ["title", "detail"] } } }, "required": ["language_code", "title"] } } # self.fields['explanation'].widget = JsonEditorWidget(attrs={ # 'schema': json.dumps(explanation_schema), # 'title': 'Explanations' # }) # Custom Forms for JSON Fields class HadisCollectionAdminForm(forms.ModelForm): """Custom form for HadisCollection with JSON editor widgets""" class Meta: model = HadisCollection fields = '__all__' widgets = { 'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget), 'summary': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), } class HadisTagAdminForm(forms.ModelForm): """Custom form for HadisTag with JSON editor widgets""" class Meta: model = HadisTag fields = '__all__' widgets = { 'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget), } class HadisStatusAdminForm(forms.ModelForm): """Custom form for HadisStatus with JSON editor widgets""" class Meta: model = HadisStatus fields = '__all__' widgets = { 'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget), 'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), } class HadisReferenceAdminForm(forms.ModelForm): """Custom form for HadisReference with JSON editor widgets""" class Meta: model = HadisReference fields = '__all__' widgets = { 'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), } # Inline Admin Classes class ReferenceImageInline(TabularInline): """Inline for ReferenceImage in HadisReference admin""" model = ReferenceImage extra = 0 fields = ('thumbnail', 'priority') ordering = ('priority',) class HadisReferenceInline(TabularInline): """Inline for HadisReference in Hadis admin""" model = HadisReference form = HadisReferenceAdminForm extra = 0 fields = ('book_reference', 'description') readonly_fields = ('created_at',) # Main Admin Classes class HadisTagAdmin(ModelAdmin): """Admin for HadisTag model""" form = HadisTagAdminForm list_display = ('get_title_display', 'status', 'created_at') list_filter = ('status', 'created_at') search_fields = ('title',) readonly_fields = ('created_at', 'updated_at') fieldsets = ( (None, { 'fields': ('title', 'status') }), (_('Timestamps'), { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) @display(description=_('Title'), ordering='title') def get_title_display(self, obj): return self._extract_first_text(obj.title) def _extract_first_text(self, json_data): """Helper to safely extract the first 'title' from a JSON list""" if json_data and isinstance(json_data, list) and len(json_data) > 0: first_item = json_data[0] if isinstance(first_item, dict): return first_item.get('title', '-') return '-' class HadisStatusAdmin(ModelAdmin): """Admin for HadisStatus model""" form = HadisStatusAdminForm list_display = ('get_title_display', 'color', 'order', 'get_description_display') list_filter = ('color',) search_fields = ('title', 'description') ordering = ('order',) readonly_fields = ('slug',) fieldsets = ( (None, { 'fields': ('title', 'slug', 'color', 'order', 'description') }), ) @display(description=_('Title'), ordering='title') def get_title_display(self, obj): return self._extract_first_text(obj.title) @display(description=_('Description')) def get_description_display(self, obj): return self._extract_first_text(obj.description) def _extract_first_text(self, json_data): """Helper to safely extract the first 'title' from a JSON list""" if json_data and isinstance(json_data, list) and len(json_data) > 0: first_item = json_data[0] if isinstance(first_item, dict): return first_item.get('title', '-') return '-' class HadisAdmin(ModelAdmin): """Admin for Hadis model""" form = HadisAdminForm list_display = ('number', 'get_title_display', 'category', 'status', 'hadis_status', 'created_at','slug') list_filter = ('status', 'hadis_status', 'category', 'created_at') search_fields = ('title', 'text', 'category__title', 'slug') readonly_fields = ('created_at', 'updated_at', 'share_link', 'slug') ordering = ('category', 'number') inlines = [HadisReferenceInline] filter_horizontal = ('tags',) fieldsets = ( (None, { 'fields': ('category', 'number', 'title', 'title_narrator', 'status', 'slug') }), (_('Content'), { 'fields': ('text', 'translation','description') }), (_('Status & Classification'), { 'fields': ('hadis_status','tags') }), (_('Additional Information'), { 'fields': ('address', 'links', 'share_link'), 'classes': ('collapse',) }), (_('Timestamps'), { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) @display(description=_('Title'), ordering='title') def get_title_display(self, obj): return self._extract_first_text(obj.title) def _extract_first_text(self, json_data): """Helper to safely extract the first 'title' from a JSON list""" if json_data and isinstance(json_data, list) and len(json_data) > 0: first_item = json_data[0] if isinstance(first_item, dict): return first_item.get('title', '-') return '-' class HadisReferenceAdmin(ModelAdmin): """Admin for HadisReference model""" form = HadisReferenceAdminForm list_display = ('hadis', 'book_reference', 'created_at') list_filter = ('created_at', 'book_reference') search_fields = ('hadis__title', 'book_reference__title') readonly_fields = ('created_at',) inlines = [ReferenceImageInline] fieldsets = ( (None, { 'fields': ('hadis', 'book_reference','description') }), (_('Timestamps'), { 'fields': ('created_at',), 'classes': ('collapse',) }), ) class ReferenceImageAdmin(ModelAdmin): """Admin for ReferenceImage model""" list_display = ('reference', 'thumbnail', 'priority') list_filter = ('priority',) search_fields = ('reference__hadis__title', 'reference__book__title') ordering = ('reference', 'priority') fieldsets = ( (None, { 'fields': ('reference', 'thumbnail', 'priority') }), ) class HadisInCollectionInline(TabularInline): """Inline for HadisInCollection in HadisCollection admin""" model = HadisInCollection extra = 0 fields = ('hadis', 'order') ordering = ('order',) class HadisCollectionAdmin(ModelAdmin): """Admin for HadisCollection model""" form = HadisCollectionAdminForm list_display = ('display_header','get_title_display', 'slug', 'status', 'order', 'created_at') list_filter = ('status', 'created_at') search_fields = ('title', 'slug', 'summary') readonly_fields = ('slug', 'created_at', 'updated_at') ordering = ('order',) inlines = [HadisInCollectionInline] fieldsets = ( (None, { 'fields': ('title', 'slug', 'summary', 'status','pin_top', 'order','thumbnail') }), (_('Timestamps'), { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) @display(description=_('Title'), ordering='title') def get_title_display(self, obj): return self._extract_first_text(obj.title) def _extract_first_text(self, json_data): """Helper to safely extract the first 'title' from a JSON list""" if json_data and isinstance(json_data, list) and len(json_data) > 0: first_item = json_data[0] if isinstance(first_item, dict): return first_item.get('title', '-') return '-' @display(description=_("Collection"), header=True) def display_header(self, obj): from django.templatetags.static import static # Get thumbnail image path - use article's thumbnail if available, otherwise use default thumbnail_path = obj.thumbnail.url if obj.thumbnail else None return [ self.get_title_display(obj), None, None, { "path": thumbnail_path, "height": 30, "width": 50, "borderless": True, # "squared": True, }, ] class HadisInCollectionAdmin(ModelAdmin): """Admin for HadisInCollection model""" list_display = ('hadis', 'collection', 'order', 'created_at') list_filter = ('collection', 'created_at') search_fields = ('hadis__title', 'collection__title') readonly_fields = ('created_at',) ordering = ('collection', 'order') fieldsets = ( (None, { 'fields': ('hadis', 'collection', 'order') }), (_('Timestamps'), { 'fields': ('created_at',), 'classes': ('collapse',) }), ) class HadisCorrectionAdminForm(forms.ModelForm): """Custom form for HadisCorrection with JSON editor widgets""" class Meta: model = HadisCorrection fields = '__all__' widgets = { 'title': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextInputWidget), 'description': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), 'translation': MultiLanguageJSONWidget(input_widget_class=UnfoldAdminTextareaWidget), } class HadisCorrectionAdmin(ModelAdmin): """Admin for HadisCorrection model""" form = HadisCorrectionAdminForm list_display = ('hadis', 'get_title_display', 'slug', 'created_at') list_filter = ('created_at', 'hadis__category') search_fields = ('hadis__title', 'title', 'slug') readonly_fields = ('slug', 'created_at', 'updated_at', 'share_link') ordering = ('-created_at',) fieldsets = ( (None, { 'fields': ('hadis', 'title', 'slug') }), (_('Content'), { 'fields': ('description', 'translation') }), (_('Additional Information'), { 'fields': ('share_link',), 'classes': ('collapse',) }), (_('Timestamps'), { 'fields': ('created_at', 'updated_at'), 'classes': ('collapse',) }), ) @display(description=_('Title'), ordering='title') def get_title_display(self, obj): return self._extract_first_text(obj.title) def _extract_first_text(self, json_data): """Helper to safely extract the first 'title' from a JSON list""" if json_data and isinstance(json_data, list) and len(json_data) > 0: first_item = json_data[0] if isinstance(first_item, dict): return first_item.get('title', '-') return '-' # Register models with dovoodi admin site dovoodi_admin_site.register(HadisTag, HadisTagAdmin) dovoodi_admin_site.register(HadisStatus, HadisStatusAdmin) dovoodi_admin_site.register(Hadis, HadisAdmin) dovoodi_admin_site.register(HadisReference, HadisReferenceAdmin) dovoodi_admin_site.register(ReferenceImage, ReferenceImageAdmin) dovoodi_admin_site.register(HadisCollection, HadisCollectionAdmin) dovoodi_admin_site.register(HadisInCollection, HadisInCollectionAdmin) dovoodi_admin_site.register(HadisCorrection, HadisCorrectionAdmin)