admin.py 6.61 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.contrib import admin, messages
7
from django.db.models import Q
8
9
10
from django.http import HttpResponse
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
11

12
from activemembers import models
13
from activemembers.forms import MemberGroupMembershipForm, MemberGroupForm
14
from utils.snippets import datetime_to_lectureyear
15
from utils.translation import TranslatedModelAdmin
Thom Wiggers's avatar
Thom Wiggers committed
16

17

18
class MemberGroupMembershipInlineFormSet(forms.BaseInlineFormSet):
19
20
21
    """
    Solely here for performance reasons.

Thom Wiggers's avatar
Thom Wiggers committed
22
23
24
    Needed because the `__str__()` of `MemberGroupMembership` (which is
    displayed above each inline form) uses the username, name of the member
    and name of the group.
25
26
27
28
    """

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


33
34
35
36
class MemberGroupMembershipInline(admin.StackedInline):
    """Inline for group memberships"""
    model = models.MemberGroupMembership
    formset = MemberGroupMembershipInlineFormSet
37
38
39
    can_delete = False
    ordering = ('since',)
    extra = 0
40
    autocomplete_fields = ('member',)
41
42


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@admin.register(models.Society)
class CommitteeAdmin(TranslatedModelAdmin):
    """Manage the societies"""
    inlines = (MemberGroupMembershipInline,)
    form = MemberGroupForm
    list_display = ('name', 'since', 'until', 'active', 'email')
    list_filter = ('until', 'active',)
    search_fields = ('name', 'description')
    filter_horizontal = ('permissions',)

    fields = ('name', 'description', 'photo', 'permissions', 'since',
              'until', 'contact_mailinglist', 'contact_email', 'active')

    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
62
63
64


@admin.register(models.Board)
65
class BoardAdmin(TranslatedModelAdmin):
66
    """Manage the board"""
67
    inlines = (MemberGroupMembershipInline,)
68
    form = MemberGroupForm
Thom Wiggers's avatar
Thom Wiggers committed
69
    exclude = ('is_board',)
70
    filter_horizontal = ('permissions',)
Thom Wiggers's avatar
Thom Wiggers committed
71

72
73
    fields = ('name', 'description', 'photo', 'permissions',
              'contact_mailinglist', 'contact_email', 'since', 'until',)
74

Thom Wiggers's avatar
Thom Wiggers committed
75

76
class TypeFilter(admin.SimpleListFilter):
77
    """Filter memberships on board-only"""
78
79
    title = _('group memberships')
    parameter_name = 'group_type'
80
81
82

    def lookups(self, request, model_admin):
        return [
83
84
85
            ('boards', _('Only boards')),
            ('committees', _('Only committees')),
            ('societies', _('Only societies')),
86
87
88
        ]

    def queryset(self, request, queryset):
89
        if self.value() == 'boards':
90
            return queryset.exclude(group__board=None)
91
92
93
94
        elif self.value() == 'committees':
            return queryset.exclude(group__committee=None)
        elif self.value() == 'societies':
            return queryset.exclude(group__society=None)
95
96
97
98
99

        return queryset


class LectureYearFilter(admin.SimpleListFilter):
100
    """Filter the memberships on those started or ended in a lecture year"""
101
102
103
104
105
106
    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(
107
                models.MemberGroupMembership.objects.earliest('since').since
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
        )

        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)


123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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)


145
146
147
148
149
@admin.register(models.MemberGroupMembership)
class MemberGroupMembershipAdmin(TranslatedModelAdmin):
    """Manage the group memberships"""
    form = MemberGroupMembershipForm
    list_display = ('member', 'group', 'since', 'until', 'chair', 'role')
150
    list_filter = ('group', TypeFilter, LectureYearFilter,
151
                   ActiveMembershipsFilter)
152
    list_select_related = ('member', 'group',)
153
154
    search_fields = ('member__first_name', 'member__last_name',
                     'member__email')
155

156
157
    actions = ('export',)

158
159
    def changelist_view(self, request, extra_context=None):
        self.message_user(request, _('Do not edit existing memberships if the '
160
161
                                     'chair of a group has changed, add a '
                                     'new membership instead.'),
162
163
164
                          messages.WARNING)
        return super().changelist_view(request, extra_context)

165
166
167
168
    def export(self, request, queryset):
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = ('attachment;'
                                           'filename='
169
                                           '"group_memberships.csv"')
170
171
172
173
174
        writer = csv.writer(response)
        writer.writerow([
            _('First name'),
            _('Last name'),
            _('Email'),
175
176
177
178
            _('Group'),
            _('Member since'),
            _('Member until'),
            _('Chair of the group'),
179
180
181
182
183
184
185
186
            _('Role'),
        ])

        for membership in queryset:
            writer.writerow([
                membership.member.first_name,
                membership.member.last_name,
                membership.member.email,
187
                membership.group,
188
189
190
191
192
193
194
195
196
                membership.since,
                membership.until,
                membership.chair,
                membership.role,
            ])

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

197
198

@admin.register(models.Mentorship)
199
class MentorshipAdmin(admin.ModelAdmin):
200
    """Manage the mentorships"""
201
    list_select_related = ('member',)