Source code for members.models.member

import logging
import operator
from datetime import timedelta
from functools import reduce

from django.conf import settings
from django.contrib.auth.models import User, UserManager
from django.db.models import Q
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from activemembers.models import MemberGroup, MemberGroupMembership
from payments.models import BankAccount

logger = logging.getLogger(__name__)


[docs]class MemberManager(UserManager): """Get all members, i.e. all users with a profile."""
[docs] def get_queryset(self): return super().get_queryset().exclude(profile=None)
[docs]class ActiveMemberManager(MemberManager): """Get all active members, i.e. who have a committee membership"""
[docs] def get_queryset(self): """Select all committee members""" active_memberships = MemberGroupMembership.active_objects.filter( group__board=None ).filter(group__society=None) return ( super() .get_queryset() .filter(membergroupmembership__in=active_memberships) .distinct() )
[docs]class CurrentMemberManager(MemberManager): """Get all members with an active membership"""
[docs] def get_queryset(self): """ Select all members who have a current membership """ return ( super() .get_queryset() .exclude(membership=None) .filter( Q(membership__until__isnull=True) | Q(membership__until__gt=timezone.now().date()) ) .distinct() )
[docs] def with_birthdays_in_range(self, from_date, to_date): """ Select all who are currently a Thalia member and have a birthday within the specified range :param from_date: the start of the range (inclusive) :param to_date: the end of the range (inclusive) :paramtype from_date: datetime :paramtype to_date: datetime :return: the filtered queryset :rtype: Queryset """ queryset = self.get_queryset().filter(profile__birthday__lte=to_date) if (to_date - from_date).days >= 366: # 366 is important to also account for leap years # Everyone that's born before to_date has a birthday return queryset delta = to_date - from_date dates = [from_date + timedelta(days=i) for i in range(delta.days + 1)] monthdays = [ {"profile__birthday__month": d.month, "profile__birthday__day": d.day} for d in dates ] # Don't get me started (basically, we are making a giant OR query with # all days and months that are in the range) query = reduce(operator.or_, [Q(**d) for d in monthdays]) return queryset.filter(query)
[docs]class Member(User): class Meta: proxy = True ordering = ("first_name", "last_name") objects = MemberManager() current_members = CurrentMemberManager() active_members = ActiveMemberManager() def __str__(self): return "{} ({})".format(self.get_full_name(), self.username) @property def current_membership(self): """ The currently active membership of the user. None if not active. :return: the currently active membership or None :rtype: Membership or None """ membership = self.latest_membership if membership and not membership.is_active(): return None return membership @property def latest_membership(self): """Get the most recent membership of this user""" if not self.membership_set.exists(): return None return self.membership_set.latest("since") @property def earliest_membership(self): """Get the earliest membership of this user""" if not self.membership_set.exists(): return None return self.membership_set.earliest("since")
[docs] def has_been_member(self): """Has this user ever been a member?""" return self.membership_set.filter(type="member").count() > 0
[docs] def has_been_honorary_member(self): """Has this user ever been an honorary member?""" return self.membership_set.filter(type="honorary").count() > 0
[docs] def has_active_membership(self): """Is this member currently active Tested by checking if the expiration date has passed. """ return self.current_membership is not None
# Special properties for admin site has_active_membership.boolean = True has_active_membership.short_description = _("Is this user currently active")
[docs] @classmethod def all_with_membership(cls, membership_type): """ Get all users who have a specific membership. :param membership_type: The membership to select by :return: List of users :rtype: [Member] """ return [ x for x in cls.objects.all() if x.current_membership and x.current_membership.type == membership_type ]
@property def can_attend_events(self): """May this user attend events""" if not self.profile: return False return ( self.profile.event_permissions == "all" or self.profile.event_permissions == "no_drinks" ) and self.current_membership is not None
[docs] def get_member_groups(self): """Get the groups this user is a member of""" return MemberGroup.objects.filter( Q(membergroupmembership__member=self) & ( Q(membergroupmembership__until=None) | Q(membergroupmembership__until__gt=timezone.now()) ) ).exclude(active=False)
[docs] def get_absolute_url(self): return reverse("members:profile", args=[str(self.pk)])
@property def tpay_enabled(self): """Does this user have a bank account with Direct Debit enabled""" bank_accounts = BankAccount.objects.filter(owner=self) return ( settings.THALIA_PAY_ENABLED_PAYMENT_METHOD and bank_accounts.exists() and bank_accounts.last().valid )