admin.py 7.47 KB
Newer Older
Thom Wiggers's avatar
Thom Wiggers committed
1
2
3
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.http import HttpResponseRedirect
4
from django.template.defaultfilters import date as _date
5
from django.urls import reverse
Thom Wiggers's avatar
Thom Wiggers committed
6
7
from django.utils import timezone
from django.utils.html import format_html
8
from django.utils.http import is_safe_url
Thom Wiggers's avatar
Thom Wiggers committed
9
from django.utils.translation import ugettext_lazy as _
10

11
from events import services
Thom Wiggers's avatar
Thom Wiggers committed
12
from members.models import Member
13
from pizzas.models import PizzaEvent
14
from utils.translation import TranslatedModelAdmin
15
from . import forms, models
Thom Wiggers's avatar
Thom Wiggers committed
16

Sébastiaan Versteeg's avatar
Sébastiaan Versteeg committed
17

18
19
20
21
22
23
def _do_next(request, response):
    if 'next' in request.GET and is_safe_url(request.GET['next']):
        return HttpResponseRedirect(request.GET['next'])
    else:
        return response

Thom Wiggers's avatar
Thom Wiggers committed
24

25
26
27
28
29
30
class DoNextModelAdmin(TranslatedModelAdmin):
    """
    This class adds processing of a `next` parameter in the urls
    of the add and change admin forms. If it is set and safe this
    override will redirect the user to the provided url.
    """
31

Thom Wiggers's avatar
Thom Wiggers committed
32
33
    def response_add(self, request, obj):
        res = super().response_add(request, obj)
34
        return _do_next(request, res)
Thom Wiggers's avatar
Thom Wiggers committed
35
36
37

    def response_change(self, request, obj):
        res = super().response_change(request, obj)
38
        return _do_next(request, res)
Thom Wiggers's avatar
Thom Wiggers committed
39
40
41


class RegistrationInformationFieldInline(admin.StackedInline):
42
    form = forms.RegistrationInformationFieldForm
Thom Wiggers's avatar
Thom Wiggers committed
43
44
45
46
47
48
    extra = 0
    model = models.RegistrationInformationField
    ordering = ('_order',)

    radio_fields = {'type': admin.VERTICAL}

49
50
51
52
53
54
55
    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        if obj is not None:
            count = obj.registrationinformationfield_set.count()
            formset.form.declared_fields['order'].initial = count
        return formset

Thom Wiggers's avatar
Thom Wiggers committed
56

57
58
59
60
61
62
class PizzaEventInline(admin.StackedInline):
    model = PizzaEvent
    extra = 0
    max_num = 1


Thom Wiggers's avatar
Thom Wiggers committed
63
64
@admin.register(models.Event)
class EventAdmin(DoNextModelAdmin):
65
    inlines = (RegistrationInformationFieldInline, PizzaEventInline,)
66
    fields = ('title', 'description', 'start', 'end', 'organiser', 'category',
67
              'registration_start', 'registration_end', 'cancel_deadline',
68
              'send_cancel_email', 'location', 'map_location', 'price', 'fine',
69
              'max_participants', 'no_registration_message', 'published')
70
    list_display = ('overview_link', 'event_date', 'registration_date',
71
72
                    'num_participants', 'organiser', 'category', 'published',
                    'edit_link')
Thom Wiggers's avatar
Thom Wiggers committed
73
    list_display_links = ('edit_link',)
74
    list_filter = ('start', 'published', 'category')
Thom Wiggers's avatar
Thom Wiggers committed
75
76
77
78
79
80
81
82
83
84
85
    actions = ('make_published', 'make_unpublished')
    date_hierarchy = 'start'
    search_fields = ('title', 'description')
    prepopulated_fields = {'map_location': ('location',)}

    def overview_link(self, obj):
        return format_html('<a href="{link}">{title}</a>',
                           link=reverse('events:admin-details',
                                        kwargs={'event_id': obj.pk}),
                           title=obj.title)

86
    def has_change_permission(self, request, event=None):
87
        if (event is not None and
88
                not services.is_organiser(request.member, event)):
89
            return False
90
91
        return super().has_change_permission(request, event)

92
    def event_date(self, obj):
93
        event_date = timezone.make_naive(obj.start)
94
95
96
97
        return _date(event_date, "l d b Y, G:i")
    event_date.short_description = _('Event Date')

    def registration_date(self, obj):
98
99
100
101
102
        if obj.registration_start is not None:
            start_date = timezone.make_naive(obj.registration_start)
        else:
            start_date = obj.registration_start

103
        return _date(start_date, "l d b Y, G:i")
Milan van Stiphout's avatar
Milan van Stiphout committed
104
    registration_date.short_description = _('Registration Start')
105

Thom Wiggers's avatar
Thom Wiggers committed
106
107
108
109
110
111
112
    def edit_link(self, obj):
        return _('Edit')
    edit_link.short_description = ''

    def num_participants(self, obj):
        """Pretty-print the number of participants"""
        num = (obj.registration_set
Joren Vrancken's avatar
Joren Vrancken committed
113
               .exclude(date_cancelled__lt=timezone.now()).count())
Thom Wiggers's avatar
Thom Wiggers committed
114
115
116
117
118
119
        if not obj.max_participants:
            return '{}/∞'.format(num)
        return '{}/{}'.format(num, obj.max_participants)
    num_participants.short_description = _('Number of participants')

    def make_published(self, request, queryset):
120
        self._change_published(request, queryset, True)
Thom Wiggers's avatar
Thom Wiggers committed
121
122
123
    make_published.short_description = _('Publish selected events')

    def make_unpublished(self, request, queryset):
124
        self._change_published(request, queryset, False)
Thom Wiggers's avatar
Thom Wiggers committed
125
126
    make_unpublished.short_description = _('Unpublish selected events')

127
128
    @staticmethod
    def _change_published(request, queryset, published):
129
130
131
132
        if not request.user.is_superuser:
            queryset = queryset.filter(
                organiser__in=request.member.get_committees())
        queryset.update(published=published)
133

Thom Wiggers's avatar
Thom Wiggers committed
134
135
136
137
    def save_formset(self, request, form, formset, change):
        """Save formsets with their order"""
        formset.save()

138
139
140
141
        informationfield_forms = (
            x for x in formset.forms if
            isinstance(x, forms.RegistrationInformationFieldForm)
        )
Thom Wiggers's avatar
Thom Wiggers committed
142
143
        form.instance.set_registrationinformationfield_order([
            f.instance.pk
144
            for f in sorted(informationfield_forms,
Thom Wiggers's avatar
Thom Wiggers committed
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
                            key=lambda x: (x.cleaned_data['order'],
                                           x.instance.pk))
        ])
        form.instance.save()

    def formfield_for_dbfield(self, db_field, request, **kwargs):
        field = super().formfield_for_dbfield(db_field, request, **kwargs)
        if db_field.name == 'organiser':
            # Disable add/change/delete buttons
            field.widget.can_add_related = False
            field.widget.can_change_related = False
            field.widget.can_delete_related = False
        return field

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'organiser':
            # Use custom queryset for organiser field
162
            # Only get the current active committees the user is a member of
163
164
165
            if not (request.user.is_superuser or
                    request.user.has_perm('events.override_organiser')):
                kwargs['queryset'] = request.member.get_committees()
Thom Wiggers's avatar
Thom Wiggers committed
166
167
        return super().formfield_for_foreignkey(db_field, request, **kwargs)

168
169
170
171
172
    def get_actions(self, request):
        actions = super(EventAdmin, self).get_actions(request)
        del actions['delete_selected']
        return actions

Thom Wiggers's avatar
Thom Wiggers committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192

@admin.register(models.Registration)
class RegistrationAdmin(DoNextModelAdmin):
    """Custom admin for registrations"""

    def formfield_for_dbfield(self, db_field, request, **kwargs):
        field = super().formfield_for_dbfield(db_field, request, **kwargs)
        if db_field.name in ('event', 'member'):
            # Disable add/change/delete buttons
            field.widget.can_add_related = False
            field.widget.can_change_related = False
            field.widget.can_delete_related = False
        return field

    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == 'event':
            # allow to restrict event
            if request.GET.get('event_pk'):
                kwargs['queryset'] = models.Event.objects.filter(
                    pk=int(request.GET['event_pk']))
193
        elif db_field.name == 'member':
194
            kwargs['queryset'] = Member.active_members.all()
Thom Wiggers's avatar
Thom Wiggers committed
195
        return super().formfield_for_foreignkey(db_field, request, **kwargs)