Replace persisted event statuses with publication and cancellation flags, and compute public lifecycle labels from event timing and registration capacity. Keep filters, registration checks, and profile responses aligned with the derived status.
256 lines
9.8 KiB
Python
256 lines
9.8 KiB
Python
from django.contrib import admin
|
|
from django.utils import timezone
|
|
from unfold.admin import ModelAdmin, TabularInline
|
|
|
|
from apps.events.models import Event
|
|
|
|
from .current import (
|
|
AboutAudience,
|
|
AboutContent,
|
|
AboutGalleryImage,
|
|
AboutItem,
|
|
AboutMember,
|
|
AboutMilestone,
|
|
AboutYear,
|
|
HomeContent,
|
|
ListingContent,
|
|
SiteContent,
|
|
)
|
|
|
|
|
|
class FixedContentAdmin(ModelAdmin):
|
|
"""The page records are installed by migration; editors only change them."""
|
|
|
|
list_per_page = 20
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return False
|
|
|
|
|
|
@admin.register(SiteContent)
|
|
class SiteContentAdmin(FixedContentAdmin):
|
|
fieldsets = (
|
|
("Association", {"fields": ("official_name", "short_name", "faculty_subline", "description", "logo", "logo_alt")}),
|
|
("Navigation labels", {"fields": ("nav_home", "nav_about", "nav_events", "nav_blog")}),
|
|
("Contact and footer", {"fields": ("email", "phone", "telegram_url", "instagram_url", "website_url", "address", "footer_copy")}),
|
|
("eNAMAD certificate", {"fields": ("enamad_image", "enamad_image_alt", "enamad_url"), "description": "The badge stays unlinked until you add its verification URL."}),
|
|
("SEO defaults", {"fields": ("seo_title", "seo_description", "seo_image", "seo_image_alt")}),
|
|
)
|
|
|
|
|
|
@admin.register(HomeContent)
|
|
class HomeContentAdmin(FixedContentAdmin):
|
|
fieldsets = (
|
|
("Page introduction", {"fields": ("title", "intro")}),
|
|
("Hero", {"fields": (
|
|
"hero_heading", "hero_body", "hero_image", "hero_image_alt",
|
|
"hero_action_label", "hero_action_url", "hero_secondary_action_label", "hero_secondary_action_url",
|
|
), "description": "Destinations accept an internal path such as /events or a secure https URL."}),
|
|
("Featured events", {"fields": (
|
|
"featured_events_heading", "featured_events_intro", "featured_events_link_label", "featured_events_url", "featured_event_action_label",
|
|
), "description": "Destinations accept an internal path such as /events or a secure https URL."}),
|
|
("Featured blog posts", {"fields": (
|
|
"featured_posts_heading", "featured_posts_intro", "featured_posts_link_label", "featured_posts_url", "featured_post_action_label",
|
|
), "description": "Destinations accept an internal path such as /blog or a secure https URL."}),
|
|
("Participation", {"fields": (
|
|
"participation_heading", "participation_body", "participation_image", "participation_image_alt",
|
|
"participation_action_label", "participation_action_url",
|
|
"participation_secondary_action_label", "participation_secondary_action_url",
|
|
), "description": "Destinations accept an internal path such as /auth or a secure https URL."}),
|
|
("SEO", {"fields": ("seo_title", "seo_description", "seo_image", "seo_image_alt")}),
|
|
)
|
|
|
|
|
|
class AboutItemInline(TabularInline):
|
|
model = AboutItem
|
|
extra = 0
|
|
fields = ("kind", "title", "text", "position")
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).filter(kind="faq")
|
|
|
|
def formfield_for_choice_field(self, db_field, request, **kwargs):
|
|
field = super().formfield_for_choice_field(db_field, request, **kwargs)
|
|
if db_field.name == "kind":
|
|
field.choices = tuple(choice for choice in field.choices if choice[0] == "faq")
|
|
return field
|
|
|
|
def has_add_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
|
|
class AboutAudienceInline(TabularInline):
|
|
model = AboutAudience
|
|
extra = 0
|
|
fields = ("title", "text", "icon", "position")
|
|
ordering = ("position",)
|
|
|
|
def has_add_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
|
|
class AboutMilestoneInline(TabularInline):
|
|
model = AboutMilestone
|
|
extra = 0
|
|
fields = ("year_label", "title", "description", "position")
|
|
ordering = ("position",)
|
|
|
|
def has_add_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
|
|
class AboutMemberInline(TabularInline):
|
|
model = AboutMember
|
|
fk_name = "year_group"
|
|
extra = 0
|
|
fields = ("name", "role", "bio", "photo", "photo_alt", "position")
|
|
ordering = ("position",)
|
|
|
|
def has_add_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
|
|
class LegacyAboutMemberInline(TabularInline):
|
|
model = AboutMember
|
|
fk_name = "about"
|
|
extra = 0
|
|
fields = ("name", "role", "entry_year", "bio", "photo", "photo_alt", "position")
|
|
ordering = ("entry_year", "position")
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).filter(year_group__isnull=True)
|
|
|
|
def has_add_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
|
|
class AboutGalleryInline(TabularInline):
|
|
model = AboutGalleryImage
|
|
extra = 0
|
|
fields = ("image", "image_alt", "caption", "position")
|
|
ordering = ("position",)
|
|
|
|
def has_add_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
|
|
@admin.register(AboutContent)
|
|
class AboutContentAdmin(FixedContentAdmin):
|
|
inlines = (
|
|
AboutItemInline,
|
|
AboutAudienceInline,
|
|
AboutMilestoneInline,
|
|
LegacyAboutMemberInline,
|
|
AboutGalleryInline,
|
|
)
|
|
fieldsets = (
|
|
("Page introduction", {"fields": ("title", "intro", "identity_heading", "identity_body")}),
|
|
("Mission, vision, and values", {"fields": (
|
|
"mission_heading", "mission_body", "vision_heading", "vision_body", "values_heading", "values_body",
|
|
)}),
|
|
("Activities", {"fields": ("activities_heading", "activities_body")}),
|
|
("Association history", {"fields": ("history_heading",)}),
|
|
("Who the association serves", {"fields": ("audience_heading",)}),
|
|
("Annual archive", {"fields": ("members_heading", "members_intro", "year_events_heading")}),
|
|
("Memories gallery", {"fields": ("gallery_heading", "gallery_intro")}),
|
|
("FAQ and call to action", {"fields": (
|
|
"faq_heading", "cta_heading", "cta_body", "cta_action_label", "cta_action_url",
|
|
), "description": "The CTA destination stays empty until you set an internal path or secure https URL."}),
|
|
("SEO", {"fields": ("seo_title", "seo_description", "seo_image", "seo_image_alt")}),
|
|
)
|
|
|
|
|
|
@admin.register(AboutYear)
|
|
class AboutYearAdmin(ModelAdmin):
|
|
list_display = ("year_label", "position")
|
|
list_editable = ("position",)
|
|
ordering = ("position", "pk")
|
|
search_fields = ("year_label",)
|
|
fieldsets = (
|
|
("Academic year", {"fields": ("year_label", "position", "events")}),
|
|
)
|
|
filter_horizontal = ("events",)
|
|
inlines = (AboutMemberInline,)
|
|
|
|
def has_module_permission(self, request):
|
|
return request.user.has_perm("content.change_aboutcontent")
|
|
|
|
def has_view_permission(self, request, obj=None):
|
|
return self.has_module_permission(request)
|
|
|
|
def has_add_permission(self, request):
|
|
return self.has_module_permission(request)
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return self.has_module_permission(request)
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
return self.has_module_permission(request)
|
|
|
|
def get_queryset(self, request):
|
|
return super().get_queryset(request).filter(about_id=1)
|
|
|
|
def save_model(self, request, obj, form, change):
|
|
if not obj.about_id:
|
|
obj.about = AboutContent.objects.get(pk=1)
|
|
super().save_model(request, obj, form, change)
|
|
|
|
def formfield_for_manytomany(self, db_field, request, **kwargs):
|
|
field = super().formfield_for_manytomany(db_field, request, **kwargs)
|
|
if db_field.name == "events":
|
|
field.queryset = Event.objects.filter(
|
|
is_deleted=False,
|
|
is_published=True,
|
|
start_time__lte=timezone.now(),
|
|
).order_by("-start_time", "title")
|
|
return field
|
|
|
|
|
|
@admin.register(ListingContent)
|
|
class ListingContentAdmin(FixedContentAdmin):
|
|
list_display = ("slug", "title")
|
|
readonly_fields = ("slug",)
|
|
fieldsets = (
|
|
("Content", {"fields": ("slug", "title", "intro")}),
|
|
("SEO", {"fields": ("seo_title", "seo_description", "seo_image", "seo_image_alt")}),
|
|
)
|