From c76ff92c30af212bbad863aff0a95f1ec19eedfa Mon Sep 17 00:00:00 2001 From: imperosol Date: Sat, 13 Sep 2025 18:37:53 +0200 Subject: [PATCH] Better management of roles in ClubMemberForm --- club/forms.py | 52 ++++++++++++++++++-------- club/templates/club/club_members.jinja | 10 +++-- club/tests/test_membership.py | 2 +- club/views.py | 9 ++++- locale/fr/LC_MESSAGES/django.po | 18 ++++++--- 5 files changed, 64 insertions(+), 27 deletions(-) diff --git a/club/forms.py b/club/forms.py index a257dc50..0c0f6294 100644 --- a/club/forms.py +++ b/club/forms.py @@ -26,6 +26,7 @@ from django import forms from django.conf import settings from django.db.models import Exists, OuterRef, Q from django.db.models.functions import Lower +from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from club.models import Club, Mailing, MailingSubscription, Membership @@ -217,20 +218,36 @@ class ClubMemberForm(forms.ModelForm): fields = ["user", "role", "description"] widgets = {"user": AutoCompleteSelectUser} - def __init__( - self, - *args, - club: Club, - request_user: User, - **kwargs, - ): + def __init__(self, *args, club: Club, request_user: User, **kwargs): self.club = club self.request_user = request_user self.request_user_membership = self.club.get_membership_for(self.request_user) super().__init__(*args, **kwargs) self.fields["role"].required = True + self.fields["role"].choices = [ + (value, name) + for value, name in settings.SITH_CLUB_ROLES.items() + if value <= self.max_available_role + ] self.instance.club = club + @cached_property + def max_available_role(self): + """The greatest role that will be obtainable with this form. + + Admins and the club president can attribute any role. + Board members can attribute roles lower than their own. + Other users can attribute curious and member roles. + """ + if self.request_user.has_perm("club.add_subscription"): + return settings.SITH_CLUB_ROLES_ID["President"] + membership = self.request_user_membership + if membership is not None and membership.role > settings.SITH_MAXIMUM_FREE_ROLE: + if membership.role == settings.SITH_CLUB_ROLES_ID["President"]: + return membership.role + return membership.role - 1 + return settings.SITH_MAXIMUM_FREE_ROLE + def clean_user(self): """Check that the user is not trying to add a user already in the club. @@ -248,16 +265,21 @@ class ClubMemberForm(forms.ModelForm): return user def clean(self): - """Check user rights for adding an user.""" + """Check user rights for adding a user.""" cleaned_data = super().clean() if "role" not in cleaned_data: return cleaned_data - request_user = self.request_user - membership = self.request_user_membership - if not ( - cleaned_data["role"] <= settings.SITH_MAXIMUM_FREE_ROLE - or (membership is not None and membership.role >= cleaned_data["role"]) - or request_user.has_perm("club.add_subscription") - ): + if ( + self.request_user_membership is None + or self.request_user_membership.role <= settings.SITH_MAXIMUM_FREE_ROLE + ) and not self.request_user.has_perm("club.add_membership"): + raise forms.ValidationError( + _( + "You cannot add other users to a club " + "if you are not in the club board." + ), + code="invalid", + ) + if cleaned_data["role"] > self.max_available_role: raise forms.ValidationError(_("You do not have the permission to do that")) return cleaned_data diff --git a/club/templates/club/club_members.jinja b/club/templates/club/club_members.jinja index 5bd6a535..99772c60 100644 --- a/club/templates/club/club_members.jinja +++ b/club/templates/club/club_members.jinja @@ -12,11 +12,13 @@ {% block content %}

{% trans %}Club members{% endtrans %}

-
-

{% trans %}Add a new member{% endtrans %}

- {{ add_member_fragment }} -
+ {% if add_member_fragment %} +
+

{% trans %}Add a new member{% endtrans %}

+ {{ add_member_fragment }} +
+ {% endif %} {% if members %}
{% csrf_token %} diff --git a/club/tests/test_membership.py b/club/tests/test_membership.py index 8a3e5737..1e8b7dfd 100644 --- a/club/tests/test_membership.py +++ b/club/tests/test_membership.py @@ -353,7 +353,7 @@ class TestMembership(TestClub): assert not form.is_valid() assert form.errors == { - "__all__": ["Vous n'avez pas la permission de faire cela"] + "role": ["Sélectionnez un choix valide. 10 n\u2019en fait pas partie."] } self.club.refresh_from_db() assert nb_memberships == self.club.members.count() diff --git a/club/views.py b/club/views.py index 5540a0b1..6cf84dd5 100644 --- a/club/views.py +++ b/club/views.py @@ -69,7 +69,7 @@ from com.views import ( from core.auth.mixins import CanCreateMixin, CanEditMixin from core.models import PageRev from core.views import DetailFormView, PageEditViewBase, UseFragmentsMixin -from core.views.mixins import FragmentMixin, TabedViewMixin +from core.views.mixins import FragmentMixin, FragmentRenderer, TabedViewMixin from counter.models import Selling @@ -301,9 +301,14 @@ class ClubMembersView( form_class = ClubOldMemberForm template_name = "club/club_members.jinja" current_tab = "members" - fragments = {"add_member_fragment": ClubAddMembersFragment} permission_required = "club.view_club" + def get_fragments(self) -> dict[str, type[FragmentMixin] | FragmentRenderer]: + membership = self.object.get_membership_for(self.request.user) + if membership and membership.role <= settings.SITH_MAXIMUM_FREE_ROLE: + return {} + return {"add_member_fragment": ClubAddMembersFragment} + def get_fragment_data(self) -> dict[str, Any]: return {"add_member_fragment": {"club": self.object}} diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index c3139104..1a08e3d2 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-09-13 15:18+0200\n" +"POT-Creation-Date: 2025-09-13 18:32+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Maréchal \n" @@ -173,6 +173,13 @@ msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" msgid "You can not add the same user twice" msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur" +#: club/forms.py +msgid "" +"You cannot add other users to a club if you are not in the club board." +msgstr "" +"Vous ne pouvez pas ajouter d'autres utilisateurs dans un club si vous " +"ne faites pas partie de son bureau." + #: club/forms.py sas/forms.py msgid "You do not have the permission to do that" msgstr "Vous n'avez pas la permission de faire cela" @@ -326,10 +333,6 @@ msgstr "Membres du club" msgid "Add a new member" msgstr "Ajouter un nouveau membre" -#: club/templates/club/club_members.jinja -msgid "Current club members" -msgstr "Membres actuels du club" - #: club/templates/club/club_members.jinja #: club/templates/club/club_old_members.jinja #: core/templates/core/user_clubs.jinja @@ -684,6 +687,11 @@ msgstr "Listes de diffusion" msgid "Posters list" msgstr "Liste d'affiches" +#: club/views.py +#, python-format +msgid "%(user)s has been added to club." +msgstr "%(user)s a été ajouté au club." + #: com/forms.py msgid "Format: 16:9 | Resolution: 1920x1080" msgstr "Format : 16:9 | Résolution : 1920x1080"