We planned to upgrade GitLab and Mattermost to the latest version this Friday morning. Expect some downtime!

Commit fa52caf6 authored by Sébastiaan Versteeg's avatar Sébastiaan Versteeg

Move statistics code to services, separate tests into multiple files and add display name tests

parent eec023d7
import operator
from datetime import date, timedelta
import os
from datetime import timedelta
from functools import reduce
from PIL import Image
from django.conf import settings
from django.contrib.auth.models import User, UserManager
from django.core import validators
......@@ -15,10 +17,6 @@ from localflavor.generic.countries.sepa import IBAN_SEPA_COUNTRIES
from localflavor.generic.models import IBANField
from activemembers.models import Committee
from utils.snippets import datetime_to_lectureyear
from PIL import Image
import os
class MemberManager(UserManager):
......@@ -362,7 +360,7 @@ class Profile(models.Model):
pref = self.display_name_preference
if pref == 'nickname' and self.nickname is not None:
return self.nickname
if pref == 'firstname':
elif pref == 'firstname':
return self.user.first_name
elif pref == 'initials':
if self.initials:
......@@ -372,7 +370,7 @@ class Profile(models.Model):
return "{} '{}' {}".format(self.user.first_name,
self.nickname,
self.user.last_name)
elif pref == 'nicklast':
elif pref == 'nicklast' and self.nickname is not None:
return "'{}' {}".format(self.nickname,
self.user.last_name)
else:
......@@ -390,7 +388,6 @@ class Profile(models.Model):
return self.user.last_name
else:
return self.user.first_name
return
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
......@@ -510,56 +507,3 @@ class Membership(models.Model):
def is_active(self):
return not self.until or self.until > timezone.now().date()
def gen_stats_member_type(member_types):
total = dict()
for member_type in member_types:
total[member_type] = (Membership
.objects
.filter(since__lte=date.today())
.filter(Q(until__isnull=True) |
Q(until__gt=date.today()))
.filter(type=member_type)
.count())
return total
def gen_stats_year(member_types):
"""
Generate list with 6 entries, where each entry represents the total amount
of Thalia members in a year. The sixth element contains all the multi-year
students.
"""
stats_year = []
current_year = datetime_to_lectureyear(date.today())
for i in range(5):
new = dict()
for member_type in member_types:
new[member_type] = (
Membership
.objects
.filter(user__profile__starting_year=current_year - i)
.filter(since__lte=date.today())
.filter(Q(until__isnull=True) |
Q(until__gt=date.today()))
.filter(type=member_type)
.count())
stats_year.append(new)
# Add multi year members
new = dict()
for member_type in member_types:
new[member_type] = (
Membership
.objects
.filter(user__profile__starting_year__lt=current_year - 4)
.filter(since__lte=date.today())
.filter(Q(until__isnull=True) |
Q(until__gt=date.today()))
.filter(type=member_type)
.count())
stats_year.append(new)
return stats_year
from datetime import date
from django.db.models import Q
from members.models import Membership
from utils.snippets import datetime_to_lectureyear
def member_achievements(member):
memberships = member.committeemembership_set.all()
......@@ -42,3 +47,54 @@ def member_achievements(member):
'earliest': earliest,
}
return sorted(achievements.values(), key=lambda x: x['earliest'])
def gen_stats_member_type(member_types):
total = dict()
for member_type in member_types:
total[member_type] = (Membership
.objects
.filter(since__lte=date.today())
.filter(Q(until__isnull=True) |
Q(until__gt=date.today()))
.filter(type=member_type)
.count())
return total
def gen_stats_year(member_types):
"""
Generate list with 6 entries, where each entry represents the total amount
of Thalia members in a year. The sixth element contains all the multi-year
students.
"""
stats_year = []
current_year = datetime_to_lectureyear(date.today())
for i in range(5):
new = dict()
for member_type in member_types:
new[member_type] = (
Membership.objects
.filter(user__profile__starting_year=current_year - i)
.filter(since__lte=date.today())
.filter(Q(until__isnull=True) |
Q(until__gt=date.today()))
.filter(type=member_type)
.count())
stats_year.append(new)
# Add multi year members
new = dict()
for member_type in member_types:
new[member_type] = (
Membership.objects
.filter(user__profile__starting_year__lt=current_year - 4)
.filter(since__lte=date.today())
.filter(Q(until__isnull=True) |
Q(until__gt=date.today()))
.filter(type=member_type)
.count())
stats_year.append(new)
return stats_year
from datetime import date, datetime, timedelta
from django.test import TestCase
from django.utils import timezone
from members.models import (Profile, Member, Membership)
from members.views import filter_users
class MemberBirthdayTest(TestCase):
fixtures = ['members.json']
def _make_date(self, date):
return timezone.make_aware(datetime.strptime(date, '%Y-%m-%d'))
def _get_members(self, start, end):
start_date = self._make_date(start)
end_date = self._make_date(end)
return Member.active_members.with_birthdays_in_range(
start_date, end_date
)
def _assert_none(self, start, end):
members = self._get_members(start, end)
self.assertEqual(len(members), 0)
def _assert_thom(self, start, end):
members = self._get_members(start, end)
self.assertEqual(len(members), 1)
self.assertEqual(members[0].get_full_name(), 'Thom Wiggers')
def test_one_year_contains_birthday(self):
self._assert_thom('2016-03-02', '2016-08-08')
def test_one_year_not_contains_birthday(self):
self._assert_none('2016-01-01', '2016-02-01')
def test_span_year_contains_birthday(self):
self._assert_thom('2015-08-09', '2016-08-08')
def test_span_year_not_contains_birthday(self):
self._assert_none('2015-12-25', '2016-03-01')
def test_span_multiple_years_contains_birthday(self):
self._assert_thom('2012-12-31', '2016-01-01')
def test_range_before_person_born(self):
self._assert_none('1985-12-12', '1985-12-13')
def test_person_born_in_range_in_one_year(self):
self._assert_thom('1993-01-01', '1993-04-01')
def test_person_born_in_range_spanning_one_year(self):
self._assert_thom('1992-12-31', '1993-04-01')
def test_person_born_in_range_spanning_multiple_years(self):
self._assert_thom('1992-12-31', '1995-01-01')
class MemberTest(TestCase):
fixtures = ['members.json']
def test_has_been_member(self):
member = Member.objects.get(pk=1)
self.assertTrue(member.has_been_member())
m1 = member.membership_set.all()[0]
m1.type = 'honorary'
m1.save()
self.assertFalse(member.has_been_member())
def test_has_been_honorary_member(self):
member = Member.objects.get(pk=1)
self.assertFalse(member.has_been_honorary_member())
m1 = member.membership_set.all()[0]
m1.type = 'honorary'
m1.save()
self.assertTrue(member.has_been_honorary_member())
class MemberDisplayNameTest(TestCase):
@classmethod
def setUpTestData(cls):
cls.member = Member.objects.create(
username='johnnytest',
first_name='',
last_name=''
)
cls.profile = Profile.objects.create(
user_id=cls.member.pk,
initials=None,
nickname=None,
display_name_preference='full',
)
def setUp(self):
self.profile.display_name_preference = 'full'
# Assuming we always have a first and last name
self.profile.user.first_name = 'Johnny'
self.profile.user.last_name = 'Test'
self.profile.nickname = None
self.profile.initials = None
def test_check_display_name_full(self):
self.assertEqual('Johnny Test', self.profile.display_name())
self.assertEqual('Johnny', self.profile.short_display_name())
def test_check_display_name_nickname(self):
self.profile.display_name_preference = 'nickname'
self.assertEqual('Johnny Test', self.profile.display_name())
self.assertEqual('Johnny', self.profile.short_display_name())
self.profile.nickname = 'John'
self.assertEqual('John', self.profile.display_name())
self.assertEqual('John', self.profile.short_display_name())
def test_check_display_name_firstname(self):
self.profile.display_name_preference = 'firstname'
self.assertEqual('Johnny', self.profile.display_name())
self.assertEqual('Johnny', self.profile.short_display_name())
def test_check_display_name_initials(self):
self.profile.display_name_preference = 'initials'
self.assertEqual('Test', self.profile.display_name())
self.assertEqual('Test', self.profile.short_display_name())
self.profile.initials = 'J'
self.assertEqual('J Test', self.profile.display_name())
self.assertEqual('J Test', self.profile.short_display_name())
def test_check_display_name_fullnick(self):
self.profile.display_name_preference = 'fullnick'
self.assertEqual('Johnny Test', self.profile.display_name())
self.assertEqual('Johnny', self.profile.short_display_name())
self.profile.nickname = 'John'
self.assertEqual('Johnny \'John\' Test', self.profile.display_name())
self.assertEqual('Johnny', self.profile.short_display_name())
def test_check_display_name_nicklast(self):
self.profile.display_name_preference = 'nicklast'
self.assertEqual('Johnny Test', self.profile.display_name())
self.assertEqual('Johnny', self.profile.short_display_name())
self.profile.nickname = 'John'
self.assertEqual('\'John\' Test', self.profile.display_name())
self.assertEqual('John', self.profile.short_display_name())
class MembershipFilterTest(TestCase):
@classmethod
def setUpTestData(cls):
# Add 10 members with default membership
members = [Member(id=i, username=i) for i in range(7)]
Member.objects.bulk_create(members)
profiles = [Profile(user_id=i) for i in range(7)]
Profile.objects.bulk_create(profiles)
Membership(user_id=0, type='honorary',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=1, type='supporter',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=2, type='member',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=3, type='member',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=3, type='member',
until=date.today() - timedelta(days=365*10)).save()
Membership(user_id=4, type='supporter',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=4, type='member',
until=date.today() - timedelta(days=365*10)).save()
Membership(user_id=5, type='member',
until=date.today() - timedelta(days=365*10)).save()
# user_id=6 has no memberships at all
def test_honorary(self):
members = filter_users('honor', '', [date.today().year])
self.assertEqual(len(members), 1)
self.assertEqual(members[0].id, 0)
def test_ex(self):
members = filter_users('ex', '', [date.today().year])
self.assertEqual(len(members), 3)
for member in members:
self.assertIn(member.id, {4, 5, 6})
# TODO more tests for other cases
from datetime import date, datetime, timedelta
from datetime import timedelta, date
from django.test import TestCase
from django.utils import timezone
from members.models import (Profile, Member, Membership,
gen_stats_member_type, gen_stats_year)
from members.views import filter_users
from members.models import Member, Membership, Profile
from members.services import gen_stats_year, gen_stats_member_type
from utils.snippets import datetime_to_lectureyear
class MemberBirthdayTest(TestCase):
fixtures = ['members.json']
def _make_date(self, date):
return timezone.make_aware(datetime.strptime(date, '%Y-%m-%d'))
def _get_members(self, start, end):
start_date = self._make_date(start)
end_date = self._make_date(end)
return Member.active_members.with_birthdays_in_range(
start_date, end_date
)
def _assert_none(self, start, end):
members = self._get_members(start, end)
self.assertEqual(len(members), 0)
def _assert_thom(self, start, end):
members = self._get_members(start, end)
self.assertEqual(len(members), 1)
self.assertEqual(members[0].get_full_name(), 'Thom Wiggers')
def test_one_year_contains_birthday(self):
self._assert_thom('2016-03-02', '2016-08-08')
def test_one_year_not_contains_birthday(self):
self._assert_none('2016-01-01', '2016-02-01')
def test_span_year_contains_birthday(self):
self._assert_thom('2015-08-09', '2016-08-08')
def test_span_year_not_contains_birthday(self):
self._assert_none('2015-12-25', '2016-03-01')
def test_span_multiple_years_contains_birthday(self):
self._assert_thom('2012-12-31', '2016-01-01')
def test_range_before_person_born(self):
self._assert_none('1985-12-12', '1985-12-13')
def test_person_born_in_range_in_one_year(self):
self._assert_thom('1993-01-01', '1993-04-01')
def test_person_born_in_range_spanning_one_year(self):
self._assert_thom('1992-12-31', '1993-04-01')
def test_person_born_in_range_spanning_multiple_years(self):
self._assert_thom('1992-12-31', '1995-01-01')
class MemberTest(TestCase):
fixtures = ['members.json']
def test_has_been_member(self):
member = Member.objects.get(pk=1)
self.assertTrue(member.has_been_member())
m1 = member.membership_set.all()[0]
m1.type = 'honorary'
m1.save()
self.assertFalse(member.has_been_member())
def test_has_been_honorary_member(self):
member = Member.objects.get(pk=1)
self.assertFalse(member.has_been_honorary_member())
m1 = member.membership_set.all()[0]
m1.type = 'honorary'
m1.save()
self.assertTrue(member.has_been_honorary_member())
class MembershipFilterTest(TestCase):
@classmethod
def setUpTestData(cls):
# Add 10 members with default membership
members = [Member(id=i, username=i) for i in range(7)]
Member.objects.bulk_create(members)
profiles = [Profile(user_id=i) for i in range(7)]
Profile.objects.bulk_create(profiles)
Membership(user_id=0, type='honorary',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=1, type='supporter',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=2, type='member',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=3, type='member',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=3, type='member',
until=date.today() - timedelta(days=365*10)).save()
Membership(user_id=4, type='supporter',
until=date.today() + timedelta(days=1)).save()
Membership(user_id=4, type='member',
until=date.today() - timedelta(days=365*10)).save()
Membership(user_id=5, type='member',
until=date.today() - timedelta(days=365*10)).save()
# user_id=6 has no memberships at all
def test_honorary(self):
members = filter_users('honor', '', [date.today().year])
self.assertEqual(len(members), 1)
self.assertEqual(members[0].id, 0)
def test_ex(self):
members = filter_users('ex', '', [date.today().year])
self.assertEqual(len(members), 3)
for member in members:
self.assertIn(member.id, {4, 5, 6})
# TODO more tests for other cases
class StatisticsTest(TestCase):
@classmethod
......
......@@ -12,6 +12,7 @@ from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.response import Response
from members import services
from .services import member_achievements
from . import models
from .forms import ProfileForm
......@@ -213,9 +214,9 @@ def statistics(request):
context = {
"total_members": total,
"total_stats_year": json.dumps(models.gen_stats_year(member_types)),
"total_stats_year": json.dumps(services.gen_stats_year(member_types)),
"total_stats_member_type": json.dumps(
models.gen_stats_member_type(member_types)),
services.gen_stats_member_type(member_types)),
}
return render(request, 'members/statistics.html', context)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment