from django.contrib import admin from django.contrib.humanize.templatetags.humanize import naturaltime from django.utils.html import format_html from django_object_actions import ( DjangoObjectActions, action, takes_instance_or_queryset, ) from django_q.models import Task from django_q.tasks import async_task from .models import ( Event, EventExt, EventInstructor, EventInvoice, EventMeetingTime, Flag, Member, Transaction, ) from .tasks.scrape import ( scrape_event_details, scrape_membershipworks, ) from .tasks.ucsAccounts import sync_accounts class ReadOnlyAdmin(admin.ModelAdmin): def has_add_permission(self, request, obj=None): return False def has_change_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False class BaseMembershipWorksAdmin(DjangoObjectActions, ReadOnlyAdmin): changelist_actions = ("refresh_membershipworks_data", "sync_ucs_accounts") # internal method from DjangoObjectActions def _get_tool_dict(self, tool_name): tool = super(DjangoObjectActions, self)._get_tool_dict(tool_name) if tool_name == "refresh_membershipworks_data": try: last_run_time = naturaltime( Task.objects.filter(group=scrape_membershipworks.q_task_group) .values_list("started", flat=True) .latest("started") ) except Task.DoesNotExist: last_run_time = "Never" tool["label"] = f"Refresh Data [Last Run {last_run_time}]" return tool @action def refresh_membershipworks_data(self, request, obj): async_task(scrape_membershipworks, group=scrape_membershipworks.q_task_group) self.message_user( request, "Queued refresh, please wait a few seconds/minutes then refresh the page", ) @action def sync_ucs_accounts(self, request, obj): async_task(sync_accounts, group=sync_accounts.q_task_group) self.message_user( request, "Queued refresh, please wait a few seconds/minutes then refresh the page", ) class MemberFlagInline(admin.TabularInline): model = Member.flags.through @admin.register(Member) class MemberAdmin(BaseMembershipWorksAdmin): search_fields = ["^first_name", "^last_name", "^account_name"] inlines = [MemberFlagInline] @admin.register(Flag) class FlagAdmin(BaseMembershipWorksAdmin): inlines = [MemberFlagInline] list_display = ["name", "type"] list_filter = ["type"] show_facets = admin.ShowFacets.ALWAYS search_fields = ["name"] @admin.register(Transaction) class TransactionAdmin(BaseMembershipWorksAdmin): list_display = ["timestamp", "member", "name", "type", "sum", "note"] list_filter = ["type"] show_facets = admin.ShowFacets.ALWAYS search_fields = ["member", "name", "type", "note"] date_hierarchy = "timestamp" class EventMeetingTimeInline(admin.TabularInline): model = EventMeetingTime extra = 0 min_num = 1 readonly_fields = ["duration"] # TODO: remove when switched to GeneratedField @admin.display() def duration(self, obj): return obj.duration @admin.register(EventInstructor) class EventInstructorAdmin(admin.ModelAdmin): autocomplete_fields = ["member"] search_fields = ["name", "member__account_name"] class EventInvoiceInline(admin.StackedInline): model = EventInvoice @admin.register(EventExt) class EventAdmin(DjangoObjectActions, admin.ModelAdmin): inlines = [EventInvoiceInline, EventMeetingTimeInline] list_display = [ "unescaped_title", "start", "duration", "count", "cap", "category", ] list_filter = [ "category", "calendar", "venue", ("materials_fee", admin.EmptyFieldListFilter), ] show_facets = admin.ShowFacets.ALWAYS search_fields = ["eid", "title", "url"] date_hierarchy = "start" exclude = ["url", "details"] autocomplete_fields = ["instructor"] change_actions = ["fetch_details"] actions = ["fetch_details"] @property def readonly_fields(self): fields = [] for field in Event._meta.get_fields(): if field.auto_created or field.many_to_many or not field.concrete: continue elif field.name == "url": fields.append("_url") else: fields.append(field.name) fields.insert(fields.index("end") + 1, "duration") fields.append("details_timestamp") return fields @admin.display(ordering="title") def unescaped_title(self, obj): return obj.unescaped_title @admin.display(ordering="duration") def duration(self, obj): return obj.duration @admin.display(description="URL") def _url(self, obj): return format_html( '{0}', obj.url, ) @takes_instance_or_queryset def fetch_details(self, request, queryset): scrape_event_details(queryset) def has_add_permission(self, request, obj=None): return False def has_delete_permission(self, request, obj=None): return False