Files
guilan-ace-backend/apps/events/admin.py
Amirhossein Khalili 3ec28638d1 feat: replace email flows with in-app notifications
Add recipient notification detail and filtering, a queued admin composer, and contextual automatic titles. Retire email delivery, obsolete auth routes, newsletter data, and related templates and settings.
2026-09-26 12:23:10 +03:30

155 lines
6.8 KiB
Python

from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from core.admin import BaseModelAdmin, SoftDeleteListFilter
from core.templatetags.jalali import jdate
from apps.events.models import Event, Registration
from apps.events.resources import EventResource, RegistrationResource
@admin.register(Event)
class EventAdmin(BaseModelAdmin, ImportExportModelAdmin):
resource_class = EventResource
list_display = (
'title', 'event_type', 'start_time_display', 'end_time_display', 'status',
'price_display', 'capacity_display', 'attendees_display', 'is_registration_open_display',
)
list_filter = (
'event_type', 'status', 'is_deleted', 'start_time', 'end_time',
'registration_start_date', 'registration_end_date', SoftDeleteListFilter,
)
search_fields = ('title', 'description', 'address')
prepopulated_fields = {'slug': ('title',)}
date_hierarchy = 'start_time'
filter_horizontal = ('gallery_images',)
fieldsets = (
('Event Details', {'fields': ('title', 'slug', 'description', 'featured_image')}),
('Timing & Type', {'fields': ('start_time', 'end_time', 'event_type', 'status')}),
('Location & Online', {
'fields': ('address', 'location', 'online_link'),
'description': 'For On-Site or Hybrid events, provide address and select on map. For Online events, provide a link.',
}),
('Registration & Pricing', {
'fields': ('capacity', 'price', 'registration_start_date', 'registration_end_date', 'registration_success_markdown'),
'description': 'Leave capacity blank for unlimited. Leave price blank for free events.',
}),
('Gallery', {'fields': ('gallery_images',), 'description': 'Add images related to this event from the Gallery app.'}),
('Soft Delete', {'fields': ('is_deleted', 'deleted_at'), 'classes': ('collapse',)}),
)
readonly_fields = ('deleted_at',)
actions = BaseModelAdmin.actions + [
'make_published', 'make_draft', 'make_cancelled', 'make_completed', 'restore_events',
]
@admin.display(description='Price')
def price_display(self, obj):
return obj.price if obj.price is not None else 'رایگان'
@admin.display(description='Start')
def start_time_display(self, obj):
return jdate(obj.start_time)
@admin.display(description='End')
def end_time_display(self, obj):
return jdate(obj.end_time)
@admin.display(description='Capacity')
def capacity_display(self, obj):
return obj.capacity if obj.capacity is not None else 'نامحدود'
@admin.display(description='Attendees')
def attendees_display(self, obj):
return obj.current_attendees_count
@admin.display(description='Open', boolean=True)
def is_registration_open_display(self, obj):
return obj.is_registration_open
@admin.action(description='Mark selected events as published')
def make_published(self, request, queryset):
queryset.update(status=Event.StatusChoices.PUBLISHED)
self.message_user(request, f'Published {queryset.count()} events.')
@admin.action(description='Mark selected events as draft')
def make_draft(self, request, queryset):
queryset.update(status=Event.StatusChoices.DRAFT)
self.message_user(request, f'Marked {queryset.count()} events as draft.')
@admin.action(description='Mark selected events as cancelled')
def make_cancelled(self, request, queryset):
queryset.update(status=Event.StatusChoices.CANCELLED)
self.message_user(request, f'Cancelled {queryset.count()} events.')
@admin.action(description='Mark selected events as completed')
def make_completed(self, request, queryset):
queryset.update(status=Event.StatusChoices.COMPLETED)
self.message_user(request, f'Completed {queryset.count()} events.')
@admin.action(description='Restore selected events')
def restore_events(self, request, queryset):
for event in queryset:
event.restore()
self.message_user(request, f'Restored {queryset.count()} events.')
@admin.register(Registration)
class RegistrationAdmin(BaseModelAdmin, ImportExportModelAdmin):
resource_class = RegistrationResource
list_display = (
'user', 'event', 'status', 'registered_at', 'ticket_id',
'discount_code', 'discount_amount', 'final_price',
)
list_filter = ('status', 'event', 'is_deleted', 'registered_at', SoftDeleteListFilter)
search_fields = (
'user__username', 'user__email', 'user__first_name', 'user__last_name',
'event__title', 'ticket_id',
)
readonly_fields = (
'ticket_id', 'registered_at', 'confirmation_notification_sent_at',
'cancellation_notification_sent_at', 'discount_code', 'discount_amount',
'final_price', 'deleted_at',
)
fieldsets = (
('Registration Details', {'fields': (
'user', 'event', 'status', 'registered_at', 'ticket_id',
'confirmation_notification_sent_at', 'cancellation_notification_sent_at',
)}),
('Pricing & Discount', {
'fields': ('discount_code', 'discount_amount', 'final_price'),
'classes': ('collapse',),
}),
('Soft Delete', {'fields': ('is_deleted', 'deleted_at'), 'classes': ('collapse',)}),
)
actions = BaseModelAdmin.actions + [
'confirm_registrations', 'cancel_registrations', 'mark_attended', 'restore_registrations',
]
@admin.action(description='Confirm selected registrations')
def confirm_registrations(self, request, queryset):
count = 0
for registration in queryset:
registration.status = Registration.StatusChoices.CONFIRMED
registration.save(update_fields=['status'])
count += 1
self.message_user(request, f'Confirmed {count} registrations.')
@admin.action(description='Cancel selected registrations')
def cancel_registrations(self, request, queryset):
count = 0
for registration in queryset:
registration.status = Registration.StatusChoices.CANCELLED
registration.save(update_fields=['status'])
count += 1
self.message_user(request, f'Cancelled {count} registrations.')
@admin.action(description='Mark selected registrations as attended')
def mark_attended(self, request, queryset):
queryset.update(status=Registration.StatusChoices.ATTENDED)
self.message_user(request, f'Marked {queryset.count()} registrations as attended.')
@admin.action(description='Restore selected registrations')
def restore_registrations(self, request, queryset):
for registration in queryset:
registration.restore()
self.message_user(request, f'Restored {queryset.count()} registrations.')