From d5ad2c5141cd5b460ca14e4edf824f69b9b82f4d Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 24 Apr 2019 03:10:42 +0200 Subject: [PATCH] clubs: Handle bulk add of users in clubs and refresh of the form handling --- club/templates/club/club_members.jinja | 5 +- club/views.py | 132 +++++++++++++++---------- locale/fr/LC_MESSAGES/django.po | 69 +++++++------ 3 files changed, 121 insertions(+), 85 deletions(-) diff --git a/club/templates/club/club_members.jinja b/club/templates/club/club_members.jinja index 5f68a9df..d3db8542 100644 --- a/club/templates/club/club_members.jinja +++ b/club/templates/club/club_members.jinja @@ -11,7 +11,7 @@ {% trans %}Since{% endtrans %} - {% for m in club.members.filter(end_date=None).order_by('-role').all() %} + {% for m in members %} {{ user_profile_link(m.user) }} {{ settings.SITH_CLUB_ROLES[m.role] }} @@ -30,6 +30,3 @@

{% endblock %} - - - diff --git a/club/views.py b/club/views.py index 1b460b2c..5b7e1349 100644 --- a/club/views.py +++ b/club/views.py @@ -33,7 +33,7 @@ from django.core.urlresolvers import reverse, reverse_lazy from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext as _t -from ajax_select.fields import AutoCompleteSelectField +from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404, redirect @@ -44,6 +44,7 @@ from core.views import ( CanEditPropMixin, TabedViewMixin, PageEditViewBase, + DetailFormView, ) from core.views.forms import SelectDate, SelectDateTime from club.models import Club, Membership, Mailing, MailingSubscription @@ -305,7 +306,7 @@ class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView): current_tab = "tools" -class ClubMemberForm(forms.ModelForm): +class ClubMemberForm(forms.Form): """ Form handling the members of a club """ @@ -313,24 +314,68 @@ class ClubMemberForm(forms.ModelForm): error_css_class = "error" required_css_class = "required" - class Meta: - model = Membership - fields = ["user", "role", "start_date", "description"] - widgets = {"start_date": SelectDate} - - user = AutoCompleteSelectField( - "users", required=True, label=_("Select user"), help_text=None + users = AutoCompleteSelectMultipleField( + "users", + label=_("Users to add"), + help_text=_("Search users to add (one or more)."), + required=True, ) - def save(self, *args, **kwargs): + def __init__(self, *args, **kwargs): + self.club = kwargs.pop("club") + self.request_user = kwargs.pop("request_user") + super(ClubMemberForm, self).__init__(*args, **kwargs) + + # Using a ModelForm forces a save and we don't want that + # We want the view to process the model creation since they are multiple users + self.fields.update( + forms.fields_for_model( + Membership, + fields=("role", "start_date", "description"), + widgets={"start_date": SelectDate}, + ) + ) + if not self.request_user.is_root: + self.fields.pop("start_date") + + def clean_users(self): """ - Overloaded to return the club, and not to a Membership object that has no view + Check that the user is not trying to add an user already in the club """ - super(ClubMemberForm, self).save(*args, **kwargs) - return self.instance.club + cleaned_data = super(ClubMemberForm, self).clean() + users = [] + for user_id in cleaned_data["users"]: + user = User.objects.filter(id=user_id).first() + if not user: + raise forms.ValidationError( + _("One of the selected users doesn't exist", code="invalid") + ) + users.append(user) + if self.club.get_membership_for(user): + raise forms.ValidationError( + _("You can not add the same user twice"), code="invalid" + ) + return users + + def clean(self): + """ + Check user rights + """ + cleaned_data = super(ClubMemberForm, self).clean() + request_user = self.request_user + membership = self.club.get_membership_for(request_user) + print(request_user.is_root) + if not ( + cleaned_data["role"] <= SITH_MAXIMUM_FREE_ROLE + or (membership is not None and membership.role >= cleaned_data["role"]) + or request_user.is_board_member + or request_user.is_root + ): + raise forms.ValidationError(_("You do not have the permission to do that")) + return cleaned_data -class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView): +class ClubMembersView(ClubTabsMixin, CanViewMixin, DetailFormView): """ View of a club's members """ @@ -341,52 +386,39 @@ class ClubMembersView(ClubTabsMixin, CanViewMixin, UpdateView): template_name = "club/club_members.jinja" current_tab = "members" - def get_form(self): - """ - Here we get a Membership object, but the view handles Club object. - That's why the save method of ClubMemberForm is overridden. - """ - form = super(ClubMembersView, self).get_form() - if ( - "user" in form.data and form.data.get("user") != "" - ): # Load an existing membership if possible - form.instance = ( - Membership.objects.filter(club=self.object) - .filter(user=form.data.get("user")) - .filter(end_date=None) - .first() - ) - if form.instance is None: # Instanciate a new membership - form.instance = Membership(club=self.object, user=self.request.user) - if not self.request.user.is_root: - form.fields.pop("start_date", None) - return form + def get_form_kwargs(self): + kwargs = super(ClubMembersView, self).get_form_kwargs() + kwargs["request_user"] = self.request_user + kwargs["club"] = self.get_object() + return kwargs + + def get_context_data(self, *args, **kwargs): + kwargs = super(ClubMembersView, self).get_context_data(*args, **kwargs) + kwargs["members"] = ( + self.get_object().members.filter(end_date=None).order_by("-role").all() + ) + return kwargs def form_valid(self, form): """ Check user rights """ - user = self.request.user - ms = self.object.get_membership_for(user) - if ( - form.cleaned_data["role"] <= SITH_MAXIMUM_FREE_ROLE - or (ms is not None and ms.role >= form.cleaned_data["role"]) - or user.is_board_member - or user.is_root - ): - form.save() - form = self.form_class() - return super(ModelFormMixin, self).form_valid(form) - else: - form.add_error(None, _("You do not have the permission to do that")) - return self.form_invalid(form) + resp = super(ClubMembersView, self).form_valid(form) + + data = form.clean() + users = data.pop("users", []) + for user in users: + Membership(club=self.get_object(), user=user, **data).save() + return resp def dispatch(self, request, *args, **kwargs): - self.request = request + self.request_user = request.user return super(ClubMembersView, self).dispatch(request, *args, **kwargs) def get_success_url(self, **kwargs): - return reverse_lazy("club:club_members", kwargs={"club_id": self.club.id}) + return reverse_lazy( + "club:club_members", kwargs={"club_id": self.get_object().id} + ) class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView): diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index a62e1c94..3c29867c 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: 2019-04-22 14:57+0200\n" +"POT-Creation-Date: 2019-04-24 03:06+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Skia \n" "Language-Team: AE info \n" @@ -177,7 +177,7 @@ msgstr "type de cible" #: accounting/models.py:313 club/models.py:422 #: club/templates/club/club_members.jinja:8 #: club/templates/club/club_old_members.jinja:8 -#: club/templates/club/mailing.jinja:28 club/views.py:111 +#: club/templates/club/mailing.jinja:28 club/views.py:112 #: counter/templates/counter/cash_summary_list.jinja:32 #: counter/templates/counter/stats.jinja:15 #: counter/templates/counter/stats.jinja:52 @@ -386,7 +386,7 @@ msgid "Delete" msgstr "Supprimer" #: accounting/templates/accounting/bank_account_details.jinja:18 -#: club/views.py:128 core/views/user.py:205 sas/templates/sas/picture.jinja:86 +#: club/views.py:129 core/views/user.py:205 sas/templates/sas/picture.jinja:86 msgid "Infos" msgstr "Infos" @@ -405,7 +405,7 @@ msgstr "Nouveau compte club" #: accounting/templates/accounting/bank_account_details.jinja:27 #: accounting/templates/accounting/bank_account_list.jinja:22 #: accounting/templates/accounting/club_account_details.jinja:58 -#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:174 +#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:175 #: com/templates/com/news_admin_list.jinja:39 #: com/templates/com/news_admin_list.jinja:68 #: com/templates/com/news_admin_list.jinja:115 @@ -1070,8 +1070,8 @@ msgstr "Du" msgid "To" msgstr "Au" -#: club/templates/club/club_sellings.jinja:5 club/views.py:194 -#: club/views.py:478 counter/templates/counter/counter_main.jinja:19 +#: club/templates/club/club_sellings.jinja:5 club/views.py:195 +#: club/views.py:507 counter/templates/counter/counter_main.jinja:19 #: counter/templates/counter/last_ops.jinja:35 msgid "Sellings" msgstr "Ventes" @@ -1097,7 +1097,7 @@ msgstr "unités" msgid "Benefit: " msgstr "Bénéfice : " -#: club/templates/club/club_sellings.jinja:21 club/views.py:417 +#: club/templates/club/club_sellings.jinja:21 club/views.py:446 #: core/templates/core/user_account_detail.jinja:18 #: core/templates/core/user_account_detail.jinja:51 #: counter/templates/counter/cash_summary_list.jinja:33 counter/views.py:168 @@ -1246,60 +1246,71 @@ msgstr "Aucune page n'existe pour ce club" msgid "Club stats" msgstr "Statistiques du club" -#: club/views.py:138 +#: club/views.py:139 msgid "Members" msgstr "Membres" -#: club/views.py:147 +#: club/views.py:148 msgid "Old members" msgstr "Anciens membres" -#: club/views.py:157 core/templates/core/page.jinja:33 +#: club/views.py:158 core/templates/core/page.jinja:33 msgid "History" msgstr "Historique" -#: club/views.py:165 core/templates/core/base.jinja:121 core/views/user.py:228 +#: club/views.py:166 core/templates/core/base.jinja:121 core/views/user.py:228 #: sas/templates/sas/picture.jinja:95 trombi/views.py:60 msgid "Tools" msgstr "Outils" -#: club/views.py:185 +#: club/views.py:186 msgid "Edit club page" msgstr "Éditer la page de club" -#: club/views.py:201 +#: club/views.py:202 msgid "Mailing list" msgstr "Listes de diffusion" -#: club/views.py:210 com/views.py:141 +#: club/views.py:211 com/views.py:141 msgid "Posters list" msgstr "Liste d'affiches" -#: club/views.py:220 counter/templates/counter/counter_list.jinja:21 +#: club/views.py:221 counter/templates/counter/counter_list.jinja:21 #: counter/templates/counter/counter_list.jinja:43 #: counter/templates/counter/counter_list.jinja:59 msgid "Props" msgstr "Propriétés" -#: club/views.py:322 core/views/forms.py:358 counter/views.py:113 -#: trombi/views.py:141 -msgid "Select user" -msgstr "Choisir un utilisateur" +#: club/views.py:319 +msgid "Users to add" +msgstr "Utilisateurs à ajouter" -#: club/views.py:381 sas/views.py:129 sas/views.py:195 sas/views.py:286 +#: club/views.py:320 core/views/group.py:63 +msgid "Search users to add (one or more)." +msgstr "Recherche les utilisateurs à ajouter (un ou plus)." + +#: club/views.py:348 +msgid "One of the selected users doesn't exist" +msgstr "Un des utilisateurs sélectionné n'existe pas" + +#: club/views.py:353 core/views/group.py:82 +msgid "You can not add the same user twice" +msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur" + +#: club/views.py:371 sas/views.py:129 sas/views.py:195 sas/views.py:286 msgid "You do not have the permission to do that" msgstr "Vous n'avez pas la permission de faire cela" -#: club/views.py:406 counter/views.py:1481 +#: club/views.py:435 counter/views.py:1481 msgid "Begin date" msgstr "Date de début" -#: club/views.py:412 com/views.py:85 com/views.py:221 counter/views.py:1487 +#: club/views.py:441 com/views.py:85 com/views.py:221 counter/views.py:1487 #: election/views.py:190 subscription/views.py:52 msgid "End date" msgstr "Date de fin" -#: club/views.py:435 core/templates/core/user_stats.jinja:27 +#: club/views.py:464 core/templates/core/user_stats.jinja:27 #: counter/views.py:1635 msgid "Product" msgstr "Produit" @@ -3507,6 +3518,10 @@ msgstr "Parrain" msgid "Godchild" msgstr "Fillot" +#: core/views/forms.py:358 counter/views.py:113 trombi/views.py:141 +msgid "Select user" +msgstr "Choisir un utilisateur" + #: core/views/forms.py:371 core/views/forms.py:389 election/models.py:24 #: election/views.py:167 msgid "edit groups" @@ -3525,14 +3540,6 @@ msgstr "Utilisateurs à retirer du groupe" msgid "Users to add to group" msgstr "Utilisateurs à ajouter au groupe" -#: core/views/group.py:63 -msgid "Search users to add (one or more)." -msgstr "Recherche les utilisateurs à ajouter (un ou plus)." - -#: core/views/group.py:82 -msgid "You can not add the same user twice" -msgstr "Vous ne pouvez pas ajouter deux fois le même utilisateur" - #: core/views/user.py:223 trombi/templates/trombi/export.jinja:25 #: trombi/templates/trombi/user_profile.jinja:11 msgid "Pictures"