Commit 80202e60 authored by Thom Wiggers's avatar Thom Wiggers 📐
Browse files

Merge branch 'feature/activemembers-refactor' into 'master'

Added Society model

Closes #635

See merge request !933
parents 931ceaec ce7f1c89
...@@ -3,65 +3,48 @@ import csv ...@@ -3,65 +3,48 @@ import csv
import datetime import datetime
from django import forms from django import forms
from django.db.models import Q
from django.contrib import admin, messages from django.contrib import admin, messages
from django.contrib.auth.models import Permission from django.db.models import Q
from django.http import HttpResponse from django.http import HttpResponse
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from activemembers import models from activemembers import models
from activemembers.forms import CommitteeMembershipForm from activemembers.forms import MemberGroupMembershipForm, MemberGroupForm
from utils.translation import TranslatedModelAdmin
from utils.snippets import datetime_to_lectureyear from utils.snippets import datetime_to_lectureyear
from utils.translation import TranslatedModelAdmin
class CommitteeMembershipInlineFormSet(forms.BaseInlineFormSet): class MemberGroupMembershipInlineFormSet(forms.BaseInlineFormSet):
""" """
Solely here for performance reasons. Solely here for performance reasons.
Needed because the `__str__()` of `CommitteeMembership` (which is displayed Needed because the `__str__()` of `MemberGroupMembership` (which is displayed
above each inline form) uses the username, name of the member and name of above each inline form) uses the username, name of the member and name of
the committee. the group.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.queryset = self.queryset.select_related( self.queryset = self.queryset.select_related(
'member', 'committee').filter(until=None) 'member', 'group').filter(until=None)
class CommitteeMembershipInline(admin.StackedInline): class MemberGroupMembershipInline(admin.StackedInline):
"""Inline for committee memberships""" """Inline for group memberships"""
model = models.CommitteeMembership model = models.MemberGroupMembership
formset = CommitteeMembershipInlineFormSet formset = MemberGroupMembershipInlineFormSet
can_delete = False can_delete = False
ordering = ('since',) ordering = ('since',)
extra = 0 extra = 0
autocomplete_fields = ('member',) autocomplete_fields = ('member',)
class CommitteeForm(forms.ModelForm):
"""
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'))
@admin.register(models.Committee) @admin.register(models.Committee)
class CommitteeAdmin(TranslatedModelAdmin): class CommitteeAdmin(TranslatedModelAdmin):
"""Manage the committees""" """Manage the committees"""
inlines = (CommitteeMembershipInline,) inlines = (MemberGroupMembershipInline,)
form = CommitteeForm form = MemberGroupForm
list_display = ('name', 'since', 'until', 'active', 'email') list_display = ('name', 'since', 'until', 'active', 'email')
list_filter = ('until', 'active',) list_filter = ('until', 'active',)
search_fields = ('name', 'description') search_fields = ('name', 'description')
...@@ -78,16 +61,33 @@ class CommitteeAdmin(TranslatedModelAdmin): ...@@ -78,16 +61,33 @@ class CommitteeAdmin(TranslatedModelAdmin):
return instance.contact_mailinglist.name + '@thalia.nu' return instance.contact_mailinglist.name + '@thalia.nu'
return None return None
def get_queryset(self, request):
qs = super().get_queryset(request) @admin.register(models.Society)
return qs.exclude(board__is_board=True) 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
@admin.register(models.Board) @admin.register(models.Board)
class BoardAdmin(TranslatedModelAdmin): class BoardAdmin(TranslatedModelAdmin):
"""Manage the board""" """Manage the board"""
inlines = (CommitteeMembershipInline,) inlines = (MemberGroupMembershipInline,)
form = CommitteeForm form = MemberGroupForm
exclude = ('is_board',) exclude = ('is_board',)
filter_horizontal = ('permissions',) filter_horizontal = ('permissions',)
...@@ -95,22 +95,25 @@ class BoardAdmin(TranslatedModelAdmin): ...@@ -95,22 +95,25 @@ class BoardAdmin(TranslatedModelAdmin):
'contact_mailinglist', 'contact_email', 'since', 'until',) 'contact_mailinglist', 'contact_email', 'since', 'until',)
class BoardFilter(admin.SimpleListFilter): class TypeFilter(admin.SimpleListFilter):
"""Filter memberships on board-only""" """Filter memberships on board-only"""
title = _('board memberships') title = _('group memberships')
parameter_name = 'board' parameter_name = 'group_type'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
return [ return [
('only', _('Only board memberships')), ('boards', _('Only boards')),
('none', _('No board memberships')), ('committees', _('Only committees')),
('societies', _('Only societies')),
] ]
def queryset(self, request, queryset): def queryset(self, request, queryset):
if self.value() == 'only': if self.value() == 'boards':
return queryset.filter(committee__board__is_board=True) return queryset.exclude(group__board=None)
elif self.value() == 'none': elif self.value() == 'committees':
return queryset.exclude(committee__board__is_board=True) return queryset.exclude(group__committee=None)
elif self.value() == 'societies':
return queryset.exclude(group__society=None)
return queryset return queryset
...@@ -123,7 +126,7 @@ class LectureYearFilter(admin.SimpleListFilter): ...@@ -123,7 +126,7 @@ class LectureYearFilter(admin.SimpleListFilter):
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
current_year = datetime_to_lectureyear(timezone.now()) current_year = datetime_to_lectureyear(timezone.now())
first_year = datetime_to_lectureyear( first_year = datetime_to_lectureyear(
models.CommitteeMembership.objects.earliest('since').since models.MemberGroupMembership.objects.earliest('since').since
) )
return [(year, '{}-{}'.format(year, year+1)) return [(year, '{}-{}'.format(year, year+1))
...@@ -161,14 +164,14 @@ class ActiveMembershipsFilter(admin.SimpleListFilter): ...@@ -161,14 +164,14 @@ class ActiveMembershipsFilter(admin.SimpleListFilter):
return queryset.filter(until__lt=now) return queryset.filter(until__lt=now)
@admin.register(models.CommitteeMembership) @admin.register(models.MemberGroupMembership)
class CommitteeMembershipAdmin(TranslatedModelAdmin): class MemberGroupMembershipAdmin(TranslatedModelAdmin):
"""Manage the committee memberships""" """Manage the group memberships"""
form = CommitteeMembershipForm form = MemberGroupMembershipForm
list_display = ('member', 'committee', 'since', 'until', 'chair', 'role') list_display = ('member', 'group', 'since', 'until', 'chair', 'role')
list_filter = ('committee', BoardFilter, LectureYearFilter, list_filter = ('group', TypeFilter, LectureYearFilter,
ActiveMembershipsFilter) ActiveMembershipsFilter)
list_select_related = ('member', 'committee',) list_select_related = ('member', 'group',)
search_fields = ('member__first_name', 'member__last_name', search_fields = ('member__first_name', 'member__last_name',
'member__email') 'member__email')
...@@ -176,8 +179,8 @@ class CommitteeMembershipAdmin(TranslatedModelAdmin): ...@@ -176,8 +179,8 @@ class CommitteeMembershipAdmin(TranslatedModelAdmin):
def changelist_view(self, request, extra_context=None): def changelist_view(self, request, extra_context=None):
self.message_user(request, _('Do not edit existing memberships if the ' self.message_user(request, _('Do not edit existing memberships if the '
'chair of a committee has changed, add a ' 'chair of a group has changed, add a '
'new committeemembership instead.'), 'new membership instead.'),
messages.WARNING) messages.WARNING)
return super().changelist_view(request, extra_context) return super().changelist_view(request, extra_context)
...@@ -185,16 +188,16 @@ class CommitteeMembershipAdmin(TranslatedModelAdmin): ...@@ -185,16 +188,16 @@ class CommitteeMembershipAdmin(TranslatedModelAdmin):
response = HttpResponse(content_type='text/csv') response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = ('attachment;' response['Content-Disposition'] = ('attachment;'
'filename=' 'filename='
'"committee_memberships.csv"') '"group_memberships.csv"')
writer = csv.writer(response) writer = csv.writer(response)
writer.writerow([ writer.writerow([
_('First name'), _('First name'),
_('Last name'), _('Last name'),
_('Email'), _('Email'),
_('Committee'), _('Group'),
_('Committee member since'), _('Member since'),
_('Committee member until'), _('Member until'),
_('Chair of the committee'), _('Chair of the group'),
_('Role'), _('Role'),
]) ])
...@@ -203,7 +206,7 @@ class CommitteeMembershipAdmin(TranslatedModelAdmin): ...@@ -203,7 +206,7 @@ class CommitteeMembershipAdmin(TranslatedModelAdmin):
membership.member.first_name, membership.member.first_name,
membership.member.last_name, membership.member.last_name,
membership.member.email, membership.member.email,
membership.committee, membership.group,
membership.since, membership.since,
membership.until, membership.until,
membership.chair, membership.chair,
......
...@@ -8,8 +8,8 @@ from django.utils import timezone ...@@ -8,8 +8,8 @@ from django.utils import timezone
from members.models import Member from members.models import Member
class CommitteeBackend(object): class MemberGroupBackend(object):
"""Check permissions against committees""" """Check permissions against MemberGroups"""
def authenticate(self, *args, **kwargs): def authenticate(self, *args, **kwargs):
"""Not implemented in this backend""" """Not implemented in this backend"""
...@@ -27,15 +27,15 @@ class CommitteeBackend(object): ...@@ -27,15 +27,15 @@ class CommitteeBackend(object):
except Member.DoesNotExist: except Member.DoesNotExist:
return set() return set()
committees = member.committee_set.filter( groups = member.membergroup_set.filter(
Q(committeemembership__until=None) | Q(membergroupmembership__until=None) |
Q(committeemembership__until__gte=timezone.now()) Q(membergroupmembership__until__gte=timezone.now())
) )
perm_cache_name = '_committee_perm_cache' perm_cache_name = '_membergroup_perm_cache'
if not hasattr(user, perm_cache_name): if not hasattr(user, perm_cache_name):
perms = (Permission.objects perms = (Permission.objects
.filter(committee__in=committees) .filter(membergroup__in=groups)
.values_list('content_type__app_label', 'codename') .values_list('content_type__app_label', 'codename')
.order_by()) .order_by())
setattr(user, perm_cache_name, setattr(user, perm_cache_name,
......
[ [
{ {
"model": "activemembers.committee", "model": "activemembers.membergroup",
"pk": 1, "pk": 1,
"fields": { "fields": {
"name_nl": "testcie1", "name_nl": "testcie1",
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
} }
}, },
{ {
"model": "activemembers.committee", "model": "activemembers.membergroup",
"pk": 2, "pk": 2,
"fields": { "fields": {
"name_nl": "testcie2", "name_nl": "testcie2",
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
} }
}, },
{ {
"model": "activemembers.committee", "model": "activemembers.membergroup",
"pk": 3, "pk": 3,
"fields": { "fields": {
"name_nl": "testbestuur1", "name_nl": "testbestuur1",
...@@ -42,11 +42,41 @@ ...@@ -42,11 +42,41 @@
"until": "1991-09-01" "until": "1991-09-01"
} }
}, },
{
"model": "activemembers.membergroup",
"pk": 4,
"fields": {
"name_nl": "testsoc1",
"name_en": "testsoc1",
"active": "True",
"description_nl": "testdesc1",
"description_en": "testdesc1",
"since": "1990-09-01",
"until": "1991-09-01"
}
},
{
"model": "activemembers.committee",
"pk": 1,
"fields": {
}
},
{
"model": "activemembers.committee",
"pk": 2,
"fields": {
}
},
{ {
"model": "activemembers.board", "model": "activemembers.board",
"pk": 3, "pk": 3,
"fields": { "fields": {
"is_board": true }
},
{
"model": "activemembers.society",
"pk": 4,
"fields": {
} }
} }
] ]
"""The forms defined by the activemembers module""" """The forms defined by the activemembers module"""
from django import forms from django import forms
from django.contrib.auth.models import Permission
from activemembers.models import CommitteeMembership from activemembers.models import MemberGroupMembership
from members.models import Member from members.models import Member
class CommitteeMembershipForm(forms.ModelForm): class MemberGroupMembershipForm(forms.ModelForm):
"""Custom form for committee memberships that orders the members""" """Custom form for group memberships that orders the members"""
member = forms.ModelChoiceField( member = forms.ModelChoiceField(
queryset=Member.objects.order_by('first_name', queryset=Member.objects.order_by('first_name',
'last_name')) 'last_name'))
class Meta: class Meta:
model = CommitteeMembership model = MemberGroupMembership
exclude = () exclude = ()
class MemberGroupForm(forms.ModelForm):
"""
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'))
...@@ -7,8 +7,8 @@ msgid "" ...@@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-07-11 20:07+0200\n" "POT-Creation-Date: 2018-09-06 16:13+0200\n"
"PO-Revision-Date: 2018-06-13 20:08+0200\n" "PO-Revision-Date: 2018-09-06 16:12+0200\n"
"Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n" "Last-Translator: Sébastiaan Versteeg <se_bastiaan@outlook.com>\n"
"Language-Team: \n" "Language-Team: \n"
"Language: nl\n" "Language: nl\n"
...@@ -16,245 +16,274 @@ msgstr "" ...@@ -16,245 +16,274 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.0.6\n" "X-Generator: Poedit 2.0.4\n"
#: activemembers/admin.py #: admin.py models.py
msgid "board memberships" msgid "group memberships"
msgstr "bestuurslidmaatschappen" msgstr "groepslidmaatschappen"
#: activemembers/admin.py #: admin.py
msgid "Only board memberships" msgid "Only boards"
msgstr "Alleen bestuurslidmaatschappen" msgstr "Alleen besturen"
#: activemembers/admin.py #: admin.py
msgid "No board memberships" msgid "Only committees"
msgstr "Geen bestuurslidmaatschappen" msgstr "Alleen commissies"
#: activemembers/admin.py #: admin.py
msgid "Only societies"
msgstr "Alleen gezelschappen"
#: admin.py
msgid "lecture year" msgid "lecture year"
msgstr "collegejaar" msgstr "collegejaar"
#: activemembers/admin.py #: admin.py
msgid "active memberships" msgid "active memberships"
msgstr "actieve lidmaatschappen" msgstr "actieve lidmaatschappen"
#: activemembers/admin.py #: admin.py
msgid "Active" msgid "Active"
msgstr "Actief" msgstr "Actief"
#: activemembers/admin.py #: admin.py
msgid "Inactive" msgid "Inactive"
msgstr "Inactief" msgstr "Inactief"
#: activemembers/admin.py #: admin.py
msgid "" msgid ""
"Do not edit existing memberships if the chair of a committee has changed, " "Do not edit existing memberships if the chair of a group has changed, add a "
"add a new committeemembership instead." "new membership instead."
msgstr "" msgstr ""
"Pas geen bestaande lidmaatschappen aan als de voorzitter van een commissie " "Pas geen bestaande lidmaatschappen aan als de voorzitter van een groep is "
"is veranderd. Voeg in de plaats daarvan een nieuw commissielidmaatschap toe." "veranderd. Voeg in de plaats daarvan een nieuw commissielidmaatschap toe."
#: activemembers/admin.py #: admin.py
msgid "First name" msgid "First name"
msgstr "Voornaam" msgstr "Voornaam"
#: activemembers/admin.py #: admin.py
msgid "Last name" msgid "Last name"
msgstr "Achernaam" msgstr "Achernaam"
#: activemembers/admin.py #: admin.py
msgid "Email" msgid "Email"
msgstr "Email" msgstr "Email"
#: activemembers/admin.py activemembers/models.py #: admin.py
msgid "Committee" msgid "Group"
msgstr "Commissie" msgstr "Groep"
#: activemembers/admin.py activemembers/models.py #: admin.py models.py
msgid "Committee member since" msgid "Member since"
msgstr "Commissielid sinds" msgstr "Lid sinds"
#: activemembers/admin.py activemembers/models.py #: admin.py models.py
msgid "Committee member until" msgid "Member until"
msgstr "Commissielid tot" msgstr "Lid tot"
#: activemembers/admin.py activemembers/models.py #: admin.py