1
0
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:
Yohann D'ANELLO 2020-09-02 22:54:01 +02:00
parent 1b8cb7abb0
commit bf7f5b9cd6
8 changed files with 490 additions and 115 deletions

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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 %}

View File

@ -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)

View 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))

View File

@ -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)

View File

@ -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()