admin.py 7.27 KB
Newer Older
1
"""Registers admin interfaces for the activemembers module"""
2
3
4
5
import csv
import datetime

from django import forms
6
from django.db.models import Q
7
from django.contrib import admin, messages
8
from django.contrib.auth.models import Permission
9
10
11
from django.http import HttpResponse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
12

13
from activemembers import models
14
from activemembers.forms import CommitteeMembershipForm
15
from utils.translation import TranslatedModelAdmin
16
from utils.snippets import datetime_to_lectureyear
Thom Wiggers's avatar
Thom Wiggers committed
17

18

19
class CommitteeMembershipInlineFormSet(forms.BaseInlineFormSet):
20
21
22
23
24
25
26
27
28
29
    """
    Solely here for performance reasons.

    Needed because the `__str__()` of `CommitteeMembership` (which is displayed
    above each inline form) uses the username, name of the member and name of
    the committee.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
30
31
        self.queryset = self.queryset.select_related(
            'member', 'committee').filter(until=None)
32
33


34
class CommitteeMembershipInline(admin.StackedInline):
35
    """Inline for committee memberships"""
36
    model = models.CommitteeMembership
37
    formset = CommitteeMembershipInlineFormSet
38
39
40
    can_delete = False
    ordering = ('since',)
    extra = 0
41
    autocomplete_fields = ('member',)
42
43


44
class CommitteeForm(forms.ModelForm):
45
46
47
48
49
50
51
52
53
54
55
56
57
    """
    Solely here for performance reasons.

    Needed because the `__str__()` of `Permission` (which is displayed in the
    permissions selection box) also prints the corresponding app and
    `content_type` for each permission.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['permissions'].queryset = (Permission
                                               .objects
                                               .select_related('content_type'))
58
59


Thom Wiggers's avatar
Thom Wiggers committed
60
@admin.register(models.Committee)
61
class CommitteeAdmin(TranslatedModelAdmin):
62
    """Manage the committees"""
63
    inlines = (CommitteeMembershipInline,)
64
    form = CommitteeForm
65
66
    list_display = ('name', 'since', 'until', 'active', 'email')
    list_filter = ('until', 'active',)
Joren Vrancken's avatar
Joren Vrancken committed
67
    search_fields = ('name', 'description')
68
    filter_horizontal = ('permissions',)
Thom Wiggers's avatar
Thom Wiggers committed
69

70
    fields = ('name', 'description', 'photo', 'permissions', 'since',
71
72
              'until', 'contact_mailinglist', 'contact_email',
              'wiki_namespace', 'active')
73

74
75
76
77
78
79
80
    def email(self, instance):
        if instance.contact_email:
            return instance.contact_email
        elif instance.contact_mailinglist:
            return instance.contact_mailinglist.name + '@thalia.nu'
        return None

Thom Wiggers's avatar
Thom Wiggers committed
81
82
83
84
85
86
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        return qs.exclude(board__is_board=True)


@admin.register(models.Board)
87
class BoardAdmin(TranslatedModelAdmin):
88
    """Manage the board"""
89
    inlines = (CommitteeMembershipInline,)
90
    form = CommitteeForm
Thom Wiggers's avatar
Thom Wiggers committed
91
    exclude = ('is_board',)
92
    filter_horizontal = ('permissions',)
Thom Wiggers's avatar
Thom Wiggers committed
93

94
95
    fields = ('name', 'description', 'photo', 'permissions',
              'contact_mailinglist', 'contact_email', 'since', 'until',)
96

Thom Wiggers's avatar
Thom Wiggers committed
97

98
class BoardFilter(admin.SimpleListFilter):
99
    """Filter memberships on board-only"""
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    title = _('board memberships')
    parameter_name = 'board'

    def lookups(self, request, model_admin):
        return [
            ('only', _('Only board memberships')),
            ('none', _('No board memberships')),
        ]

    def queryset(self, request, queryset):
        if self.value() == 'only':
            return queryset.filter(committee__board__is_board=True)
        elif self.value() == 'none':
            return queryset.exclude(committee__board__is_board=True)

        return queryset


class LectureYearFilter(admin.SimpleListFilter):
119
    """Filter the memberships on those started or ended in a lecture year"""
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
    title = _('lecture year')
    parameter_name = 'lecture_year'

    def lookups(self, request, model_admin):
        current_year = datetime_to_lectureyear(timezone.now())
        first_year = datetime_to_lectureyear(
                models.CommitteeMembership.objects.earliest('since').since
        )

        return [(year, '{}-{}'.format(year, year+1))
                for year in range(first_year, current_year+1)]

    def queryset(self, request, queryset):
        if not self.value():
            return queryset

        year = int(self.value())
        first_of_september = datetime.date(year=year, month=9, day=1)

        return queryset.exclude(until__lt=first_of_september)


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
class ActiveMembershipsFilter(admin.SimpleListFilter):
    """Filter the memberships by whether they are active or not"""
    title = _('active memberships')
    parameter_name = 'active'

    def lookups(self, request, model_name):
        return (
            ('active', _('Active')),
            ('inactive', _('Inactive')),
        )

    def queryset(self, request, queryset):
        now = timezone.now()

        if self.value() == 'active':
            return queryset.filter(Q(until__isnull=True) |
                                   Q(until__gte=now))

        if self.value() == 'inactive':
            return queryset.filter(until__lt=now)


Thom Wiggers's avatar
Thom Wiggers committed
164
@admin.register(models.CommitteeMembership)
165
class CommitteeMembershipAdmin(TranslatedModelAdmin):
166
    """Manage the committee memberships"""
167
    form = CommitteeMembershipForm
168
    list_display = ('member', 'committee', 'since', 'until', 'chair', 'role')
169
170
    list_filter = ('committee', BoardFilter, LectureYearFilter,
                   ActiveMembershipsFilter)
171
    list_select_related = ('member', 'committee',)
172
173
    search_fields = ('member__first_name', 'member__last_name',
                     'member__email')
174

175
176
    actions = ('export',)

177
178
179
180
181
182
183
    def changelist_view(self, request, extra_context=None):
        self.message_user(request, _('Do not edit existing memberships if the '
                                     'chair of a committee has changed, add a '
                                     'new committeemembership instead.'),
                          messages.WARNING)
        return super().changelist_view(request, extra_context)

184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    def export(self, request, queryset):
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = ('attachment;'
                                           'filename='
                                           '"committee_memberships.csv"')
        writer = csv.writer(response)
        writer.writerow([
            _('First name'),
            _('Last name'),
            _('Email'),
            _('Committee'),
            _('Committee member since'),
            _('Committee member until'),
            _('Chair of the committee'),
            _('Role'),
        ])

        for membership in queryset:
            writer.writerow([
                membership.member.first_name,
                membership.member.last_name,
                membership.member.email,
                membership.committee,
                membership.since,
                membership.until,
                membership.chair,
                membership.role,
            ])

        return response
    export.short_description = _('Export selected memberships')

216
217

@admin.register(models.Mentorship)
218
class MentorshipAdmin(admin.ModelAdmin):
219
    """Manage the mentorships"""
220
    list_select_related = ('member',)