mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-11-26 18:37:12 +00:00
Test and cover fully member app
This commit is contained in:
parent
1b8cb7abb0
commit
bf7f5b9cd6
@ -31,9 +31,7 @@ class CustomUserAdmin(UserAdmin):
|
|||||||
"""
|
"""
|
||||||
When creating a new user don't show profile one the first step
|
When creating a new user don't show profile one the first step
|
||||||
"""
|
"""
|
||||||
if not obj:
|
return super().get_inline_instances(request, obj) if obj else []
|
||||||
return list()
|
|
||||||
return super().get_inline_instances(request, obj)
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Club, site=admin_site)
|
@admin.register(Club, site=admin_site)
|
||||||
|
@ -339,43 +339,40 @@ class Membership(models.Model):
|
|||||||
return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
|
return self.date_start.toordinal() <= datetime.datetime.now().toordinal()
|
||||||
|
|
||||||
def renew(self):
|
def renew(self):
|
||||||
if Membership.objects.filter(
|
if not Membership.objects.filter(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
club=self.club,
|
club=self.club,
|
||||||
date_start__gte=self.club.membership_start,
|
date_start__gte=self.club.membership_start,
|
||||||
).exists():
|
).exists():
|
||||||
# Membership is already renewed
|
# Membership is not renewed yet
|
||||||
return
|
new_membership = Membership(
|
||||||
new_membership = Membership(
|
user=self.user,
|
||||||
user=self.user,
|
club=self.club,
|
||||||
club=self.club,
|
date_start=max(self.date_end + datetime.timedelta(days=1), self.club.membership_start),
|
||||||
date_start=max(self.date_end + datetime.timedelta(days=1), self.club.membership_start),
|
)
|
||||||
)
|
if hasattr(self, '_force_renew_parent') and self._force_renew_parent:
|
||||||
if hasattr(self, '_force_renew_parent') and self._force_renew_parent:
|
new_membership._force_renew_parent = True
|
||||||
new_membership._force_renew_parent = True
|
if hasattr(self, '_soge') and self._soge:
|
||||||
if hasattr(self, '_soge') and self._soge:
|
new_membership._soge = True
|
||||||
new_membership._soge = True
|
if hasattr(self, '_force_save') and self._force_save:
|
||||||
if hasattr(self, '_force_save') and self._force_save:
|
new_membership._force_save = True
|
||||||
new_membership._force_save = True
|
new_membership.save()
|
||||||
new_membership.save()
|
new_membership.roles.set(self.roles.all())
|
||||||
new_membership.roles.set(self.roles.all())
|
new_membership.save()
|
||||||
new_membership.save()
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Calculate fee and end date before saving the membership and creating the transaction if needed.
|
Calculate fee and end date before saving the membership and creating the transaction if needed.
|
||||||
"""
|
"""
|
||||||
|
created = not self.pk
|
||||||
if self.pk:
|
if not created:
|
||||||
for role in self.roles.all():
|
for role in self.roles.all():
|
||||||
club = role.for_club
|
club = role.for_club
|
||||||
if club is not None:
|
if club is not None:
|
||||||
if club.pk != self.club_id:
|
if club.pk != self.club_id:
|
||||||
raise ValidationError(_('The role {role} does not apply to the club {club}.')
|
raise ValidationError(_('The role {role} does not apply to the club {club}.')
|
||||||
.format(role=role.name, club=club.name))
|
.format(role=role.name, club=club.name))
|
||||||
|
else:
|
||||||
created = not self.pk
|
|
||||||
if created:
|
|
||||||
if Membership.objects.filter(
|
if Membership.objects.filter(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
club=self.club,
|
club=self.club,
|
||||||
@ -384,7 +381,7 @@ class Membership(models.Model):
|
|||||||
).exists():
|
).exists():
|
||||||
raise ValidationError(_('User is already a member of the club'))
|
raise ValidationError(_('User is already a member of the club'))
|
||||||
|
|
||||||
if self.club.parent_club is not None and not self.pk:
|
if self.club.parent_club is not None:
|
||||||
# Check that the user is already a member of the parent club if the membership is created
|
# Check that the user is already a member of the parent club if the membership is created
|
||||||
if not Membership.objects.filter(
|
if not Membership.objects.filter(
|
||||||
user=self.user,
|
user=self.user,
|
||||||
@ -433,15 +430,10 @@ class Membership(models.Model):
|
|||||||
raise ValidationError(_('User is not a member of the parent club')
|
raise ValidationError(_('User is not a member of the parent club')
|
||||||
+ ' ' + self.club.parent_club.name)
|
+ ' ' + self.club.parent_club.name)
|
||||||
|
|
||||||
if self.user.profile.paid:
|
self.fee = self.club.membership_fee_paid if self.user.profile.paid else self.club.membership_fee_unpaid
|
||||||
self.fee = self.club.membership_fee_paid
|
|
||||||
else:
|
|
||||||
self.fee = self.club.membership_fee_unpaid
|
|
||||||
|
|
||||||
if self.club.membership_duration is not None:
|
self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration) \
|
||||||
self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration)
|
if self.club.membership_duration is not None else self.date_start + datetime.timedelta(days=424242)
|
||||||
else:
|
|
||||||
self.date_end = self.date_start + datetime.timedelta(days=424242)
|
|
||||||
if self.club.membership_end is not None and self.date_end > self.club.membership_end:
|
if self.club.membership_end is not None and self.date_end > self.club.membership_end:
|
||||||
self.date_end = self.club.membership_end
|
self.date_end = self.club.membership_end
|
||||||
|
|
||||||
|
@ -6,11 +6,7 @@ def save_user_profile(instance, created, raw, **_kwargs):
|
|||||||
"""
|
"""
|
||||||
Hook to create and save a profile when an user is updated if it is not registered with the signup form
|
Hook to create and save a profile when an user is updated if it is not registered with the signup form
|
||||||
"""
|
"""
|
||||||
if raw:
|
if not raw and created and instance.is_active:
|
||||||
# When provisionning data, do not try to autocreate
|
|
||||||
return
|
|
||||||
|
|
||||||
if created and instance.is_active:
|
|
||||||
from .models import Profile
|
from .models import Profile
|
||||||
Profile.objects.get_or_create(user=instance)
|
Profile.objects.get_or_create(user=instance)
|
||||||
if instance.is_superuser:
|
if instance.is_superuser:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends "member/base.html" %}
|
{% extends "base.html" %}
|
||||||
{% comment %}
|
{% comment %}
|
||||||
SPDX-License-Identifier: GPL-3.0-or-later
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from note.models import TransactionTemplate, TemplateCategory
|
from note.models import TransactionTemplate, TemplateCategory
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@ -31,7 +33,20 @@ class TemplateLoggedInTests(TestCase):
|
|||||||
sess.save()
|
sess.save()
|
||||||
|
|
||||||
def test_login_page(self):
|
def test_login_page(self):
|
||||||
response = self.client.get('/accounts/login/')
|
response = self.client.get(reverse("login"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
response = self.client.post('/accounts/login/', data=dict(
|
||||||
|
username="admin",
|
||||||
|
password="adminadmin",
|
||||||
|
permission_mask=3,
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL, 302, 200)
|
||||||
|
|
||||||
|
def test_logout(self):
|
||||||
|
response = self.client.get(reverse("logout"))
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_admin_index(self):
|
def test_admin_index(self):
|
||||||
@ -42,21 +57,3 @@ class TemplateLoggedInTests(TestCase):
|
|||||||
response = self.client.get('/accounts/password_reset/')
|
response = self.client.get('/accounts/password_reset/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
def test_logout_page(self):
|
|
||||||
response = self.client.get('/accounts/logout/')
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
def test_transfer_page(self):
|
|
||||||
response = self.client.get('/note/transfer/')
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
def test_consos_page(self):
|
|
||||||
# Create one button and ensure that it is visible
|
|
||||||
cat = TemplateCategory.objects.create()
|
|
||||||
TransactionTemplate.objects.create(
|
|
||||||
destination_id=5,
|
|
||||||
category=cat,
|
|
||||||
amount=0,
|
|
||||||
)
|
|
||||||
response = self.client.get('/note/consos/')
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
407
apps/member/tests/test_memberships.py
Normal file
407
apps/member/tests/test_memberships.py
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from member.models import Club, Membership, Profile
|
||||||
|
from note.models import Alias, NoteSpecial
|
||||||
|
from permission.models import Role
|
||||||
|
from treasury.models import SogeCredit
|
||||||
|
|
||||||
|
"""
|
||||||
|
Create some users and clubs and test that all pages are rendering properly
|
||||||
|
and that memberships are working.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class TestMemberships(TestCase):
|
||||||
|
fixtures = ('initial', )
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
"""
|
||||||
|
Create a sample superuser, a club and a membership for all tests.
|
||||||
|
"""
|
||||||
|
self.user = User.objects.create_superuser(
|
||||||
|
username="toto",
|
||||||
|
email="toto@example.com",
|
||||||
|
password="toto",
|
||||||
|
)
|
||||||
|
self.user.profile.registration_valid = True
|
||||||
|
self.user.profile.email_confirmed = True
|
||||||
|
self.user.profile.save()
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
sess = self.client.session
|
||||||
|
sess["permission_mask"] = 42
|
||||||
|
sess.save()
|
||||||
|
|
||||||
|
self.club = Club.objects.create(name="totoclub", parent_club=Club.objects.get(name="BDE"))
|
||||||
|
self.bde_membership = Membership.objects.create(user=self.user, club=Club.objects.get(name="BDE"))
|
||||||
|
self.membership = Membership.objects.create(user=self.user, club=self.club)
|
||||||
|
self.membership.roles.add(Role.objects.get(name="Bureau de club"))
|
||||||
|
self.membership.save()
|
||||||
|
|
||||||
|
def test_admin_pages(self):
|
||||||
|
"""
|
||||||
|
Check that Django Admin pages for the member app are loading successfully.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("admin:index") + "member/membership/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("admin:index") + "member/club/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("admin:index") + "auth/user/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("admin:index") + "auth/user/" + str(self.user.pk) + "/change/")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_club_list(self):
|
||||||
|
"""
|
||||||
|
Render the list of all clubs, with a search.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_list"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("member:club_list") + "?search=toto")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_club_create(self):
|
||||||
|
"""
|
||||||
|
Try to create a new club.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_create"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.client.post(reverse("member:club_create"), data=dict(
|
||||||
|
name="Club toto",
|
||||||
|
email="clubtoto@example.com",
|
||||||
|
parent_club=self.club.pk,
|
||||||
|
require_memberships=False,
|
||||||
|
membership_fee_paid=0,
|
||||||
|
membership_fee_unpaid=0,
|
||||||
|
))
|
||||||
|
self.assertTrue(Club.objects.filter(name="Club toto").exists())
|
||||||
|
club = Club.objects.get(name="Club toto")
|
||||||
|
self.assertRedirects(response, club.get_absolute_url(), 302, 200)
|
||||||
|
|
||||||
|
def test_render_club_detail(self):
|
||||||
|
"""
|
||||||
|
Display the detail of a club.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_detail", args=(self.club.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_club_update(self):
|
||||||
|
"""
|
||||||
|
Try to update the information about a club.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_update", args=(self.club.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.client.post(reverse("member:club_update", args=(self.club.pk, )), data=dict(
|
||||||
|
name="Toto club updated",
|
||||||
|
email="clubtoto@example.com",
|
||||||
|
require_memberships=True,
|
||||||
|
membership_fee_paid=0,
|
||||||
|
membership_fee_unpaid=0,
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, self.club.get_absolute_url(), 302, 200)
|
||||||
|
self.assertTrue(Club.objects.exclude(name="Toto club updated"))
|
||||||
|
|
||||||
|
def test_render_club_update_picture(self):
|
||||||
|
"""
|
||||||
|
Try to update the picture of the note of a club.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_update_pic", args=(self.club.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
old_pic = self.club.note.display_image
|
||||||
|
|
||||||
|
with open("media/pic/default.png", "rb") as f:
|
||||||
|
image = SimpleUploadedFile("image.png", f.read(), "image/png")
|
||||||
|
response = self.client.post(reverse("member:club_update_pic", args=(self.club.pk,)), dict(
|
||||||
|
image=image,
|
||||||
|
x=0,
|
||||||
|
y=0,
|
||||||
|
width=200,
|
||||||
|
height=200,
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, self.club.get_absolute_url(), 302, 200)
|
||||||
|
|
||||||
|
self.club.note.refresh_from_db()
|
||||||
|
self.assertTrue(os.path.exists(self.club.note.display_image.path))
|
||||||
|
os.remove(self.club.note.display_image.path)
|
||||||
|
|
||||||
|
self.club.note.display_image = old_pic
|
||||||
|
self.club.note.save()
|
||||||
|
|
||||||
|
def test_render_club_aliases(self):
|
||||||
|
"""
|
||||||
|
Display the list of the aliases of a club.
|
||||||
|
"""
|
||||||
|
# Alias creation and deletion is already tested in the note app
|
||||||
|
response = self.client.get(reverse("member:club_alias", args=(self.club.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_club_members(self):
|
||||||
|
"""
|
||||||
|
Display the list of the members of a club.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_members", args=(self.club.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.client.get(reverse("member:club_members", args=(self.club.pk,)) + "?search=toto&roles="
|
||||||
|
+ ",".join([str(role.pk) for role in
|
||||||
|
Role.objects.filter(weirole__isnull=True).all()]))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_club_add_member(self):
|
||||||
|
"""
|
||||||
|
Try to add memberships and renew them.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_add_member", args=(Club.objects.get(name="BDE").pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
user = User.objects.create(username="totototo")
|
||||||
|
user.profile.registration_valid = True
|
||||||
|
user.profile.email_confirmed = True
|
||||||
|
user.profile.save()
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
# We create a club without any parent and one club with parent BDE (that is the club Kfet)
|
||||||
|
for bde_parent in False, True:
|
||||||
|
if bde_parent:
|
||||||
|
club = Club.objects.get(name="Kfet")
|
||||||
|
else:
|
||||||
|
club = Club.objects.create(
|
||||||
|
name="Second club " + ("with BDE" if bde_parent else "without BDE"),
|
||||||
|
parent_club=None,
|
||||||
|
email="newclub@example.com",
|
||||||
|
require_memberships=True,
|
||||||
|
membership_fee_paid=1000,
|
||||||
|
membership_fee_unpaid=500,
|
||||||
|
membership_start=date.today(),
|
||||||
|
membership_end=date.today() + timedelta(days=366),
|
||||||
|
membership_duration=366,
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.get(reverse("member:club_add_member", args=(club.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Create a new membership
|
||||||
|
response = self.client.post(reverse("member:club_add_member", args=(club.pk,)), data=dict(
|
||||||
|
user=user.pk,
|
||||||
|
date_start="{:%Y-%m-%d}".format(timezone.now().date()),
|
||||||
|
soge=False,
|
||||||
|
credit_type=NoteSpecial.objects.get(special_type="Espèces").id,
|
||||||
|
credit_amount=4200,
|
||||||
|
last_name="TOTO",
|
||||||
|
first_name="Toto",
|
||||||
|
bank="Le matelas",
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, club.get_absolute_url(), 302, 200)
|
||||||
|
|
||||||
|
self.assertTrue(Membership.objects.filter(user=user, club=club).exists())
|
||||||
|
|
||||||
|
# Membership is sent to the past to check renewals
|
||||||
|
membership = Membership.objects.get(user=user, club=club)
|
||||||
|
self.assertTrue(membership.valid)
|
||||||
|
membership.date_start = date(year=2000, month=1, day=1)
|
||||||
|
membership.date_end = date(year=2000, month=12, day=31)
|
||||||
|
membership.save()
|
||||||
|
self.assertFalse(membership.valid)
|
||||||
|
|
||||||
|
response = self.client.get(reverse("member:club_members", args=(club.pk,)) + "?only_active=0")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
bde_membership = self.bde_membership
|
||||||
|
if bde_parent:
|
||||||
|
bde_membership = Membership.objects.get(club__name="BDE", user=user)
|
||||||
|
bde_membership.date_start = date(year=2000, month=1, day=1)
|
||||||
|
bde_membership.date_end = date(year=2000, month=12, day=31)
|
||||||
|
bde_membership.save()
|
||||||
|
|
||||||
|
response = self.client.get(reverse("member:club_renew_membership", args=(bde_membership.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.client.get(reverse("member:club_renew_membership", args=(membership.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Renew membership
|
||||||
|
response = self.client.post(reverse("member:club_renew_membership", args=(membership.pk,)), data=dict(
|
||||||
|
user=user.pk,
|
||||||
|
date_start="{:%Y-%m-%d}".format(timezone.now().date()),
|
||||||
|
soge=bde_parent,
|
||||||
|
credit_type=NoteSpecial.objects.get(special_type="Chèque").id,
|
||||||
|
credit_amount=14242,
|
||||||
|
last_name="TOTO",
|
||||||
|
first_name="Toto",
|
||||||
|
bank="Bank",
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, club.get_absolute_url(), 302, 200)
|
||||||
|
|
||||||
|
response = self.client.get(user.profile.get_absolute_url())
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_auto_join_kfet_when_join_bde_with_soge(self):
|
||||||
|
"""
|
||||||
|
When we join the BDE club with a Soge registration, a Kfet membership is automatically created.
|
||||||
|
We check that it is the case.
|
||||||
|
"""
|
||||||
|
user = User.objects.create(username="new1A")
|
||||||
|
user.profile.registration_valid = True
|
||||||
|
user.profile.email_confirmed = True
|
||||||
|
user.profile.save()
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
bde = Club.objects.get(name="BDE")
|
||||||
|
kfet = Club.objects.get(name="Kfet")
|
||||||
|
|
||||||
|
response = self.client.post(reverse("member:club_add_member", args=(bde.pk,)), data=dict(
|
||||||
|
user=user.pk,
|
||||||
|
date_start="{:%Y-%m-%d}".format(timezone.now().date()),
|
||||||
|
soge=True,
|
||||||
|
credit_type=NoteSpecial.objects.get(special_type="Virement bancaire").id,
|
||||||
|
credit_amount=(bde.membership_fee_paid + kfet.membership_fee_paid) / 100,
|
||||||
|
last_name="TOTO",
|
||||||
|
first_name="Toto",
|
||||||
|
bank="Société générale",
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, bde.get_absolute_url(), 302, 200)
|
||||||
|
|
||||||
|
self.assertTrue(Membership.objects.filter(user=user, club=bde).exists())
|
||||||
|
self.assertTrue(Membership.objects.filter(user=user, club=kfet).exists())
|
||||||
|
self.assertTrue(SogeCredit.objects.filter(user=user).exists())
|
||||||
|
|
||||||
|
def test_change_roles(self):
|
||||||
|
"""
|
||||||
|
Check to change the roles of a membership.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:club_manage_roles", args=(self.membership.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.client.post(reverse("member:club_manage_roles", args=(self.membership.pk,)), data=dict(
|
||||||
|
roles=[role.id for role in Role.objects.filter(
|
||||||
|
Q(name="Membre de club") | Q(name="Trésorier·ère de club") | Q(name="Bureau de club")).all()],
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200)
|
||||||
|
self.membership.refresh_from_db()
|
||||||
|
self.assertEqual(self.membership.roles.count(), 3)
|
||||||
|
|
||||||
|
def test_render_user_list(self):
|
||||||
|
"""
|
||||||
|
Display the user search page.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:user_list"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("member:user_list") + "?search=toto")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_user_detail(self):
|
||||||
|
"""
|
||||||
|
Display the user detail page.
|
||||||
|
"""
|
||||||
|
response = self.client.get(self.user.profile.get_absolute_url())
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_render_user_update(self):
|
||||||
|
"""
|
||||||
|
Update some data about the user.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:user_update_profile", args=(self.user.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
response = self.client.post(reverse("member:user_update_profile", args=(self.user.pk,)), data=dict(
|
||||||
|
first_name="Toto",
|
||||||
|
last_name="Toto",
|
||||||
|
username="toto changed",
|
||||||
|
email="updated@example.com",
|
||||||
|
phone_number="+33600000000",
|
||||||
|
section="",
|
||||||
|
department="A0",
|
||||||
|
promotion=timezone.now().year,
|
||||||
|
address="Earth",
|
||||||
|
paid=True,
|
||||||
|
ml_events_registration="en",
|
||||||
|
ml_sports_registration=True,
|
||||||
|
ml_art_registration=True,
|
||||||
|
report_frequency=7,
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200)
|
||||||
|
self.assertTrue(User.objects.filter(username="toto changed").exists())
|
||||||
|
self.assertTrue(Profile.objects.filter(address="Earth").exists())
|
||||||
|
self.assertTrue(Alias.objects.filter(normalized_name="totochanged").exists())
|
||||||
|
|
||||||
|
def test_render_user_update_picture(self):
|
||||||
|
"""
|
||||||
|
Update the note picture of the user.
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:user_update_pic", args=(self.user.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
old_pic = self.user.note.display_image
|
||||||
|
|
||||||
|
with open("media/pic/default.png", "rb") as f:
|
||||||
|
image = SimpleUploadedFile("image.png", f.read(), "image/png")
|
||||||
|
response = self.client.post(reverse("member:user_update_pic", args=(self.user.pk,)), dict(
|
||||||
|
image=image,
|
||||||
|
x=0,
|
||||||
|
y=0,
|
||||||
|
width=200,
|
||||||
|
height=200,
|
||||||
|
))
|
||||||
|
self.assertRedirects(response, self.user.profile.get_absolute_url(), 302, 200)
|
||||||
|
|
||||||
|
self.user.note.refresh_from_db()
|
||||||
|
self.assertTrue(os.path.exists(self.user.note.display_image.path))
|
||||||
|
os.remove(self.user.note.display_image.path)
|
||||||
|
|
||||||
|
self.user.note.display_image = old_pic
|
||||||
|
self.user.note.save()
|
||||||
|
|
||||||
|
def test_render_user_aliases(self):
|
||||||
|
"""
|
||||||
|
Display the list of aliases of the user.
|
||||||
|
"""
|
||||||
|
# Alias creation and deletion is already tested in the note app
|
||||||
|
response = self.client.get(reverse("member:user_alias", args=(self.user.pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_manage_auth_token(self):
|
||||||
|
"""
|
||||||
|
Display the page to see the API authentication token, see it and regenerate it.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
response = self.client.get(reverse("member:auth_token"))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("member:auth_token") + "?view")
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
response = self.client.get(reverse("member:auth_token") + "?regenerate")
|
||||||
|
self.assertRedirects(response, reverse("member:auth_token") + "?view", 302, 200)
|
||||||
|
|
||||||
|
def test_random_coverage(self):
|
||||||
|
# Useless, only for coverage
|
||||||
|
self.assertEqual(str(self.user), str(self.user.profile))
|
||||||
|
self.user.profile.promotion = None
|
||||||
|
self.assertEqual(self.user.profile.ens_year, 0)
|
||||||
|
self.membership.date_end = None
|
||||||
|
self.assertTrue(self.membership.valid)
|
||||||
|
|
||||||
|
def test_nk15_hasher(self):
|
||||||
|
"""
|
||||||
|
Test that NK15 passwords are successfully imported.
|
||||||
|
"""
|
||||||
|
salt = "42"
|
||||||
|
password = "strongpassword42"
|
||||||
|
hashed = hashlib.sha256((salt + password).encode("utf-8")).hexdigest()
|
||||||
|
self.user.password = "custom_nk15$1$" + salt + "|" + hashed
|
||||||
|
self.user.save()
|
||||||
|
self.assertTrue(self.user.check_password(password))
|
@ -97,8 +97,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
|||||||
note = NoteUser.objects.filter(
|
note = NoteUser.objects.filter(
|
||||||
alias__normalized_name=Alias.normalize(new_username))
|
alias__normalized_name=Alias.normalize(new_username))
|
||||||
if note.exists() and note.get().user != self.object:
|
if note.exists() and note.get().user != self.object:
|
||||||
form.add_error('username',
|
form.add_error('username', _("An alias with a similar name already exists."))
|
||||||
_("An alias with a similar name already exists."))
|
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
# Check if the username is one of user's aliases.
|
# Check if the username is one of user's aliases.
|
||||||
alias = Alias.objects.filter(name=new_username)
|
alias = Alias.objects.filter(name=new_username)
|
||||||
@ -142,9 +141,8 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
|||||||
We can't display information of a not registered user.
|
We can't display information of a not registered user.
|
||||||
"""
|
"""
|
||||||
qs = super().get_queryset()
|
qs = super().get_queryset()
|
||||||
if self.request.user.is_superuser and self.request.session.get("permission_mask", -1) >= 42:
|
return qs if self.request.user.is_superuser and self.request.session.get("permission_mask", -1) >= 42\
|
||||||
return qs
|
else qs.filter(profile__registration_valid=True)
|
||||||
return qs.filter(profile__registration_valid=True)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -204,14 +202,16 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
|||||||
"""
|
"""
|
||||||
Filter the user list with the given pattern.
|
Filter the user list with the given pattern.
|
||||||
"""
|
"""
|
||||||
qs = super().get_queryset().distinct("username").annotate(alias=F("note__alias__name"))\
|
qs = super().get_queryset().annotate(alias=F("note__alias__name"))\
|
||||||
.annotate(normalized_alias=F("note__alias__normalized_name"))\
|
.annotate(normalized_alias=F("note__alias__normalized_name"))\
|
||||||
.filter(profile__registration_valid=True).order_by("username")
|
.filter(profile__registration_valid=True)
|
||||||
if "search" in self.request.GET:
|
|
||||||
pattern = self.request.GET["search"]
|
|
||||||
|
|
||||||
if not pattern:
|
# Sqlite doesn't support order by in subqueries
|
||||||
return qs.none()
|
qs = qs.order_by("username").distinct("username")\
|
||||||
|
if settings.DATABASES[qs.db]["ENGINE"] == 'django.db.backends.postgresql' else qs.distinct()
|
||||||
|
|
||||||
|
if "search" in self.request.GET and self.request.GET["search"]:
|
||||||
|
pattern = self.request.GET["search"]
|
||||||
|
|
||||||
qs = qs.filter(
|
qs = qs.filter(
|
||||||
username__iregex="^" + pattern
|
username__iregex="^" + pattern
|
||||||
@ -270,12 +270,7 @@ class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, Det
|
|||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
self.object = self.get_object()
|
self.object = self.get_object()
|
||||||
if form.is_valid():
|
return self.form_valid(form) if form.is_valid() else self.form_invalid(form)
|
||||||
return self.form_valid(form)
|
|
||||||
else:
|
|
||||||
print('is_invalid')
|
|
||||||
print(form)
|
|
||||||
return self.form_invalid(form)
|
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
image_field = form.cleaned_data['image']
|
image_field = form.cleaned_data['image']
|
||||||
@ -320,8 +315,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView):
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
if 'regenerate' in request.GET and Token.objects.filter(user=request.user).exists():
|
if 'regenerate' in request.GET and Token.objects.filter(user=request.user).exists():
|
||||||
Token.objects.get(user=self.request.user).delete()
|
Token.objects.get(user=self.request.user).delete()
|
||||||
return redirect(reverse_lazy('member:auth_token') + "?show",
|
return redirect(reverse_lazy('member:auth_token') + "?show")
|
||||||
permanent=True)
|
|
||||||
|
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
@ -351,8 +345,9 @@ class ClubCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
email="",
|
email="",
|
||||||
)
|
)
|
||||||
|
|
||||||
def form_valid(self, form):
|
def get_success_url(self):
|
||||||
return super().form_valid(form)
|
self.object.refresh_from_db()
|
||||||
|
return reverse_lazy("member:club_detail", kwargs={"pk": self.object.pk})
|
||||||
|
|
||||||
|
|
||||||
class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
class ClubListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||||
@ -655,7 +650,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
fee += c.membership_fee_paid if user.profile.paid else c.membership_fee_unpaid
|
fee += c.membership_fee_paid if user.profile.paid else c.membership_fee_unpaid
|
||||||
c = c.parent_club
|
c = c.parent_club
|
||||||
|
|
||||||
if user.note.balance + credit_amount < fee and not Membership.objects.filter(
|
if not soge and user.note.balance + credit_amount < fee and not Membership.objects.filter(
|
||||||
club__name="Kfet",
|
club__name="Kfet",
|
||||||
user=user,
|
user=user,
|
||||||
date_start__lte=date.today(),
|
date_start__lte=date.today(),
|
||||||
@ -683,7 +678,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
|
|
||||||
if club.membership_end and form.instance.date_start > club.membership_end:
|
if club.membership_end and form.instance.date_start > club.membership_end:
|
||||||
form.add_error('user', _("The membership must begin before {:%m-%d-%Y}.")
|
form.add_error('user', _("The membership must begin before {:%m-%d-%Y}.")
|
||||||
.format(form.instance.club.membership_start))
|
.format(form.instance.club.membership_end))
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
# Now, all is fine, the membership can be created.
|
# Now, all is fine, the membership can be created.
|
||||||
@ -719,46 +714,38 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
transaction._force_save = True
|
transaction._force_save = True
|
||||||
transaction.save()
|
transaction.save()
|
||||||
|
|
||||||
|
# Parent club memberships are automatically renewed / created.
|
||||||
|
# For example, a Kfet membership creates a BDE membership if it does not exist.
|
||||||
form.instance._force_renew_parent = True
|
form.instance._force_renew_parent = True
|
||||||
|
|
||||||
ret = super().form_valid(form)
|
ret = super().form_valid(form)
|
||||||
|
|
||||||
if club.name == "BDE":
|
member_role = Role.objects.filter(Q(name="Adhérent BDE") | Q(name="Membre de club")).all() \
|
||||||
member_role = Role.objects.filter(Q(name="Adhérent BDE") | Q(name="Membre de club")).all()
|
if club.name == "BDE" else Role.objects.filter(Q(name="Adhérent Kfet") | Q(name="Membre de club")).all() \
|
||||||
elif club.name == "Kfet":
|
if club.name == "Kfet"else Role.objects.filter(name="Membre de club").all()
|
||||||
member_role = Role.objects.filter(Q(name="Adhérent Kfet") | Q(name="Membre de club")).all()
|
|
||||||
else:
|
|
||||||
member_role = Role.objects.filter(name="Membre de club").all()
|
|
||||||
form.instance.roles.set(member_role)
|
form.instance.roles.set(member_role)
|
||||||
form.instance._force_save = True
|
form.instance._force_save = True
|
||||||
form.instance.save()
|
form.instance.save()
|
||||||
|
|
||||||
# If Société générale pays, then we assume that this is the BDE membership, and we auto-renew the
|
# If Société générale pays, then we assume that this is the BDE membership, and we auto-renew the
|
||||||
# Kfet membership.
|
# Kfet membership.
|
||||||
if soge:
|
if soge and club.name == "BDE":
|
||||||
# If not already done, create BDE and Kfet memberships
|
|
||||||
bde = Club.objects.get(name="BDE")
|
|
||||||
kfet = Club.objects.get(name="Kfet")
|
kfet = Club.objects.get(name="Kfet")
|
||||||
|
fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid
|
||||||
|
|
||||||
soge_clubs = [bde, kfet]
|
# Get current membership, to get the end date
|
||||||
for club in soge_clubs:
|
old_membership = Membership.objects.filter(
|
||||||
fee = club.membership_fee_paid if user.profile.paid else club.membership_fee_unpaid
|
club=kfet,
|
||||||
|
user=user,
|
||||||
# Get current membership, to get the end date
|
).order_by("-date_start")
|
||||||
old_membership = Membership.objects.filter(
|
|
||||||
club=club,
|
|
||||||
user=user,
|
|
||||||
).order_by("-date_start")
|
|
||||||
|
|
||||||
if old_membership.filter(date_start__gte=club.membership_start).exists():
|
|
||||||
# Membership is already renewed
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
if not old_membership.filter(date_start__gte=kfet.membership_start).exists():
|
||||||
|
# If the membership is not already renewed
|
||||||
membership = Membership(
|
membership = Membership(
|
||||||
club=club,
|
club=kfet,
|
||||||
user=user,
|
user=user,
|
||||||
fee=fee,
|
fee=fee,
|
||||||
date_start=max(old_membership.first().date_end + timedelta(days=1), club.membership_start)
|
date_start=max(old_membership.first().date_end + timedelta(days=1), kfet.membership_start)
|
||||||
if old_membership.exists() else form.instance.date_start,
|
if old_membership.exists() else form.instance.date_start,
|
||||||
)
|
)
|
||||||
membership._force_save = True
|
membership._force_save = True
|
||||||
@ -767,10 +754,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
membership.refresh_from_db()
|
membership.refresh_from_db()
|
||||||
if old_membership.exists():
|
if old_membership.exists():
|
||||||
membership.roles.set(old_membership.get().roles.all())
|
membership.roles.set(old_membership.get().roles.all())
|
||||||
elif c.name == "BDE":
|
membership.roles.set(Role.objects.filter(Q(name="Adhérent Kfet") | Q(name="Membre de club")).all())
|
||||||
membership.roles.set(Role.objects.filter(Q(name="Adhérent BDE") | Q(name="Membre de club")).all())
|
|
||||||
elif c.name == "Kfet":
|
|
||||||
membership.roles.set(Role.objects.filter(Q(name="Adhérent Kfet") | Q(name="Membre de club")).all())
|
|
||||||
membership.save()
|
membership.save()
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
@ -830,9 +814,7 @@ class ClubMembersListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableV
|
|||||||
qs = qs.filter(date_start__lte=timezone.now().today(), date_end__gte=timezone.now().today())
|
qs = qs.filter(date_start__lte=timezone.now().today(), date_end__gte=timezone.now().today())
|
||||||
|
|
||||||
if "roles" in self.request.GET:
|
if "roles" in self.request.GET:
|
||||||
if not self.request.GET["roles"]:
|
roles_str = self.request.GET["roles"].replace(' ', '').split(',') if self.request.GET["roles"] else ['0']
|
||||||
return qs.none()
|
|
||||||
roles_str = self.request.GET["roles"].replace(' ', '').split(',')
|
|
||||||
roles_int = map(int, roles_str)
|
roles_int = map(int, roles_str)
|
||||||
qs = qs.filter(roles__in=roles_int)
|
qs = qs.filter(roles__in=roles_int)
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
|
|||||||
|
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
# Sqlite doesn't support ORDER BY in subqueries
|
# Sqlite doesn't support ORDER BY in subqueries
|
||||||
queryset = queryset.order_by("username") \
|
queryset = queryset.order_by("name") \
|
||||||
if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' else queryset
|
if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' else queryset
|
||||||
|
|
||||||
alias = self.request.query_params.get("alias", ".*")
|
alias = self.request.query_params.get("alias", ".*")
|
||||||
@ -140,6 +140,9 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet):
|
|||||||
),
|
),
|
||||||
all=True)
|
all=True)
|
||||||
|
|
||||||
|
queryset = queryset if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' \
|
||||||
|
else queryset.order_by("name")
|
||||||
|
|
||||||
return queryset.distinct()
|
return queryset.distinct()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user