Skip to content
Snippets Groups Projects
Forked from KIF / AKPlanning
541 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
admin.py 9.93 KiB
from django.apps import apps
from django.contrib import admin
from django.contrib.admin import SimpleListFilter
from django.db.models import Count, F
from django import forms
from django.shortcuts import render
from django.urls import path, reverse_lazy
from django.utils import timezone
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from rest_framework.reverse import reverse
from simple_history.admin import SimpleHistoryAdmin

from AKModel.availability.forms import AvailabilitiesFormMixin
from AKModel.availability.models import Availability
from AKModel.models import Event, AKOwner, AKCategory, AKTrack, AKTag, AKRequirement, AK, AKSlot, Room, AKOrgaMessage, \
    ConstraintViolation
from AKModel.views import EventStatusView, AKCSVExportView, AKWikiExportView, AKMessageDeleteView


@admin.register(Event)
class EventAdmin(admin.ModelAdmin):
    model = Event
    list_display = ['name', 'status_url', 'place', 'start', 'end', 'active']
    list_filter = ['active']
    list_editable = ['active']
    ordering = ['-start']

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = [
            path('<slug:slug>/status/', self.admin_site.admin_view(EventStatusView.as_view()), name="event_status"),
            path('<slug:event_slug>/ak-csv-export/', self.admin_site.admin_view(AKCSVExportView.as_view()), name="ak_csv_export"),
            path('<slug:event_slug>/ak-wiki-export/', self.admin_site.admin_view(AKWikiExportView.as_view()), name="ak_wiki_export"),
            path('<slug:slug>/delete-orga-messages/', self.admin_site.admin_view(AKMessageDeleteView.as_view()),
                 name="ak_delete_orga_messages"),
        ]
        return custom_urls + urls

    def status_url(self, obj):
        return format_html("<a href='{url}'>{text}</a>",
                           url=reverse_lazy('admin:event_status', kwargs={'slug': obj.slug}), text=_("Status"))
    status_url.short_description = text=_("Status")

    def get_form(self, request, obj=None, change=False, **kwargs):
        # Use timezone of event
        if obj is not None and obj.timezone:
            timezone.activate(obj.timezone)
        # No timezone available? Use UTC
        else:
            timezone.activate("UTC")
        return super().get_form(request, obj, change, **kwargs)


@admin.register(AKOwner)
class AKOwnerAdmin(admin.ModelAdmin):
    model = AKOwner
    list_display = ['name', 'institution', 'event']
    list_filter = ['institution', 'event']
    list_editable = []
    ordering = ['name']

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(AKOwnerAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)


@admin.register(AKCategory)
class AKCategoryAdmin(admin.ModelAdmin):
    model = AKCategory
    list_display = ['name', 'color', 'event']
    list_filter = ['event']
    list_editable = ['color']
    ordering = ['name']

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(AKCategoryAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)


@admin.register(AKTrack)
class AKTrackAdmin(admin.ModelAdmin):
    model = AKTrack
    list_display = ['name', 'color', 'event']
    list_filter = ['event']
    list_editable = ['color']
    ordering = ['name']

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(AKTrackAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)


@admin.register(AKTag)
class AKTagAdmin(admin.ModelAdmin):
    model = AKTag
    list_display = ['name']
    list_filter = []
    list_editable = []
    ordering = ['name']


@admin.register(AKRequirement)
class AKRequirementAdmin(admin.ModelAdmin):
    model = AKRequirement
    list_display = ['name', 'event']
    list_filter = ['event']
    list_editable = []
    ordering = ['name']

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(AKRequirementAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)


class WishFilter(SimpleListFilter):
    title = _("Wish")  # a label for our filter
    parameter_name = 'wishes'  # you can put anything here

    def lookups(self, request, model_admin):
        # This is where you create filter options; we have two:
        return [
            ('WISH', _("Is wish")),
            ('NO_WISH', _("Is not a wish")),
        ]

    def queryset(self, request, queryset):
        annotated_queryset = queryset.annotate(owner_count=Count(F('owners')))
        if self.value() == 'NO_WISH':
            return annotated_queryset.filter(owner_count__gt=0)
        if self.value() == 'WISH':
            return annotated_queryset.filter(owner_count=0)
        return queryset


@admin.register(AK)
class AKAdmin(SimpleHistoryAdmin):
    model = AK
    list_display = ['name', 'short_name', 'category', 'track', 'is_wish', 'interest', 'event']
    list_filter = ['category', WishFilter, 'event']
    list_editable = ['short_name', 'track', 'interest']
    ordering = ['pk']
    actions = ['wiki_export']

    def is_wish(self, obj):
        return obj.wish

    def wiki_export(self, request, queryset):
        return render(request, 'admin/AKModel/wiki_export.html', context={"AKs": queryset})

    wiki_export.short_description = _("Export to wiki syntax")

    is_wish.boolean = True

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(AKAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)


class RoomForm(AvailabilitiesFormMixin, forms.ModelForm):
    class Meta:
        model = Room
        fields = ['name',
                  'location',
                  'capacity',
                  'properties',
                  'event',
                  ]

        widgets = {
            'properties': forms.CheckboxSelectMultiple,
        }

    def __init__(self, *args, **kwargs):
        # Init availability mixin
        kwargs['initial'] = dict()
        super().__init__(*args, **kwargs)
        self.initial = {**self.initial, **kwargs['initial']}


@admin.register(Room)
class RoomAdmin(admin.ModelAdmin):
    model = Room
    list_display = ['name', 'location', 'capacity', 'event']
    list_filter = ['location', 'properties', 'event']
    list_editable = []
    ordering = ['location', 'name']
    change_form_template = "admin/AKModel/room_change_form.html"

    def get_form(self, request, obj=None, change=False, **kwargs):
        if obj is not None:
            return RoomForm
        return super().get_form(request, obj, change, **kwargs)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(RoomAdmin, self).formfield_for_foreignkey(
            db_field, request, **kwargs
        )


@admin.register(AKSlot)
class AKSlotAdmin(admin.ModelAdmin):
    model = AKSlot
    list_display = ['id', 'ak', 'room', 'start', 'duration', 'event']
    list_filter = ['room', 'event']
    list_editable = ['ak', 'room', 'start', 'duration']
    ordering = ['start']

    readonly_fields = ['ak_details_link', 'updated']

    def get_urls(self):
        urls = super().get_urls()
        custom_urls = []
        if apps.is_installed("AKScheduling"):
            from AKScheduling.views import SchedulingAdminView, UnscheduledSlotsAdminView

            custom_urls.extend([
                path('<slug:event_slug>/schedule/', self.admin_site.admin_view(SchedulingAdminView.as_view()),
                     name="schedule"),
                path('<slug:event_slug>/unscheduled/', self.admin_site.admin_view(UnscheduledSlotsAdminView.as_view()),
                     name="slots_unscheduled"),
            ])
        return custom_urls + urls

    def get_form(self, request, obj=None, change=False, **kwargs):
        # Use timezone of associated event
        if obj is not None and obj.event.timezone:
            timezone.activate(obj.event.timezone)
        # No timezone available? Use UTC
        else:
            timezone.activate("UTC")
        return super().get_form(request, obj, change, **kwargs)

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            kwargs['initial'] = Event.get_next_active()
        return super(AKSlotAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

    def ak_details_link(self, akslot):
        if apps.is_installed("AKScheduling") and akslot.ak is not None:
            link = f"<a href={reverse('submit:ak_detail', args=[akslot.event.slug, akslot.ak.pk])}>{str(akslot.ak)}</a>"
            return mark_safe(link)
        return "-"
    ak_details_link.short_description = _('AK Details')


@admin.register(Availability)
class AvailabilityAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, change=False, **kwargs):
        # Use timezone of associated event
        if obj is not None and obj.event.timezone:
            timezone.activate(obj.event.timezone)
        # No timezone available? Use UTC
        else:
            timezone.activate("UTC")
        return super().get_form(request, obj, change, **kwargs)


@admin.register(AKOrgaMessage)
class AKOrgaMessageAdmin(admin.ModelAdmin):
    list_display = ['timestamp', 'ak', 'text']
    list_filter = ['ak__event']
    readonly_fields = ['timestamp', 'ak', 'text']


@admin.register(ConstraintViolation)
class ConstraintViolationAdmin(admin.ModelAdmin):
    list_display = ['type', 'level', 'get_details']
    list_filter = ['event']
    readonly_fields = ['timestamp']