From 66cf2bd957c576016137167a28b80ba6ff680f79 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 | 21 ++++++++--- locale/fr/LC_MESSAGES/django.po | 15 ++++++-- 5 files changed, 70 insertions(+), 30 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 999973d6..c32014eb 100644 --- a/club/views.py +++ b/club/views.py @@ -72,7 +72,7 @@ from core.auth.mixins import ( ) 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 @@ -307,17 +307,26 @@ 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 + and not self.request.user.has_perm("club.add_membership") + ): + return {} + return {"add_member_fragment": ClubAddMembersFragment} + def get_fragment_data(self) -> dict[str, Any]: return {"add_member_fragment": {"club": self.object}} def get_form_kwargs(self): - kwargs = super().get_form_kwargs() - kwargs["user"] = self.request.user - kwargs["club"] = self.object - return kwargs + return super().get_form_kwargs() | { + "user": self.request.user, + "club": self.object, + } def get_context_data(self, **kwargs): kwargs = super().get_context_data(**kwargs) diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 878e683a..36ab0f12 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -173,6 +173,12 @@ 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 +332,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 @@ -680,6 +682,11 @@ msgstr "Vente" msgid "Mailing list" msgstr "Listes de diffusion" +#: 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"