from django.contrib import admin from django.http import FileResponse, Http404, HttpResponseRedirect from django.urls import path, reverse from django.utils.html import format_html from .models import ( AboutSection, AboutSectionItem, ContactSubmission, ContactSubmissionAttachment, CustomPage, CustomPageSection, CustomPageSectionItem, DownloadItem, FAQEntry, HeroSection, HomepageSection, HomepageSectionItem, ) @admin.register(HeroSection) class HeroSectionAdmin(admin.ModelAdmin): fieldsets = ( ("Badge", {"fields": ("badge",)}), ("Title", {"fields": ("title", "title_highlight")}), ("Text", {"fields": ("subtitle", "description")}), ("Primary Button", {"fields": ("primary_cta_text", "primary_cta_url")}), ("Secondary Button", {"fields": ("secondary_cta_text", "secondary_cta_url")}), ("Image", {"fields": ("image", "image_alt")}), ) def has_add_permission(self, request): return not HeroSection.objects.exists() def has_delete_permission(self, request, obj=None): return False def changelist_view(self, request, extra_context=None): hero = HeroSection.objects.first() if hero: return HttpResponseRedirect( reverse("admin:pages_herosection_change", args=[hero.pk]) ) return super().changelist_view(request, extra_context) class HomepageSectionItemInline(admin.TabularInline): model = HomepageSectionItem extra = 1 fields = ("icon", "title", "content", "url", "image", "order") ordering = ("order",) @admin.register(HomepageSection) class HomepageSectionAdmin(admin.ModelAdmin): list_display = ("section_type", "title", "badge", "order", "is_active") list_filter = ("section_type", "is_active") list_editable = ("order", "is_active") inlines = [HomepageSectionItemInline] fieldsets = ( (None, {"fields": ("section_type", "badge", "title", "description")}), ("CTA Link (About Strip)", {"fields": ("link_text", "link_url"), "classes": ("collapse",)}), ("Settings", {"fields": ("order", "is_active")}), ) class AboutSectionItemInline(admin.TabularInline): model = AboutSectionItem extra = 1 fields = ("icon", "title", "content", "url", "image", "image_alt", "badge", "is_featured", "order") ordering = ("order",) @admin.register(AboutSection) class AboutSectionAdmin(admin.ModelAdmin): list_display = ("section_type", "badge", "title", "order", "is_active") list_filter = ("section_type", "is_active") list_editable = ("order", "is_active") inlines = [AboutSectionItemInline] fieldsets = ( (None, {"fields": ("section_type", "badge", "title", "subtitle")}), ("Content", {"fields": ("content_format", "content")}), ("Settings", {"fields": ("order", "is_active")}), ) class ContactSubmissionAttachmentInline(admin.TabularInline): model = ContactSubmissionAttachment extra = 0 can_delete = False fields = ("original_filename", "attachment_link", "uploaded_at") readonly_fields = ("original_filename", "attachment_link", "uploaded_at") @admin.display(description="File") def attachment_link(self, obj): if not obj.file: return "—" url = reverse("admin:pages_contactattachment_download", args=[obj.pk]) return format_html('Download', url) @admin.register(ContactSubmission) class ContactSubmissionAdmin(admin.ModelAdmin): list_display = ("name", "title", "email", "submitted_at", "is_read") list_filter = ("is_read", "submitted_at") search_fields = ("name", "title", "description", "email") list_editable = ("is_read",) readonly_fields = ("name", "title", "description", "email", "submitted_at") inlines = [ContactSubmissionAttachmentInline] fieldsets = ( (None, {"fields": ("name", "title", "email", "description")}), ("Meta", {"fields": ("submitted_at", "is_read")}), ) def get_urls(self): urls = super().get_urls() custom_urls = [ path( "attachment//download/", self.admin_site.admin_view(self.download_attachment), name="pages_contactattachment_download", ), ] return custom_urls + urls def download_attachment(self, request, attachment_id): try: attachment = ContactSubmissionAttachment.objects.get(pk=attachment_id) except ContactSubmissionAttachment.DoesNotExist as exc: raise Http404 from exc if not attachment.file: raise Http404 return FileResponse( attachment.file.open("rb"), as_attachment=True, filename=attachment.original_filename, ) @admin.register(FAQEntry) class FAQEntryAdmin(admin.ModelAdmin): list_display = ("question", "order", "is_active", "created_at") list_filter = ("is_active",) search_fields = ("question", "answer") list_editable = ("order", "is_active") fieldsets = ( (None, {"fields": ("question",)}), ("Answer", {"fields": ("answer_format", "answer")}), ("Settings", {"fields": ("order", "is_active")}), ) class CustomPageSectionItemInline(admin.TabularInline): model = CustomPageSectionItem extra = 1 fields = ( "icon", "badge", "title", "content_format", "content", "url", "image", "image_alt", "is_featured", "order", ) ordering = ("order",) class CustomPageSectionInline(admin.StackedInline): model = CustomPageSection extra = 1 fields = ( "section_type", "badge", "title", "subtitle", "description", "content_format", "content", "link_text", "link_url", "order", "is_active", ) ordering = ("order",) show_change_link = True class CustomPageSectionItemOnPageInline(admin.TabularInline): model = CustomPageSectionItem fk_name = "page" extra = 1 verbose_name = "Section item" verbose_name_plural = "Section items (subsections)" fields = ( "section", "icon", "badge", "title", "content_format", "content", "url", "image", "order", ) ordering = ("section", "order") def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "section": page_id = request.resolver_match.kwargs.get("object_id") if request.resolver_match else None if page_id: kwargs["queryset"] = CustomPageSection.objects.filter(page_id=page_id).order_by("order") return super().formfield_for_foreignkey(db_field, request, **kwargs) class CustomPageSectionAdmin(admin.ModelAdmin): list_display = ("page", "section_type", "title", "order", "is_active") list_filter = ("section_type", "is_active", "page") list_editable = ("order", "is_active") inlines = [CustomPageSectionItemInline] fieldsets = ( (None, {"fields": ("page", "section_type", "badge", "title", "subtitle")}), ("Text", {"fields": ("description", "content_format", "content")}), ("CTA Link", {"fields": ("link_text", "link_url"), "classes": ("collapse",)}), ("Settings", {"fields": ("order", "is_active")}), ) def save_formset(self, request, form, formset, change): instances = formset.save(commit=False) for instance in instances: if isinstance(instance, CustomPageSectionItem): instance.page = form.instance.page instance.save() for obj in formset.deleted_objects: obj.delete() formset.save_m2m() @admin.register(CustomPage) class CustomPageAdmin(admin.ModelAdmin): list_display = ("title", "slug", "show_in_nav", "menu_order", "is_published", "updated_at") list_filter = ("show_in_nav", "is_published") search_fields = ("title", "slug", "menu_label") list_editable = ("show_in_nav", "menu_order", "is_published") prepopulated_fields = {"slug": ("title",)} inlines = [CustomPageSectionInline, CustomPageSectionItemOnPageInline] fieldsets = ( (None, {"fields": ("title", "slug", "menu_label", "meta_description")}), ("Navigation", {"fields": ("show_in_nav", "menu_order")}), ("Publishing", {"fields": ("is_published",)}), ) def save_formset(self, request, form, formset, change): instances = formset.save(commit=False) for instance in instances: if isinstance(instance, CustomPageSectionItem): instance.page = form.instance instance.save() for obj in formset.deleted_objects: obj.delete() formset.save_m2m() admin.site.register(CustomPageSection, CustomPageSectionAdmin) @admin.register(DownloadItem) class DownloadItemAdmin(admin.ModelAdmin): list_display = ("name", "platform", "version", "is_active", "order") list_filter = ("platform", "is_active") search_fields = ("name", "description") list_editable = ("order", "is_active") fieldsets = ( (None, {"fields": ("name", "platform", "version", "download_url", "description")}), ("Settings", {"fields": ("order", "is_active")}), )