Verified Commit b6e054d4 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg
Browse files

Modify all usages of MemberGroup to take Society into account or use Committee if applicable

parent be6109fb
...@@ -3,17 +3,16 @@ import csv ...@@ -3,17 +3,16 @@ 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 MemberGroupMembershipForm 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 MemberGroupMembershipInlineFormSet(forms.BaseInlineFormSet): class MemberGroupMembershipInlineFormSet(forms.BaseInlineFormSet):
...@@ -41,27 +40,11 @@ class MemberGroupMembershipInline(admin.StackedInline): ...@@ -41,27 +40,11 @@ class MemberGroupMembershipInline(admin.StackedInline):
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 = (MemberGroupMembershipInline,) 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=None) 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 = (MemberGroupMembershipInline,) 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.exclude(group__board=None) return queryset.exclude(group__board=None)
elif self.value() == 'none': elif self.value() == 'committees':
return queryset.filter(group__board=None) return queryset.exclude(group__committee=None)
elif self.value() == 'societies':
return queryset.exclude(group__society=None)
return queryset return queryset
...@@ -166,7 +169,7 @@ class MemberGroupMembershipAdmin(TranslatedModelAdmin): ...@@ -166,7 +169,7 @@ class MemberGroupMembershipAdmin(TranslatedModelAdmin):
"""Manage the group memberships""" """Manage the group memberships"""
form = MemberGroupMembershipForm form = MemberGroupMembershipForm
list_display = ('member', 'group', 'since', 'until', 'chair', 'role') list_display = ('member', 'group', 'since', 'until', 'chair', 'role')
list_filter = ('group', BoardFilter, LectureYearFilter, list_filter = ('group', TypeFilter, LectureYearFilter,
ActiveMembershipsFilter) ActiveMembershipsFilter)
list_select_related = ('member', 'group',) list_select_related = ('member', 'group',)
search_fields = ('member__first_name', 'member__last_name', search_fields = ('member__first_name', 'member__last_name',
......
...@@ -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(membergroupmembership__until=None) | Q(membergroupmembership__until=None) |
Q(membergroupmembership__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,
......
"""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 MemberGroupMembership from activemembers.models import MemberGroupMembership
from members.models import Member from members.models import Member
...@@ -14,3 +15,18 @@ class MemberGroupMembershipForm(forms.ModelForm): ...@@ -14,3 +15,18 @@ class MemberGroupMembershipForm(forms.ModelForm):
class Meta: class Meta:
model = MemberGroupMembership 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'))
...@@ -17,8 +17,8 @@ from utils.translation import (ModelTranslateMeta, MultilingualField, ...@@ -17,8 +17,8 @@ from utils.translation import (ModelTranslateMeta, MultilingualField,
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class ActiveMemberGroupsManager(models.Manager): class ActiveMemberGroupManager(models.Manager):
"""Returns active committees only""" """Returns active objects only sorted by the localized name"""
def get_queryset(self): def get_queryset(self):
return (super().get_queryset() return (super().get_queryset()
...@@ -27,10 +27,10 @@ class ActiveMemberGroupsManager(models.Manager): ...@@ -27,10 +27,10 @@ class ActiveMemberGroupsManager(models.Manager):
class MemberGroup(models.Model, metaclass=ModelTranslateMeta): class MemberGroup(models.Model, metaclass=ModelTranslateMeta):
"""Describes a committee""" """Describes a groups of members"""
objects = models.Manager() objects = models.Manager()
active_objects = ActiveMemberGroupsManager() active_objects = ActiveMemberGroupManager()
name = MultilingualField( name = MultilingualField(
models.CharField, models.CharField,
...@@ -117,6 +117,11 @@ class MemberGroup(models.Model, metaclass=ModelTranslateMeta): ...@@ -117,6 +117,11 @@ class MemberGroup(models.Model, metaclass=ModelTranslateMeta):
class Committee(MemberGroup): class Committee(MemberGroup):
"""Describes a committee, which is a type of MemberGroup"""
objects = models.Manager()
active_objects = ActiveMemberGroupManager()
wiki_namespace = models.CharField( wiki_namespace = models.CharField(
_('Wiki namespace'), _('Wiki namespace'),
null=True, null=True,
...@@ -130,6 +135,11 @@ class Committee(MemberGroup): ...@@ -130,6 +135,11 @@ class Committee(MemberGroup):
class Society(MemberGroup): class Society(MemberGroup):
"""Describes a society, which is a type of MemberGroup"""
objects = models.Manager()
active_objects = ActiveMemberGroupManager()
class Meta: class Meta:
verbose_name = _('society') verbose_name = _('society')
verbose_name_plural = _('societies') verbose_name_plural = _('societies')
...@@ -137,6 +147,8 @@ class Society(MemberGroup): ...@@ -137,6 +147,8 @@ class Society(MemberGroup):
class Board(MemberGroup): class Board(MemberGroup):
"""Describes a board, which is a type of MemberGroup"""
class Meta: class Meta:
verbose_name = _('board') verbose_name = _('board')
verbose_name_plural = _('boards') verbose_name_plural = _('boards')
...@@ -173,7 +185,7 @@ class Board(MemberGroup): ...@@ -173,7 +185,7 @@ class Board(MemberGroup):
class ActiveMembershipManager(models.Manager): class ActiveMembershipManager(models.Manager):
""" """
Customs manager that gets the currently active committee memberships Custom manager that gets the currently active membergroup memberships
""" """
def get_queryset(self): def get_queryset(self):
...@@ -183,7 +195,7 @@ class ActiveMembershipManager(models.Manager): ...@@ -183,7 +195,7 @@ class ActiveMembershipManager(models.Manager):
class MemberGroupMembership(models.Model, metaclass=ModelTranslateMeta): class MemberGroupMembership(models.Model, metaclass=ModelTranslateMeta):
"""Describes a group membership""" """Describes a group membership"""
objects = models.Manager() objects = models.Manager()
active_memberships = ActiveMembershipManager() active_objects = ActiveMembershipManager()
member = models.ForeignKey( member = models.ForeignKey(
'members.Member', 'members.Member',
......
...@@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404, render, redirect, reverse ...@@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404, render, redirect, reverse
import datetime import datetime
from utils.snippets import datetime_to_lectureyear from utils.snippets import datetime_to_lectureyear
from utils.translation import localize_attr_name from utils.translation import localize_attr_name
from .models import Board, MemberGroup, MemberGroupMembership from .models import Board, MemberGroup, MemberGroupMembership, Committee
def committee_index(request): def committee_index(request):
...@@ -12,7 +12,7 @@ def committee_index(request): ...@@ -12,7 +12,7 @@ def committee_index(request):
:param request: the request object :param request: the request object
:return: response containing the HTML :return: response containing the HTML
""" """
committees = MemberGroup.active_objects.all().order_by( committees = Committee.active_objects.all().order_by(
localize_attr_name('name')) localize_attr_name('name'))
return render(request, 'activemembers/committee_index.html', return render(request, 'activemembers/committee_index.html',
...@@ -27,11 +27,11 @@ def committee_detail(request, pk): ...@@ -27,11 +27,11 @@ def committee_detail(request, pk):
:param pk: pk of the selected committee :param pk: pk of the selected committee
:return: :return:
""" """
committee = get_object_or_404(MemberGroup, pk=pk) committee = get_object_or_404(Committee, pk=pk)
members = [] members = []
memberships = (MemberGroupMembership memberships = (MemberGroupMembership
.active_memberships .active_objects
.filter(group=committee) .filter(group=committee)
.prefetch_related('member__membergroupmembership_set')) .prefetch_related('member__membergroupmembership_set'))
for membership in memberships: for membership in memberships:
......
...@@ -168,7 +168,7 @@ class EventAdmin(DoNextModelAdmin): ...@@ -168,7 +168,7 @@ class EventAdmin(DoNextModelAdmin):
def _change_published(request, queryset, published): def _change_published(request, queryset, published):
if not request.user.is_superuser: if not request.user.is_superuser:
queryset = queryset.filter( queryset = queryset.filter(
organiser__in=request.member.get_committees()) organiser__in=request.member.get_member_groups())
queryset.update(published=published) queryset.update(published=published)
def save_formset(self, request, form, formset, change): def save_formset(self, request, form, formset, change):
...@@ -204,13 +204,13 @@ class EventAdmin(DoNextModelAdmin): ...@@ -204,13 +204,13 @@ class EventAdmin(DoNextModelAdmin):
# Only get the current active committees the user is a member of # Only get the current active committees the user is a member of
if not (request.user.is_superuser or if not (request.user.is_superuser or
request.user.has_perm('events.override_organiser')): request.user.has_perm('events.override_organiser')):
kwargs['queryset'] = request.member.get_committees() kwargs['queryset'] = request.member.get_member_groups()
else: else:
# Hide old boards and inactive committees for new events # Hide old boards and inactive committees for new events
if 'add' in request.path: if 'add' in request.path:
kwargs['queryset'] = ( kwargs['queryset'] = (
MemberGroup.active_objects.all() | MemberGroup.active_objects.all() |
MemberGroup.unfiltered_objects MemberGroup.objects
.filter(board=None) .filter(board=None)
.exclude(until__lt=(timezone.now() - .exclude(until__lt=(timezone.now() -
timezone.timedelta(weeks=1))) timezone.timedelta(weeks=1)))
......
...@@ -71,7 +71,7 @@ def is_organiser(member, event): ...@@ -71,7 +71,7 @@ def is_organiser(member, event):
return True return True
if event and member.has_perm('events.change_event'): if event and member.has_perm('events.change_event'):
return member.get_committees().filter( return member.get_member_groups().filter(
pk=event.organiser.pk).count() != 0 pk=event.organiser.pk).count() != 0
return False return False
......
# Generated by Django 2.0.8 on 2018-09-01 17:19
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('activemembers', '0034_clean_up_models'),
('mailinglists', '0012_auto_20180203_2304'),
]
operations = [
migrations.RemoveField(
model_name='mailinglist',
name='committees',
),
migrations.AddField(
model_name='mailinglist',
name='member_groups',
field=models.ManyToManyField(blank=True, help_text='Select entire groups to include in the list.', to='activemembers.MemberGroup', verbose_name='Member groups'),
),
]
...@@ -47,10 +47,10 @@ class MailingList(models.Model): ...@@ -47,10 +47,10 @@ class MailingList(models.Model):
help_text=_('Select individual members to include in the list.'), help_text=_('Select individual members to include in the list.'),
) )
committees = models.ManyToManyField( member_groups = models.ManyToManyField(
MemberGroup, MemberGroup,
verbose_name=_("Committees"), verbose_name=_("Member groups"),
help_text=_('Select entire committees to include in the list.'), help_text=_('Select entire groups to include in the list.'),
blank=True, blank=True,
) )
...@@ -70,8 +70,8 @@ class MailingList(models.Model): ...@@ -70,8 +70,8 @@ class MailingList(models.Model):
for member in self.members.all(): for member in self.members.all():
yield member.email yield member.email
for committee in self.committees.all().prefetch_related("members"): for group in self.member_groups.all().prefetch_related("members"):
for member in committee.members.exclude( for member in group.members.exclude(
committeemembership__until__lt=timezone.now().date()): committeemembership__until__lt=timezone.now().date()):
yield member.email yield member.email
......
...@@ -7,16 +7,18 @@ from utils.snippets import datetime_to_lectureyear ...@@ -7,16 +7,18 @@ from utils.snippets import datetime_to_lectureyear
def get_automatic_lists(): def get_automatic_lists():
memberships = (MemberGroupMembership.active_memberships current_committee_chairs = (MemberGroupMembership.active_objects
.filter(group__board=None) .filter(group__board=None)
.filter(group__society=None)
.filter(chair=True) .filter(chair=True)
.prefetch_related('member')) .prefetch_related('member'))
committee_chairs = [x.member for x in memberships] + [ committee_chair_emails = [x.member for x in current_committee_chairs] + [
Member(email='intern@thalia.nu') Member(email='intern@thalia.nu')
] ]
active_committee_memberships = (MemberGroupMembership.active_memberships active_committee_memberships = (MemberGroupMembership.active_objects
.filter(group__board=None) .filter(group__board=None)
.filter(group__society=None)
.prefetch_related('member')) .prefetch_related('member'))
active_members = [x.member for x in active_committee_memberships] active_members = [x.member for x in active_committee_memberships]
...@@ -46,7 +48,7 @@ def get_automatic_lists(): ...@@ -46,7 +48,7 @@ def get_automatic_lists():
active_members) active_members)
lists += _create_automatic_list( lists += _create_automatic_list(
['commissievoorzitters', 'committeechairs'], '[THALIA] [CHAIRS]', ['commissievoorzitters', 'committeechairs'], '[THALIA] [CHAIRS]',
committee_chairs, moderated=False) committee_chair_emails, moderated=False)
lists += _create_automatic_list( lists += _create_automatic_list(
['optin'], '[THALIA] [OPTIN]', Member.current_members.filter( ['optin'], '[THALIA] [OPTIN]', Member.current_members.filter(
profile__receive_optin=True), profile__receive_optin=True),
......
...@@ -35,8 +35,9 @@ class ActiveMemberManager(MemberManager): ...@@ -35,8 +35,9 @@ class ActiveMemberManager(MemberManager):
def get_queryset(self): def get_queryset(self):
"""Select all committee members""" """Select all committee members"""
active_memberships = (MemberGroupMembership active_memberships = (MemberGroupMembership
.active_memberships .active_objects
.filter(group__board=None)) .filter(group__board=None)
.filter(group__society=None))
return (super().get_queryset() return (super().get_queryset()
.filter(membergroupmembership__in=active_memberships) .filter(membergroupmembership__in=active_memberships)
...@@ -175,9 +176,9 @@ class Member(User): ...@@ -175,9 +176,9 @@ class Member(User):
self.profile.event_permissions == 'no_drinks') and self.profile.event_permissions == 'no_drinks') and
self.current_membership is not None) self.current_membership is not None)
def get_committees(self): def get_member_groups(self):
"""Get the committees this user is a member of""" """Get the groups this user is a member of"""
return MemberGroup.unfiltered_objects.filter( return MemberGroup.objects.filter(
Q(membergroupmembership__member=self) & Q(membergroupmembership__member=self) &
( (
Q(membergroupmembership__until=None) | Q(membergroupmembership__until=None) |
......
...@@ -177,7 +177,7 @@ PASSWORD_HASHERS = ( ...@@ -177,7 +177,7 @@ PASSWORD_HASHERS = (
AUTHENTICATION_BACKENDS = [ AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
'activemembers.backends.CommitteeBackend', 'activemembers.backends.MemberGroupBackend',
] ]
REST_FRAMEWORK = {