initial commit
This commit is contained in:
@@ -0,0 +1,330 @@
|
||||
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 apps.core.admin_video import video_admin_preview
|
||||
from apps.core.video import VIDEO_ADMIN_FIELDSET
|
||||
|
||||
from .models import (
|
||||
AboutSection,
|
||||
AboutSectionItem,
|
||||
ContactSubmission,
|
||||
ContactSubmissionAttachment,
|
||||
CustomPage,
|
||||
CustomPageSection,
|
||||
CustomPageSectionItem,
|
||||
DownloadItem,
|
||||
FAQEntry,
|
||||
HeroSection,
|
||||
HomepageSection,
|
||||
HomepageSectionItem,
|
||||
PageVideo,
|
||||
)
|
||||
|
||||
|
||||
@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",
|
||||
"image_alt",
|
||||
"tags",
|
||||
"project_status",
|
||||
"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]
|
||||
readonly_fields = ("video_preview",)
|
||||
fieldsets = (
|
||||
(None, {"fields": ("section_type", "badge", "title", "title_highlight", "description_format", "description")}),
|
||||
("CTA Link (About Strip)", {"fields": ("link_text", "link_url"), "classes": ("collapse",)}),
|
||||
VIDEO_ADMIN_FIELDSET,
|
||||
("Settings", {"fields": ("order", "is_active")}),
|
||||
)
|
||||
|
||||
@admin.display(description="Preview")
|
||||
def video_preview(self, obj):
|
||||
return video_admin_preview(obj)
|
||||
|
||||
|
||||
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]
|
||||
readonly_fields = ("video_preview",)
|
||||
fieldsets = (
|
||||
(None, {"fields": ("section_type", "badge", "title", "subtitle")}),
|
||||
("Content", {"fields": ("content_format", "content")}),
|
||||
VIDEO_ADMIN_FIELDSET,
|
||||
("Settings", {"fields": ("order", "is_active")}),
|
||||
)
|
||||
|
||||
@admin.display(description="Preview")
|
||||
def video_preview(self, obj):
|
||||
return video_admin_preview(obj)
|
||||
|
||||
|
||||
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('<a href="{}">Download</a>', 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/<int:attachment_id>/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_format",
|
||||
"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]
|
||||
readonly_fields = ("video_preview",)
|
||||
fieldsets = (
|
||||
(None, {"fields": ("page", "section_type", "badge", "title", "subtitle")}),
|
||||
("Text", {"fields": ("description_format", "description", "content_format", "content")}),
|
||||
("CTA Link", {"fields": ("link_text", "link_url"), "classes": ("collapse",)}),
|
||||
VIDEO_ADMIN_FIELDSET,
|
||||
("Settings", {"fields": ("order", "is_active")}),
|
||||
)
|
||||
|
||||
@admin.display(description="Preview")
|
||||
def video_preview(self, obj):
|
||||
return video_admin_preview(obj)
|
||||
|
||||
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(PageVideo)
|
||||
class PageVideoAdmin(admin.ModelAdmin):
|
||||
list_display = ("page", "title", "video_source", "video_size", "order", "is_active")
|
||||
list_filter = ("page", "video_source", "is_active")
|
||||
list_editable = ("order", "is_active")
|
||||
search_fields = ("title", "description", "video_url")
|
||||
readonly_fields = ("video_preview",)
|
||||
fieldsets = (
|
||||
(None, {"fields": ("page", "badge", "title", "description_format", "description")}),
|
||||
VIDEO_ADMIN_FIELDSET,
|
||||
("Settings", {"fields": ("order", "is_active")}),
|
||||
)
|
||||
|
||||
@admin.display(description="Preview")
|
||||
def video_preview(self, obj):
|
||||
return video_admin_preview(obj)
|
||||
|
||||
|
||||
@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")}),
|
||||
)
|
||||
Reference in New Issue
Block a user