diff --git a/apps/member/admin.py b/apps/member/admin.py index 4cc2d0bf..7936f564 100644 --- a/apps/member/admin.py +++ b/apps/member/admin.py @@ -31,9 +31,7 @@ class CustomUserAdmin(UserAdmin): """ When creating a new user don't show profile one the first step """ - if not obj: - return list() - return super().get_inline_instances(request, obj) + return super().get_inline_instances(request, obj) if obj else [] @admin.register(Club, site=admin_site) diff --git a/apps/member/models.py b/apps/member/models.py index b17f1f09..a1628fae 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -339,43 +339,40 @@ class Membership(models.Model): return self.date_start.toordinal() <= datetime.datetime.now().toordinal() def renew(self): - if Membership.objects.filter( + if not Membership.objects.filter( user=self.user, club=self.club, date_start__gte=self.club.membership_start, ).exists(): - # Membership is already renewed - return - new_membership = Membership( - user=self.user, - club=self.club, - 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: - new_membership._force_renew_parent = True - if hasattr(self, '_soge') and self._soge: - new_membership._soge = True - if hasattr(self, '_force_save') and self._force_save: - new_membership._force_save = True - new_membership.save() - new_membership.roles.set(self.roles.all()) - new_membership.save() + # Membership is not renewed yet + new_membership = Membership( + user=self.user, + club=self.club, + 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: + new_membership._force_renew_parent = True + if hasattr(self, '_soge') and self._soge: + new_membership._soge = True + if hasattr(self, '_force_save') and self._force_save: + new_membership._force_save = True + new_membership.save() + new_membership.roles.set(self.roles.all()) + new_membership.save() def save(self, *args, **kwargs): """ Calculate fee and end date before saving the membership and creating the transaction if needed. """ - - if self.pk: + created = not self.pk + if not created: for role in self.roles.all(): club = role.for_club if club is not None: if club.pk != self.club_id: raise ValidationError(_('The role {role} does not apply to the club {club}.') .format(role=role.name, club=club.name)) - - created = not self.pk - if created: + else: if Membership.objects.filter( user=self.user, club=self.club, @@ -384,7 +381,7 @@ class Membership(models.Model): ).exists(): 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 if not Membership.objects.filter( user=self.user, @@ -433,15 +430,10 @@ class Membership(models.Model): raise ValidationError(_('User is not a member of the parent club') + ' ' + self.club.parent_club.name) - if self.user.profile.paid: - self.fee = self.club.membership_fee_paid - else: - self.fee = self.club.membership_fee_unpaid + self.fee = self.club.membership_fee_paid if self.user.profile.paid else 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) - else: - self.date_end = self.date_start + datetime.timedelta(days=424242) + 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) if self.club.membership_end is not None and self.date_end > self.club.membership_end: self.date_end = self.club.membership_end diff --git a/apps/member/signals.py b/apps/member/signals.py index 70162b37..43659b01 100644 --- a/apps/member/signals.py +++ b/apps/member/signals.py @@ -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 """ - if raw: - # When provisionning data, do not try to autocreate - return - - if created and instance.is_active: + if not raw and created and instance.is_active: from .models import Profile Profile.objects.get_or_create(user=instance) if instance.is_superuser: diff --git a/apps/member/templates/member/manage_auth_tokens.html b/apps/member/templates/member/manage_auth_tokens.html index 473286c1..014686f1 100644 --- a/apps/member/templates/member/manage_auth_tokens.html +++ b/apps/member/templates/member/manage_auth_tokens.html @@ -1,4 +1,4 @@ -{% extends "member/base.html" %} +{% extends "base.html" %} {% comment %} SPDX-License-Identifier: GPL-3.0-or-later {% endcomment %} diff --git a/apps/member/tests/test_login.py b/apps/member/tests/test_login.py index 51a4ab94..c4467f81 100644 --- a/apps/member/tests/test_login.py +++ b/apps/member/tests/test_login.py @@ -1,8 +1,10 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later - +from django.conf import settings from django.contrib.auth.models import User from django.test import TestCase +from django.urls import reverse + from note.models import TransactionTemplate, TemplateCategory """ @@ -31,7 +33,20 @@ class TemplateLoggedInTests(TestCase): sess.save() 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) def test_admin_index(self): @@ -42,21 +57,3 @@ class TemplateLoggedInTests(TestCase): response = self.client.get('/accounts/password_reset/') 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) diff --git a/apps/member/tests/test_memberships.py b/apps/member/tests/test_memberships.py new file mode 100644 index 00000000..8ad7b7cb --- /dev/null +++ b/apps/member/tests/test_memberships.py @@ -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)) diff --git a/apps/member/views.py b/apps/member/views.py index cccffc4a..c2f9f136 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -97,8 +97,7 @@ class UserUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): note = NoteUser.objects.filter( alias__normalized_name=Alias.normalize(new_username)) if note.exists() and note.get().user != self.object: - form.add_error('username', - _("An alias with a similar name already exists.")) + form.add_error('username', _("An alias with a similar name already exists.")) return super().form_invalid(form) # Check if the username is one of user's aliases. 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. """ qs = super().get_queryset() - if self.request.user.is_superuser and self.request.session.get("permission_mask", -1) >= 42: - return qs - return qs.filter(profile__registration_valid=True) + return qs if self.request.user.is_superuser and self.request.session.get("permission_mask", -1) >= 42\ + else qs.filter(profile__registration_valid=True) def get_context_data(self, **kwargs): """ @@ -204,14 +202,16 @@ class UserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): """ 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"))\ - .filter(profile__registration_valid=True).order_by("username") - if "search" in self.request.GET: - pattern = self.request.GET["search"] + .filter(profile__registration_valid=True) - if not pattern: - return qs.none() + # Sqlite doesn't support order by in subqueries + 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( username__iregex="^" + pattern @@ -270,12 +270,7 @@ class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, Det def post(self, request, *args, **kwargs): form = self.get_form() self.object = self.get_object() - if form.is_valid(): - return self.form_valid(form) - else: - print('is_invalid') - print(form) - return self.form_invalid(form) + return self.form_valid(form) if form.is_valid() else self.form_invalid(form) def form_valid(self, form): image_field = form.cleaned_data['image'] @@ -320,8 +315,7 @@ class ManageAuthTokens(LoginRequiredMixin, TemplateView): def get(self, request, *args, **kwargs): if 'regenerate' in request.GET and Token.objects.filter(user=request.user).exists(): Token.objects.get(user=self.request.user).delete() - return redirect(reverse_lazy('member:auth_token') + "?show", - permanent=True) + return redirect(reverse_lazy('member:auth_token') + "?show") return super().get(request, *args, **kwargs) @@ -351,8 +345,9 @@ class ClubCreateView(ProtectQuerysetMixin, ProtectedCreateView): email="", ) - def form_valid(self, form): - return super().form_valid(form) + def get_success_url(self): + self.object.refresh_from_db() + return reverse_lazy("member:club_detail", kwargs={"pk": self.object.pk}) 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 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", user=user, 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: 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) # Now, all is fine, the membership can be created. @@ -719,46 +714,38 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView): transaction._force_save = True 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 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() - elif club.name == "Kfet": - 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() + 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() \ + if club.name == "Kfet"else Role.objects.filter(name="Membre de club").all() form.instance.roles.set(member_role) form.instance._force_save = True form.instance.save() # If Société générale pays, then we assume that this is the BDE membership, and we auto-renew the # Kfet membership. - if soge: - # If not already done, create BDE and Kfet memberships - bde = Club.objects.get(name="BDE") + if soge and club.name == "BDE": kfet = Club.objects.get(name="Kfet") + fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid - soge_clubs = [bde, kfet] - for club in soge_clubs: - fee = club.membership_fee_paid if user.profile.paid else club.membership_fee_unpaid - - # Get current membership, to get the end date - 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 + # Get current membership, to get the end date + old_membership = Membership.objects.filter( + club=kfet, + user=user, + ).order_by("-date_start") + if not old_membership.filter(date_start__gte=kfet.membership_start).exists(): + # If the membership is not already renewed membership = Membership( - club=club, + club=kfet, user=user, 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, ) membership._force_save = True @@ -767,10 +754,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, ProtectedCreateView): membership.refresh_from_db() if old_membership.exists(): membership.roles.set(old_membership.get().roles.all()) - elif c.name == "BDE": - 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.roles.set(Role.objects.filter(Q(name="Adhérent Kfet") | Q(name="Membre de club")).all()) membership.save() 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()) if "roles" in self.request.GET: - if not self.request.GET["roles"]: - return qs.none() - roles_str = self.request.GET["roles"].replace(' ', '').split(',') + roles_str = self.request.GET["roles"].replace(' ', '').split(',') if self.request.GET["roles"] else ['0'] roles_int = map(int, roles_str) qs = qs.filter(roles__in=roles_int) diff --git a/apps/note/api/views.py b/apps/note/api/views.py index 1ab954c9..a478e7ff 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -118,7 +118,7 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet): queryset = super().get_queryset() # 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 alias = self.request.query_params.get("alias", ".*") @@ -140,6 +140,9 @@ class ConsumerViewSet(ReadOnlyProtectedModelViewSet): ), all=True) + queryset = queryset if settings.DATABASES[queryset.db]["ENGINE"] == 'django.db.backends.postgresql' \ + else queryset.order_by("name") + return queryset.distinct()