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.
155 lines
6.8 KiB
Python
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.')
|