From cfd4955672f014323a754a38fde7a39119bd4dae Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Mon, 29 Apr 2019 19:22:01 +0200 Subject: [PATCH 1/8] clubs: clean up imports and move forms to external file --- club/forms.py | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++ club/views.py | 206 +++-------------------------------------------- 2 files changed, 232 insertions(+), 193 deletions(-) create mode 100644 club/forms.py diff --git a/club/forms.py b/club/forms.py new file mode 100644 index 00000000..fdfa8256 --- /dev/null +++ b/club/forms.py @@ -0,0 +1,219 @@ +# -*- coding:utf-8 -* +# +# Copyright 2016,2017 +# - Skia +# - Sli +# +# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM, +# http://ae.utbm.fr. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License a published by the Free Software +# Foundation; either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple +# Place - Suite 330, Boston, MA 02111-1307, USA. +# +# + +from django.conf import settings +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from ajax_select.fields import AutoCompleteSelectField, AutoCompleteSelectMultipleField + +from club.models import Mailing, MailingSubscription, Club, Membership + +from core.models import User +from core.views.forms import SelectDate, SelectDateTime +from counter.models import Counter + + +class ClubEditForm(forms.ModelForm): + class Meta: + model = Club + fields = ["address", "logo", "short_description"] + + def __init__(self, *args, **kwargs): + super(ClubEditForm, self).__init__(*args, **kwargs) + self.fields["short_description"].widget = forms.Textarea() + + +class MailingForm(forms.ModelForm): + class Meta: + model = Mailing + fields = ("email", "club", "moderator") + + def __init__(self, *args, **kwargs): + club_id = kwargs.pop("club_id", None) + user_id = kwargs.pop("user_id", -1) # Remember 0 is treated as None + super(MailingForm, self).__init__(*args, **kwargs) + if club_id: + self.fields["club"].queryset = Club.objects.filter(id=club_id) + self.fields["club"].initial = club_id + self.fields["club"].widget = forms.HiddenInput() + if user_id >= 0: + self.fields["moderator"].queryset = User.objects.filter(id=user_id) + self.fields["moderator"].initial = user_id + self.fields["moderator"].widget = forms.HiddenInput() + + +class MailingSubscriptionForm(forms.ModelForm): + class Meta: + model = MailingSubscription + fields = ("mailing", "user", "email") + + def __init__(self, *args, **kwargs): + kwargs.pop("user_id", None) # For standart interface + club_id = kwargs.pop("club_id", None) + super(MailingSubscriptionForm, self).__init__(*args, **kwargs) + self.fields["email"].required = False + if club_id: + self.fields["mailing"].queryset = Mailing.objects.filter( + club__id=club_id, is_moderated=True + ) + + user = AutoCompleteSelectField( + "users", label=_("User"), help_text=None, required=False + ) + + +class SellingsFormBase(forms.Form): + begin_date = forms.DateTimeField( + ["%Y-%m-%d %H:%M:%S"], + label=_("Begin date"), + required=False, + widget=SelectDateTime, + ) + end_date = forms.DateTimeField( + ["%Y-%m-%d %H:%M:%S"], + label=_("End date"), + required=False, + widget=SelectDateTime, + ) + counter = forms.ModelChoiceField( + Counter.objects.order_by("name").all(), label=_("Counter"), required=False + ) + + +class ClubMemberForm(forms.Form): + """ + Form handling the members of a club + """ + + error_css_class = "error" + required_css_class = "required" + + users = AutoCompleteSelectMultipleField( + "users", + label=_("Users to add"), + help_text=_("Search users to add (one or more)."), + required=False, + ) + + def __init__(self, *args, **kwargs): + self.club = kwargs.pop("club") + self.request_user = kwargs.pop("request_user") + self.club_members = kwargs.pop("club_members", None) + if not self.club_members: + self.club_members = ( + self.club.members.filter(end_date=None).order_by("-role").all() + ) + self.request_user_membership = self.club.get_membership_for(self.request_user) + super(ClubMemberForm, self).__init__(*args, **kwargs) + + # Using a ModelForm binds too much the form with the model and we don't want that + # We want the view to process the model creation since they are multiple users + # We also want the form to handle bulk deletion + self.fields.update( + forms.fields_for_model( + Membership, + fields=("role", "start_date", "description"), + widgets={"start_date": SelectDate}, + ) + ) + + # Role is required only if users is specified + self.fields["role"].required = False + + # Start date and description are never really required + self.fields["start_date"].required = False + self.fields["description"].required = False + + self.fields["users_old"] = forms.ModelMultipleChoiceField( + User.objects.filter( + id__in=[ + ms.user.id + for ms in self.club_members + if ms.can_be_edited_by( + self.request_user, self.request_user_membership + ) + ] + ).all(), + label=_("Mark as old"), + required=False, + widget=forms.CheckboxSelectMultiple, + ) + if not self.request_user.is_root: + self.fields.pop("start_date") + + def clean_users(self): + """ + Check that the user is not trying to add an user already in the club + Also check that the user is valid and has a valid subscription + """ + 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" + ) + if not user.is_subscribed: + raise forms.ValidationError( + _("User must be subscriber to take part to a club"), code="invalid" + ) + if self.club.get_membership_for(user): + raise forms.ValidationError( + _("You can not add the same user twice"), code="invalid" + ) + users.append(user) + return users + + def clean(self): + """ + Check user rights for adding an user + """ + cleaned_data = super(ClubMemberForm, self).clean() + + if "start_date" in cleaned_data and not cleaned_data["start_date"]: + # Drop start_date if allowed to edition but not specified + cleaned_data.pop("start_date") + + if not cleaned_data.get("users"): + # No user to add equals no check needed + return cleaned_data + + if cleaned_data.get("role", "") == "": + # Role is required if users exists + self.add_error("role", _("You should specify a role")) + 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.is_board_member + or request_user.is_root + ): + raise forms.ValidationError(_("You do not have the permission to do that")) + return cleaned_data diff --git a/club/views.py b/club/views.py index 7f50be06..c51b174f 100644 --- a/club/views.py +++ b/club/views.py @@ -23,6 +23,8 @@ # # + +from django.conf import settings from django import forms from django.views.generic import ListView, DetailView, TemplateView, View from django.views.generic.edit import DeleteView @@ -33,7 +35,6 @@ 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, AutoCompleteSelectMultipleField from django.core.exceptions import PermissionDenied from django.shortcuts import get_object_or_404, redirect @@ -46,71 +47,24 @@ from core.views import ( PageEditViewBase, DetailFormView, ) -from core.views.forms import SelectDate, SelectDateTime -from club.models import Club, Membership, Mailing, MailingSubscription -from sith.settings import SITH_MAXIMUM_FREE_ROLE -from counter.models import Selling, Counter -from core.models import User, PageRev +from core.models import PageRev + +from counter.models import Selling + from com.views import ( PosterListBaseView, PosterCreateBaseView, PosterEditBaseView, PosterDeleteBaseView, ) -from com.models import Poster -from django.conf import settings - -# Custom forms - - -class ClubEditForm(forms.ModelForm): - class Meta: - model = Club - fields = ["address", "logo", "short_description"] - - def __init__(self, *args, **kwargs): - super(ClubEditForm, self).__init__(*args, **kwargs) - self.fields["short_description"].widget = forms.Textarea() - - -class MailingForm(forms.ModelForm): - class Meta: - model = Mailing - fields = ("email", "club", "moderator") - - def __init__(self, *args, **kwargs): - club_id = kwargs.pop("club_id", None) - user_id = kwargs.pop("user_id", -1) # Remember 0 is treated as None - super(MailingForm, self).__init__(*args, **kwargs) - if club_id: - self.fields["club"].queryset = Club.objects.filter(id=club_id) - self.fields["club"].initial = club_id - self.fields["club"].widget = forms.HiddenInput() - if user_id >= 0: - self.fields["moderator"].queryset = User.objects.filter(id=user_id) - self.fields["moderator"].initial = user_id - self.fields["moderator"].widget = forms.HiddenInput() - - -class MailingSubscriptionForm(forms.ModelForm): - class Meta: - model = MailingSubscription - fields = ("mailing", "user", "email") - - def __init__(self, *args, **kwargs): - kwargs.pop("user_id", None) # For standart interface - club_id = kwargs.pop("club_id", None) - super(MailingSubscriptionForm, self).__init__(*args, **kwargs) - self.fields["email"].required = False - if club_id: - self.fields["mailing"].queryset = Mailing.objects.filter( - club__id=club_id, is_moderated=True - ) - - user = AutoCompleteSelectField( - "users", label=_("User"), help_text=None, required=False - ) +from club.models import Club, Membership, Mailing, MailingSubscription +from club.forms import ( + MailingForm, + MailingSubscriptionForm, + ClubEditForm, + ClubMemberForm, +) class ClubTabsMixin(TabedViewMixin): @@ -306,122 +260,6 @@ class ClubToolsView(ClubTabsMixin, CanEditMixin, DetailView): current_tab = "tools" -class ClubMemberForm(forms.Form): - """ - Form handling the members of a club - """ - - error_css_class = "error" - required_css_class = "required" - - users = AutoCompleteSelectMultipleField( - "users", - label=_("Users to add"), - help_text=_("Search users to add (one or more)."), - required=False, - ) - - def __init__(self, *args, **kwargs): - self.club = kwargs.pop("club") - self.request_user = kwargs.pop("request_user") - self.club_members = kwargs.pop("club_members", None) - if not self.club_members: - self.club_members = ( - self.club.members.filter(end_date=None).order_by("-role").all() - ) - self.request_user_membership = self.club.get_membership_for(self.request_user) - super(ClubMemberForm, self).__init__(*args, **kwargs) - - # Using a ModelForm binds too much the form with the model and we don't want that - # We want the view to process the model creation since they are multiple users - # We also want the form to handle bulk deletion - self.fields.update( - forms.fields_for_model( - Membership, - fields=("role", "start_date", "description"), - widgets={"start_date": SelectDate}, - ) - ) - - # Role is required only if users is specified - self.fields["role"].required = False - - # Start date and description are never really required - self.fields["start_date"].required = False - self.fields["description"].required = False - - self.fields["users_old"] = forms.ModelMultipleChoiceField( - User.objects.filter( - id__in=[ - ms.user.id - for ms in self.club_members - if ms.can_be_edited_by( - self.request_user, self.request_user_membership - ) - ] - ).all(), - label=_("Mark as old"), - required=False, - widget=forms.CheckboxSelectMultiple, - ) - if not self.request_user.is_root: - self.fields.pop("start_date") - - def clean_users(self): - """ - Check that the user is not trying to add an user already in the club - Also check that the user is valid and has a valid subscription - """ - 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" - ) - if not user.is_subscribed: - raise forms.ValidationError( - _("User must be subscriber to take part to a club"), code="invalid" - ) - if self.club.get_membership_for(user): - raise forms.ValidationError( - _("You can not add the same user twice"), code="invalid" - ) - users.append(user) - return users - - def clean(self): - """ - Check user rights for adding an user - """ - cleaned_data = super(ClubMemberForm, self).clean() - - if "start_date" in cleaned_data and not cleaned_data["start_date"]: - # Drop start_date if allowed to edition but not specified - cleaned_data.pop("start_date") - - if not cleaned_data.get("users"): - # No user to add equals no check needed - return cleaned_data - - if cleaned_data.get("role", "") == "": - # Role is required if users exists - self.add_error("role", _("You should specify a role")) - return cleaned_data - - request_user = self.request_user - membership = self.request_user_membership - 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, DetailFormView): """ View of a club's members @@ -485,24 +323,6 @@ class ClubOldMembersView(ClubTabsMixin, CanViewMixin, DetailView): current_tab = "elderlies" -class SellingsFormBase(forms.Form): - begin_date = forms.DateTimeField( - ["%Y-%m-%d %H:%M:%S"], - label=_("Begin date"), - required=False, - widget=SelectDateTime, - ) - end_date = forms.DateTimeField( - ["%Y-%m-%d %H:%M:%S"], - label=_("End date"), - required=False, - widget=SelectDateTime, - ) - counter = forms.ModelChoiceField( - Counter.objects.order_by("name").all(), label=_("Counter"), required=False - ) - - class ClubSellingView(ClubTabsMixin, CanEditMixin, DetailView): """ Sellings of a club From a0e39b8904b19b4a77714fec5c1c2bd857263eef Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 1 May 2019 03:32:28 +0200 Subject: [PATCH 2/8] clubs: rewrite MailingForm to include everything in one place Everything is handled on the same view, no more redirection hacks Remove get_context_data in DetailFormView since it's already done by django --- club/forms.py | 131 +++++++++++++++++++++++------- club/templates/club/mailing.jinja | 40 +++++++-- club/urls.py | 16 +--- club/views.py | 131 +++++++++++++++--------------- core/views/__init__.py | 5 -- 5 files changed, 202 insertions(+), 121 deletions(-) diff --git a/club/forms.py b/club/forms.py index fdfa8256..5b62df89 100644 --- a/club/forms.py +++ b/club/forms.py @@ -46,43 +46,118 @@ class ClubEditForm(forms.ModelForm): self.fields["short_description"].widget = forms.Textarea() -class MailingForm(forms.ModelForm): - class Meta: - model = Mailing - fields = ("email", "club", "moderator") +class MailingForm(forms.Form): + """ + Form handling mailing lists right + """ + + ACTION_NEW_MAILING = 1 + ACTION_NEW_SUBSCRIPTION = 2 + + subscription_users = AutoCompleteSelectMultipleField( + "users", + label=_("Users to add"), + help_text=_("Search users to add (one or more)."), + required=False, + ) def __init__(self, *args, **kwargs): club_id = kwargs.pop("club_id", None) user_id = kwargs.pop("user_id", -1) # Remember 0 is treated as None super(MailingForm, self).__init__(*args, **kwargs) + + self.fields["action"] = forms.TypedChoiceField( + ( + (self.ACTION_NEW_MAILING, _("New Mailing")), + (self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")), + ), + coerce=int, + label=_("Action"), + initial=1, + required=True, + widget=forms.HiddenInput(), + ) + + # Include fields for handling mailing creation + mailing_fields = ("email", "club", "moderator") + self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields)) + for field in mailing_fields: + self.fields["mailing_" + field] = self.fields.pop(field) + self.fields["mailing_" + field].required = False + + # Include fields for handling subscription creation + subscription_fields = ("mailing", "email") + self.fields.update( + forms.fields_for_model(MailingSubscription, fields=subscription_fields) + ) + for field in subscription_fields: + self.fields["subscription_" + field] = self.fields.pop(field) + self.fields["subscription_" + field].required = False + if club_id: - self.fields["club"].queryset = Club.objects.filter(id=club_id) - self.fields["club"].initial = club_id - self.fields["club"].widget = forms.HiddenInput() - if user_id >= 0: - self.fields["moderator"].queryset = User.objects.filter(id=user_id) - self.fields["moderator"].initial = user_id - self.fields["moderator"].widget = forms.HiddenInput() - - -class MailingSubscriptionForm(forms.ModelForm): - class Meta: - model = MailingSubscription - fields = ("mailing", "user", "email") - - def __init__(self, *args, **kwargs): - kwargs.pop("user_id", None) # For standart interface - club_id = kwargs.pop("club_id", None) - super(MailingSubscriptionForm, self).__init__(*args, **kwargs) - self.fields["email"].required = False - if club_id: - self.fields["mailing"].queryset = Mailing.objects.filter( + self.fields["mailing_club"].queryset = Club.objects.filter(id=club_id) + self.fields["mailing_club"].initial = club_id + self.fields["mailing_club"].widget = forms.HiddenInput() + self.fields["subscription_mailing"].queryset = Mailing.objects.filter( club__id=club_id, is_moderated=True ) + if user_id >= 0: + self.fields["mailing_moderator"].queryset = User.objects.filter(id=user_id) + self.fields["mailing_moderator"].initial = user_id + self.fields["mailing_moderator"].widget = forms.HiddenInput() - user = AutoCompleteSelectField( - "users", label=_("User"), help_text=None, required=False - ) + def check_required(self, cleaned_data, field): + """ + If the given field doesn't exist or has no value, add a required error on it + """ + if not cleaned_data.get(field, None): + self.add_error(field, _("This field is required")) + + def clean_subscription_users(self): + """ + Convert given users into real users and check their validity + """ + cleaned_data = super(MailingForm, self).clean() + users = [] + for user in cleaned_data["subscription_users"]: + user = User.objects.filter(id=user).first() + if not user: + raise forms.ValidationError( + _("One of the selected users doesn't exist"), code="invalid" + ) + if not user.email: + raise forms.ValidationError( + _("One of the selected users doesn't have an email address"), + code="invalid", + ) + users.append(user) + return users + + def clean(self): + cleaned_data = super(MailingForm, self).clean() + + print(cleaned_data) + + if not "action" in cleaned_data: + # If there is no action provided, we can stop here + raise forms.ValidationError(_("An action is required"), code="invalid") + + if cleaned_data["action"] == self.ACTION_NEW_MAILING: + self.check_required(cleaned_data, "mailing_email") + self.check_required(cleaned_data, "mailing_club") + self.check_required(cleaned_data, "mailing_moderator") + + if cleaned_data["action"] == self.ACTION_NEW_SUBSCRIPTION: + self.check_required(cleaned_data, "subscription_mailing") + if not cleaned_data.get( + "subscription_users", None + ) and not cleaned_data.get("subscription_email", None): + raise forms.ValidationError( + _("You must specify at least an user or an email address"), + code="invalid", + ) + + return cleaned_data class SellingsFormBase(forms.Form): diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 9c2af2b8..7d485338 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -5,11 +5,11 @@ {% endblock %} {% block content %} - {% if has_objects %} + {% if mailings %} {% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %} - {% for mailing in object_list %} + {% for mailing in mailings %} {% if mailing.is_moderated %}

{% trans %}Mailing{% endtrans %} {{ mailing.email_full }} {%- if user.is_owner(mailing) -%} @@ -47,19 +47,45 @@

{% trans %}No mailing list existing for this club{% endtrans %}

{% endif %} - {% if has_objects %} +

{{ form.non_field_errors() }}

+ {% if mailings_moderated %}

{% trans %}New member{% endtrans %}

-
+ {% csrf_token %} - {{ add_member.as_p() }} +

+ {{ form.subscription_mailing.errors }} + + {{ form.subscription_mailing }} +

+

+ {{ form.subscription_users.errors }} + + {{ form.subscription_users }} + {{ form.subscription_users.help_text }} +

+

+ {{ form.subscription_email.errors }} + + {{ form.subscription_email }} +

+

{% endif %}

{% trans %}New mailing{% endtrans %}

-
+ {% csrf_token %} - {{ add_mailing.as_p() }} + {{ form.mailing_club.errors }} + {{ form.mailing_moderator.errors }} +

+ {{ form.mailing_email.errors }} + + {{ form.mailing_email }} +

+ {{ form.mailing_club }} + {{ form.mailing_moderator }} +

diff --git a/club/urls.py b/club/urls.py index 8f446d65..d560a560 100644 --- a/club/urls.py +++ b/club/urls.py @@ -64,21 +64,7 @@ urlpatterns = [ ), url(r"^(?P[0-9]+)/prop$", ClubEditPropView.as_view(), name="club_prop"), url(r"^(?P[0-9]+)/tools$", ClubToolsView.as_view(), name="tools"), - url( - r"^(?P[0-9]+)/mailing$", - ClubMailingView.as_view(action="display"), - name="mailing", - ), - url( - r"^(?P[0-9]+)/mailing/new/mailing$", - ClubMailingView.as_view(action="add_mailing"), - name="mailing_create", - ), - url( - r"^(?P[0-9]+)/mailing/new/subscription$", - ClubMailingView.as_view(action="add_member"), - name="mailing_subscription_create", - ), + url(r"^(?P[0-9]+)/mailing$", ClubMailingView.as_view(), name="mailing"), url( r"^(?P[0-9]+)/mailing/generate$", MailingAutoGenerationView.as_view(), diff --git a/club/views.py b/club/views.py index c51b174f..7aae48f6 100644 --- a/club/views.py +++ b/club/views.py @@ -59,12 +59,7 @@ from com.views import ( ) from club.models import Club, Membership, Mailing, MailingSubscription -from club.forms import ( - MailingForm, - MailingSubscriptionForm, - ClubEditForm, - ClubMemberForm, -) +from club.forms import MailingForm, ClubEditForm, ClubMemberForm class ClubTabsMixin(TabedViewMixin): @@ -507,94 +502,98 @@ class ClubStatView(TemplateView): return kwargs -class ClubMailingView(ClubTabsMixin, ListView): +class ClubMailingView(ClubTabsMixin, DetailFormView): """ A list of mailing for a given club """ - action = None - model = Mailing + model = Club + form_class = MailingForm + pk_url_kwarg = "club_id" template_name = "club/mailing.jinja" current_tab = "mailing" def authorized(self): return ( - self.club.has_rights_in_club(self.user) - or self.user.is_root - or self.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) + self.get_object().has_rights_in_club(self.request.user) + or self.request.user.is_root + or self.request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) ) + def get_form_kwargs(self, *args, **kwargs): + kwargs = super(ClubMailingView, self).get_form_kwargs(*args, **kwargs) + kwargs["club_id"] = self.get_object().id + kwargs["user_id"] = self.request.user.id + return kwargs + def dispatch(self, request, *args, **kwargs): - self.club = get_object_or_404(Club, pk=kwargs["club_id"]) - self.user = request.user - self.object = self.club + res = super(ClubMailingView, self).dispatch(request, *args, **kwargs) if not self.authorized(): raise PermissionDenied - self.member_form = MailingSubscriptionForm(club_id=self.club.id) - self.mailing_form = MailingForm(club_id=self.club.id, user_id=self.user.id) - return super(ClubMailingView, self).dispatch(request, *args, **kwargs) - - def post(self, request, *args, **kwargs): - res = super(ClubMailingView, self).get(request, *args, **kwargs) - if self.action != "display": - if self.action == "add_mailing": - form = MailingForm - model = Mailing - elif self.action == "add_member": - form = MailingSubscriptionForm - model = MailingSubscription - return MailingGenericCreateView.as_view( - model=model, list_view=self, form_class=form - )(request, *args, **kwargs) return res - def get_queryset(self): - return Mailing.objects.filter(club_id=self.club.id).all() - def get_context_data(self, **kwargs): + self.object = self.get_object() kwargs = super(ClubMailingView, self).get_context_data(**kwargs) - kwargs["add_member"] = self.member_form - kwargs["add_mailing"] = self.mailing_form - kwargs["club"] = self.club - kwargs["user"] = self.user - kwargs["has_objects"] = len(kwargs["object_list"]) > 0 + kwargs["club"] = self.get_object() + kwargs["user"] = self.request.user + kwargs["mailings"] = Mailing.objects.filter(club_id=self.get_object().id).all() + kwargs["mailings_moderated"] = ( + kwargs["mailings"].exclude(is_moderated=False).all() + ) + kwargs["form_actions"] = { + "NEW_MALING": self.form_class.ACTION_NEW_MAILING, + "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION, + } return kwargs - def get_object(self): - return self.club + def add_new_mailing(self, cleaned_data): + """ + Create a new mailing list from the form + """ + mailing = Mailing( + club=cleaned_data["mailing_club"], + email=cleaned_data["mailing_email"], + moderator=cleaned_data["mailing_moderator"], + is_moderated=False, + ) + mailing.clean() + mailing.save() + def add_new_subscription(self, cleaned_data): + """ + Add mailing subscriptions for each user given and/or for the specified email in form + """ + for user in cleaned_data["subscription_users"]: + sub = MailingSubscription( + mailing=cleaned_data["subscription_mailing"], user=user + ) + sub.clean() + sub.save() -class MailingGenericCreateView(CreateView, SingleObjectMixin): - """ - Create a new mailing list - """ + if cleaned_data["subscription_email"]: + sub = MailingSubscription( + mailing=cleaned_data["subscription_mailing"], + email=cleaned_data["subscription_email"], + ) + sub.clean() + sub.save() - list_view = None - form_class = None + def form_valid(self, form): + resp = super(ClubMailingView, self).form_valid(form) - def get_context_data(self, **kwargs): - view_kwargs = self.list_view.get_context_data(**kwargs) - for key, data in ( - super(MailingGenericCreateView, self).get_context_data(**kwargs).items() - ): - view_kwargs[key] = data - view_kwargs[self.list_view.action] = view_kwargs["form"] - return view_kwargs + cleaned_data = form.clean() - def get_form_kwargs(self): - kwargs = super(MailingGenericCreateView, self).get_form_kwargs() - kwargs["club_id"] = self.list_view.club.id - kwargs["user_id"] = self.list_view.user.id - return kwargs + if cleaned_data["action"] == self.form_class.ACTION_NEW_MAILING: + self.add_new_mailing(cleaned_data) - def dispatch(self, request, *args, **kwargs): - if not self.list_view.authorized(): - raise PermissionDenied - self.template_name = self.list_view.template_name - return super(MailingGenericCreateView, self).dispatch(request, *args, **kwargs) + if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION: + self.add_new_subscription(cleaned_data) + + return resp def get_success_url(self, **kwargs): - return reverse_lazy("club:mailing", kwargs={"club_id": self.list_view.club.id}) + return reverse_lazy("club:mailing", kwargs={"club_id": self.get_object().id}) class MailingDeleteView(CanEditMixin, DeleteView): diff --git a/core/views/__init__.py b/core/views/__init__.py index c4972bd0..202b08fa 100644 --- a/core/views/__init__.py +++ b/core/views/__init__.py @@ -296,11 +296,6 @@ class DetailFormView(SingleObjectMixin, FormView): """ return super(DetailFormView, self).get_object() - def get_context_data(self, *args, **kwargs): - kwargs = super(DetailFormView, self).get_context_data() - kwargs["object"] = self.get_object() - return kwargs - from .user import * from .page import * From da25480993abf13054e6f3c4fe5eceb164715a6e Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 1 May 2019 15:50:03 +0200 Subject: [PATCH 3/8] clubs: use standard rights for ClubMailingView --- club/views.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/club/views.py b/club/views.py index 7aae48f6..06c8c7f3 100644 --- a/club/views.py +++ b/club/views.py @@ -502,7 +502,7 @@ class ClubStatView(TemplateView): return kwargs -class ClubMailingView(ClubTabsMixin, DetailFormView): +class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): """ A list of mailing for a given club """ @@ -513,27 +513,13 @@ class ClubMailingView(ClubTabsMixin, DetailFormView): template_name = "club/mailing.jinja" current_tab = "mailing" - def authorized(self): - return ( - self.get_object().has_rights_in_club(self.request.user) - or self.request.user.is_root - or self.request.user.is_in_group(settings.SITH_GROUP_COM_ADMIN_ID) - ) - def get_form_kwargs(self, *args, **kwargs): kwargs = super(ClubMailingView, self).get_form_kwargs(*args, **kwargs) kwargs["club_id"] = self.get_object().id kwargs["user_id"] = self.request.user.id return kwargs - def dispatch(self, request, *args, **kwargs): - res = super(ClubMailingView, self).dispatch(request, *args, **kwargs) - if not self.authorized(): - raise PermissionDenied - return res - def get_context_data(self, **kwargs): - self.object = self.get_object() kwargs = super(ClubMailingView, self).get_context_data(**kwargs) kwargs["club"] = self.get_object() kwargs["user"] = self.request.user From 24fb714c5edf0eb749b790fba2b99fed4072d2ef Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 1 May 2019 18:59:41 +0200 Subject: [PATCH 4/8] clubs: set club_id and user_id as mandatory arguments for MailingForm --- club/forms.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/club/forms.py b/club/forms.py index 5b62df89..0492577b 100644 --- a/club/forms.py +++ b/club/forms.py @@ -61,9 +61,7 @@ class MailingForm(forms.Form): required=False, ) - def __init__(self, *args, **kwargs): - club_id = kwargs.pop("club_id", None) - user_id = kwargs.pop("user_id", -1) # Remember 0 is treated as None + def __init__(self, club_id, user_id, *args, **kwargs): super(MailingForm, self).__init__(*args, **kwargs) self.fields["action"] = forms.TypedChoiceField( @@ -94,17 +92,16 @@ class MailingForm(forms.Form): self.fields["subscription_" + field] = self.fields.pop(field) self.fields["subscription_" + field].required = False - if club_id: - self.fields["mailing_club"].queryset = Club.objects.filter(id=club_id) - self.fields["mailing_club"].initial = club_id - self.fields["mailing_club"].widget = forms.HiddenInput() - self.fields["subscription_mailing"].queryset = Mailing.objects.filter( - club__id=club_id, is_moderated=True - ) - if user_id >= 0: - self.fields["mailing_moderator"].queryset = User.objects.filter(id=user_id) - self.fields["mailing_moderator"].initial = user_id - self.fields["mailing_moderator"].widget = forms.HiddenInput() + self.fields["mailing_club"].queryset = Club.objects.filter(id=club_id) + self.fields["mailing_club"].initial = club_id + self.fields["mailing_club"].widget = forms.HiddenInput() + self.fields["subscription_mailing"].queryset = Mailing.objects.filter( + club__id=club_id, is_moderated=True + ) + + self.fields["mailing_moderator"].queryset = User.objects.filter(id=user_id) + self.fields["mailing_moderator"].initial = user_id + self.fields["mailing_moderator"].widget = forms.HiddenInput() def check_required(self, cleaned_data, field): """ From 1d07195881649a0dbf579059727d7176dbe39290 Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Wed, 1 May 2019 22:52:22 +0200 Subject: [PATCH 5/8] clubs: add bulk deletion on mailing lists --- club/forms.py | 15 +- club/models.py | 14 +- club/templates/club/mailing.jinja | 55 +++++--- club/urls.py | 5 - club/views.py | 40 ++++-- locale/fr/LC_MESSAGES/django.po | 224 +++++++++++++++++------------- 6 files changed, 209 insertions(+), 144 deletions(-) diff --git a/club/forms.py b/club/forms.py index 0492577b..e0966fed 100644 --- a/club/forms.py +++ b/club/forms.py @@ -53,6 +53,7 @@ class MailingForm(forms.Form): ACTION_NEW_MAILING = 1 ACTION_NEW_SUBSCRIPTION = 2 + ACTION_REMOVE_SUBSCRIPTION = 3 subscription_users = AutoCompleteSelectMultipleField( "users", @@ -61,13 +62,14 @@ class MailingForm(forms.Form): required=False, ) - def __init__(self, club_id, user_id, *args, **kwargs): + def __init__(self, club_id, user_id, mailings, *args, **kwargs): super(MailingForm, self).__init__(*args, **kwargs) self.fields["action"] = forms.TypedChoiceField( ( (self.ACTION_NEW_MAILING, _("New Mailing")), (self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")), + (self.ACTION_REMOVE_SUBSCRIPTION, _("Remove")), ), coerce=int, label=_("Action"), @@ -76,6 +78,15 @@ class MailingForm(forms.Form): widget=forms.HiddenInput(), ) + # Generate bulk removal forms, they are never required + for mailing in mailings: + self.fields["removal_" + str(mailing.id)] = forms.ModelMultipleChoiceField( + mailing.subscriptions.all(), + label=_("Remove"), + required=False, + widget=forms.CheckboxSelectMultiple, + ) + # Include fields for handling mailing creation mailing_fields = ("email", "club", "moderator") self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields)) @@ -133,8 +144,6 @@ class MailingForm(forms.Form): def clean(self): cleaned_data = super(MailingForm, self).clean() - print(cleaned_data) - if not "action" in cleaned_data: # If there is no action provided, we can stop here raise forms.ValidationError(_("An action is required"), code="invalid") diff --git a/club/models.py b/club/models.py index d446c080..50cacd0d 100644 --- a/club/models.py +++ b/club/models.py @@ -446,18 +446,20 @@ class MailingSubscription(models.Model): def can_be_edited_by(self, user): return self.user is not None and user.id == self.user.id - @property + @cached_property def get_email(self): if self.user and not self.email: return self.user.email return self.email + @cached_property + def get_username(self): + if self.user: + return str(self.user) + return _("Unregistered user") + def fetch_format(self): return self.get_email + " " def __str__(self): - if self.user: - user = str(self.user) - else: - user = _("Unregistered user") - return "(%s) - %s : %s" % (self.mailing, user, self.email) + return "(%s) - %s : %s" % (self.mailing, self.get_username, self.email) diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 7d485338..1222a332 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -1,4 +1,5 @@ {% extends "core/base.jinja" %} +{% from 'core/macros.jinja' import select_all_checkbox %} {% block title %} {% trans %}Mailing lists{% endtrans %} @@ -10,8 +11,7 @@ {% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %} {% for mailing in mailings %} - {% if mailing.is_moderated %} -

{% trans %}Mailing{% endtrans %} {{ mailing.email_full }} +

{% trans %}Mailing{% endtrans %} {{ mailing.email_full }} {%- if user.is_owner(mailing) -%} - {% trans %}Delete{% endtrans %} {%- endif -%} @@ -19,27 +19,38 @@
-
- + {% set form_mailing_removal = form["removal_" + mailing.id|string] %} + {% if form_mailing_removal.field.choices %} + {% set ms = dict(mailing.subscriptions.all() | groupby('id')) %} + +

{{ select_all_checkbox(form_mailing_removal.auto_id) }}

+ {% csrf_token %} + + + + + + + + + + + {% for widget in form_mailing_removal.subwidgets %} + {% set user = ms[widget.data.value][0] %} + + + + + + {% endfor %} + +
{% trans %}User{% endtrans %}{% trans %}Email{% endtrans %}{% trans %}Delete{% endtrans %}
{{ user.get_username }}{{ user.get_email }}{{ widget.tag() }}
+ {{ form_mailing_removal.errors }} +

-
- - - - - - {% for subscriber in mailing.subscriptions.all() %} - - {% if subscriber.user %} - - {% else %} - - {% endif %} - - - - {% endfor %} -
{% trans %}User{% endtrans %}{% trans %}Email{%endtrans%}
{{ subscriber.user }}{% trans %}Unregistered user{% endtrans %}{{ subscriber.get_email }}{% trans %}Delete{% endtrans %}
+ + {% else %} +

{% trans %}There is no subscriber for this mailing list{% endtrans %}

{% endif %} {% endfor %} diff --git a/club/urls.py b/club/urls.py index d560a560..c5a01e02 100644 --- a/club/urls.py +++ b/club/urls.py @@ -70,11 +70,6 @@ urlpatterns = [ MailingAutoGenerationView.as_view(), name="mailing_generate", ), - url( - r"^(?P[0-9]+)/mailing/clean$", - MailingAutoCleanView.as_view(), - name="mailing_clean", - ), url( r"^(?P[0-9]+)/mailing/delete$", MailingDeleteView.as_view(), diff --git a/club/views.py b/club/views.py index 06c8c7f3..151dab16 100644 --- a/club/views.py +++ b/club/views.py @@ -513,23 +513,29 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): template_name = "club/mailing.jinja" current_tab = "mailing" - def get_form_kwargs(self, *args, **kwargs): - kwargs = super(ClubMailingView, self).get_form_kwargs(*args, **kwargs) + def get_form_kwargs(self): + kwargs = super(ClubMailingView, self).get_form_kwargs() kwargs["club_id"] = self.get_object().id kwargs["user_id"] = self.request.user.id + kwargs["mailings"] = self.mailings return kwargs + def dispatch(self, request, *args, **kwargs): + self.mailings = Mailing.objects.filter(club_id=self.get_object().id).all() + return super(ClubMailingView, self).dispatch(request, *args, **kwargs) + def get_context_data(self, **kwargs): kwargs = super(ClubMailingView, self).get_context_data(**kwargs) kwargs["club"] = self.get_object() kwargs["user"] = self.request.user - kwargs["mailings"] = Mailing.objects.filter(club_id=self.get_object().id).all() + kwargs["mailings"] = self.mailings kwargs["mailings_moderated"] = ( kwargs["mailings"].exclude(is_moderated=False).all() ) kwargs["form_actions"] = { "NEW_MALING": self.form_class.ACTION_NEW_MAILING, "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION, + "REMOVE_SUBSCRIPTION": self.form_class.ACTION_REMOVE_SUBSCRIPTION, } return kwargs @@ -565,6 +571,19 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): sub.clean() sub.save() + def remove_subscription(self, cleaned_data): + """ + Remove specified users from a mailing list + """ + fields = [ + cleaned_data[key] + for key in cleaned_data.keys() + if key.startswith("removal_") + ] + for field in fields: + for sub in field: + sub.delete() + def form_valid(self, form): resp = super(ClubMailingView, self).form_valid(form) @@ -576,6 +595,9 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION: self.add_new_subscription(cleaned_data) + if cleaned_data["action"] == self.form_class.ACTION_REMOVE_SUBSCRIPTION: + self.remove_subscription(cleaned_data) + return resp def get_success_url(self, **kwargs): @@ -634,18 +656,6 @@ class MailingAutoGenerationView(View): return redirect("club:mailing", club_id=club.id) -class MailingAutoCleanView(View): - def dispatch(self, request, *args, **kwargs): - self.mailing = get_object_or_404(Mailing, pk=kwargs["mailing_id"]) - if not request.user.can_edit(self.mailing): - raise PermissionDenied - return super(MailingAutoCleanView, self).dispatch(request, *args, **kwargs) - - def get(self, request, *args, **kwargs): - self.mailing.subscriptions.all().delete() - return redirect("club:mailing", club_id=self.mailing.club.id) - - class PosterListView(ClubTabsMixin, PosterListBaseView, CanViewMixin): """List communication posters""" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index d5f73570..ec15c62e 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-28 15:00+0200\n" +"POT-Creation-Date: 2019-05-01 22:45+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:413 #: club/templates/club/club_members.jinja:16 #: club/templates/club/club_old_members.jinja:8 -#: club/templates/club/mailing.jinja:28 club/views.py:112 +#: club/templates/club/mailing.jinja:32 #: counter/templates/counter/cash_summary_list.jinja:32 #: counter/templates/counter/stats.jinja:15 #: counter/templates/counter/stats.jinja:52 @@ -345,7 +345,7 @@ msgstr "Compte en banque : " #: accounting/templates/accounting/club_account_details.jinja:60 #: accounting/templates/accounting/label_list.jinja:26 #: club/templates/club/club_sellings.jinja:50 -#: club/templates/club/mailing.jinja:16 club/templates/club/mailing.jinja:39 +#: club/templates/club/mailing.jinja:16 club/templates/club/mailing.jinja:34 #: com/templates/com/mailing_admin.jinja:19 #: com/templates/com/news_admin_list.jinja:41 #: com/templates/com/news_admin_list.jinja:70 @@ -386,7 +386,7 @@ msgid "Delete" msgstr "Supprimer" #: accounting/templates/accounting/bank_account_details.jinja:18 -#: club/views.py:129 core/views/user.py:205 sas/templates/sas/picture.jinja:86 +#: club/views.py:78 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:175 +#: accounting/templates/accounting/journal_details.jinja:89 club/views.py:124 #: com/templates/com/news_admin_list.jinja:39 #: com/templates/com/news_admin_list.jinja:68 #: com/templates/com/news_admin_list.jinja:115 @@ -893,6 +893,101 @@ msgstr "Opérations sans étiquette" msgid "Refound this account" msgstr "Rembourser ce compte" +#: club/forms.py:60 club/forms.py:197 +msgid "Users to add" +msgstr "Utilisateurs à ajouter" + +#: club/forms.py:61 club/forms.py:198 core/views/group.py:63 +msgid "Search users to add (one or more)." +msgstr "Recherche les utilisateurs à ajouter (un ou plus)." + +#: club/forms.py:70 +#, fuzzy +#| msgid "New mailing" +msgid "New Mailing" +msgstr "Nouvelle mailing liste" + +#: club/forms.py:71 +#, fuzzy +#| msgid "Unsubscribe" +msgid "Subscribe" +msgstr "Se désabonner" + +#: club/forms.py:72 club/forms.py:85 com/templates/com/news_admin_list.jinja:40 +#: com/templates/com/news_admin_list.jinja:116 +#: com/templates/com/news_admin_list.jinja:198 +#: com/templates/com/news_admin_list.jinja:274 +msgid "Remove" +msgstr "Retirer" + +#: club/forms.py:75 launderette/views.py:228 +msgid "Action" +msgstr "Action" + +#: club/forms.py:122 +#, fuzzy +#| msgid "This field is required." +msgid "This field is required" +msgstr "Ce champ est obligatoire." + +#: club/forms.py:134 club/forms.py:259 +msgid "One of the selected users doesn't exist" +msgstr "Un des utilisateurs sélectionné n'existe pas" + +#: club/forms.py:138 +#, fuzzy +#| msgid "One of the selected users doesn't exist" +msgid "One of the selected users doesn't have an email address" +msgstr "Un des utilisateurs sélectionné n'existe pas" + +#: club/forms.py:149 +#, fuzzy +#| msgid "This field is required." +msgid "An action is required" +msgstr "Ce champ est obligatoire." + +#: club/forms.py:162 +msgid "You must specify at least an user or an email address" +msgstr "" + +#: club/forms.py:172 counter/views.py:1481 +msgid "Begin date" +msgstr "Date de début" + +#: club/forms.py:178 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/forms.py:183 club/templates/club/club_sellings.jinja:21 +#: 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 +msgid "Counter" +msgstr "Comptoir" + +#: club/forms.py:241 club/templates/club/club_members.jinja:21 +#: club/templates/club/club_members.jinja:46 +#: core/templates/core/user_clubs.jinja:29 +msgid "Mark as old" +msgstr "Marquer comme ancien" + +#: club/forms.py:263 +msgid "User must be subscriber to take part to a club" +msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" + +#: club/forms.py:267 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/forms.py:288 +msgid "You should specify a role" +msgstr "Vous devez choisir un rôle" + +#: club/forms.py:299 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/models.py:51 msgid "unix name" msgstr "nom unix" @@ -988,9 +1083,9 @@ msgstr "Au moins un utilisateur ou un email est nécessaire" msgid "This email is already suscribed in this mailing" msgstr "Cet email est déjà abonné à cette mailing" -#: club/models.py:462 club/templates/club/mailing.jinja:36 +#: club/models.py:459 msgid "Unregistered user" -msgstr "Désabonner un utilisateur" +msgstr "Utilisateur non enregistré" #: club/templates/club/club_list.jinja:4 club/templates/club/club_list.jinja:37 msgid "Club list" @@ -1037,12 +1132,6 @@ msgstr "Description" msgid "Since" msgstr "Depuis" -#: club/templates/club/club_members.jinja:21 -#: club/templates/club/club_members.jinja:46 club/views.py:363 -#: core/templates/core/user_clubs.jinja:29 -msgid "Mark as old" -msgstr "Marquer comme ancien" - #: club/templates/club/club_members.jinja:50 msgid "There are no members in this club." msgstr "Il n'y a pas de membres dans ce club." @@ -1067,8 +1156,8 @@ msgstr "Du" msgid "To" msgstr "Au" -#: club/templates/club/club_sellings.jinja:5 club/views.py:195 -#: club/views.py:563 counter/templates/counter/counter_main.jinja:19 +#: club/templates/club/club_sellings.jinja:5 club/views.py:144 +#: club/views.py:378 counter/templates/counter/counter_main.jinja:19 #: counter/templates/counter/last_ops.jinja:35 msgid "Sellings" msgstr "Ventes" @@ -1094,13 +1183,6 @@ msgstr "unités" msgid "Benefit: " msgstr "Bénéfice : " -#: club/templates/club/club_sellings.jinja:21 club/views.py:502 -#: 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 -msgid "Counter" -msgstr "Comptoir" - #: club/templates/club/club_sellings.jinja:22 #: core/templates/core/user_account_detail.jinja:19 #: core/templates/core/user_account_detail.jinja:52 @@ -1189,11 +1271,11 @@ msgstr "Comptabilité : " msgid "Manage launderettes" msgstr "Gestion des laveries" -#: club/templates/club/mailing.jinja:4 +#: club/templates/club/mailing.jinja:5 msgid "Mailing lists" msgstr "Mailing listes" -#: club/templates/club/mailing.jinja:10 +#: club/templates/club/mailing.jinja:11 msgid "" "Remember : mailing lists need to be moderated, if your new created list is " "not shown wait until moderation takes action" @@ -1206,34 +1288,38 @@ msgstr "" msgid "Generate mailing list" msgstr "Générer la liste de diffusion" -#: club/templates/club/mailing.jinja:23 -msgid "Clean mailing list" -msgstr "Néttoyer la liste de diffusion" - -#: club/templates/club/mailing.jinja:29 +#: club/templates/club/mailing.jinja:33 #: com/templates/com/mailing_admin.jinja:10 msgid "Email" msgstr "Email" -#: club/templates/club/mailing.jinja:47 +#: club/templates/club/mailing.jinja:49 +msgid "Remove from mailing list" +msgstr "Supprimer de la liste de diffusion" + +#: club/templates/club/mailing.jinja:53 +msgid "There is no subscriber for this mailing list" +msgstr "Il n'y a pas d'abonnés dans cette liste de diffusion" + +#: club/templates/club/mailing.jinja:58 msgid "No mailing list existing for this club" msgstr "Aucune mailing liste n'existe pour ce club" -#: club/templates/club/mailing.jinja:51 +#: club/templates/club/mailing.jinja:63 msgid "New member" msgstr "Nouveau membre" -#: club/templates/club/mailing.jinja:55 +#: club/templates/club/mailing.jinja:83 msgid "Add to mailing list" msgstr "Ajouter à la mailing liste" -#: club/templates/club/mailing.jinja:59 +#: club/templates/club/mailing.jinja:87 msgid "New mailing" -msgstr "Nouvelle mailing liste" +msgstr "Nouvelle liste de diffusion" -#: club/templates/club/mailing.jinja:63 +#: club/templates/club/mailing.jinja:100 msgid "Create mailing list" -msgstr "Créer une mailing liste" +msgstr "Créer une liste de diffusion" #: club/templates/club/page_history.jinja:8 msgid "No page existing for this club" @@ -1243,79 +1329,42 @@ msgstr "Aucune page n'existe pour ce club" msgid "Club stats" msgstr "Statistiques du club" -#: club/views.py:139 +#: club/views.py:88 msgid "Members" msgstr "Membres" -#: club/views.py:148 +#: club/views.py:97 msgid "Old members" msgstr "Anciens membres" -#: club/views.py:158 core/templates/core/page.jinja:33 +#: club/views.py:107 core/templates/core/page.jinja:33 msgid "History" msgstr "Historique" -#: club/views.py:166 core/templates/core/base.jinja:121 core/views/user.py:228 +#: club/views.py:115 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:186 +#: club/views.py:135 msgid "Edit club page" msgstr "Éditer la page de club" -#: club/views.py:202 +#: club/views.py:151 msgid "Mailing list" msgstr "Listes de diffusion" -#: club/views.py:211 com/views.py:141 +#: club/views.py:160 com/views.py:141 msgid "Posters list" msgstr "Liste d'affiches" -#: club/views.py:221 counter/templates/counter/counter_list.jinja:21 +#: club/views.py:170 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:319 -msgid "Users to add" -msgstr "Utilisateurs à ajouter" - -#: 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:381 -msgid "One of the selected users doesn't exist" -msgstr "Un des utilisateurs sélectionné n'existe pas" - -#: club/views.py:385 -msgid "User must be subscriber to take part to a club" -msgstr "L'utilisateur doit être cotisant pour faire partie d'un club" - -#: club/views.py:389 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:410 -msgid "You should specify a role" -msgstr "Vous devez choisir un rôle" - -#: club/views.py:421 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:491 counter/views.py:1481 -msgid "Begin date" -msgstr "Date de début" - -#: club/views.py:497 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:520 core/templates/core/user_stats.jinja:27 +#: club/views.py:335 core/templates/core/user_stats.jinja:27 #: counter/views.py:1635 msgid "Product" msgstr "Produit" @@ -1547,13 +1596,6 @@ msgstr "Auteur" msgid "Moderator" msgstr "Modérateur" -#: com/templates/com/news_admin_list.jinja:40 -#: com/templates/com/news_admin_list.jinja:116 -#: com/templates/com/news_admin_list.jinja:198 -#: com/templates/com/news_admin_list.jinja:274 -msgid "Remove" -msgstr "Retirer" - #: com/templates/com/news_admin_list.jinja:47 msgid "Notices to moderate" msgstr "Informations à modérer" @@ -4612,10 +4654,6 @@ msgstr "Éditer la page de présentation" msgid "Book launderette slot" msgstr "Réserver un créneau de laverie" -#: launderette/views.py:228 -msgid "Action" -msgstr "Action" - #: launderette/views.py:240 msgid "Tokens, separated by spaces" msgstr "Jetons, séparés par des espaces" From d1fb9cc4c3d5ec91d835e0fcec2cfe6811997367 Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Thu, 9 May 2019 17:43:47 +0200 Subject: [PATCH 6/8] clubs: remove moderator and club from mailing form + display not moderated mailings --- club/forms.py | 13 ++------- club/models.py | 2 ++ club/templates/club/mailing.jinja | 17 ++++++++---- club/views.py | 36 ++++++++++++++++++------ locale/fr/LC_MESSAGES/django.po | 46 ++++++++++++++++++------------- 5 files changed, 70 insertions(+), 44 deletions(-) diff --git a/club/forms.py b/club/forms.py index e0966fed..6cf4e405 100644 --- a/club/forms.py +++ b/club/forms.py @@ -88,7 +88,7 @@ class MailingForm(forms.Form): ) # Include fields for handling mailing creation - mailing_fields = ("email", "club", "moderator") + mailing_fields = ("email",) self.fields.update(forms.fields_for_model(Mailing, fields=mailing_fields)) for field in mailing_fields: self.fields["mailing_" + field] = self.fields.pop(field) @@ -103,17 +103,10 @@ class MailingForm(forms.Form): self.fields["subscription_" + field] = self.fields.pop(field) self.fields["subscription_" + field].required = False - self.fields["mailing_club"].queryset = Club.objects.filter(id=club_id) - self.fields["mailing_club"].initial = club_id - self.fields["mailing_club"].widget = forms.HiddenInput() self.fields["subscription_mailing"].queryset = Mailing.objects.filter( club__id=club_id, is_moderated=True ) - self.fields["mailing_moderator"].queryset = User.objects.filter(id=user_id) - self.fields["mailing_moderator"].initial = user_id - self.fields["mailing_moderator"].widget = forms.HiddenInput() - def check_required(self, cleaned_data, field): """ If the given field doesn't exist or has no value, add a required error on it @@ -150,8 +143,8 @@ class MailingForm(forms.Form): if cleaned_data["action"] == self.ACTION_NEW_MAILING: self.check_required(cleaned_data, "mailing_email") - self.check_required(cleaned_data, "mailing_club") - self.check_required(cleaned_data, "mailing_moderator") + # self.check_required(cleaned_data, "mailing_club") + # self.check_required(cleaned_data, "mailing_moderator") if cleaned_data["action"] == self.ACTION_NEW_SUBSCRIPTION: self.check_required(cleaned_data, "subscription_mailing") diff --git a/club/models.py b/club/models.py index 50cacd0d..5f0b58dd 100644 --- a/club/models.py +++ b/club/models.py @@ -338,6 +338,8 @@ class Mailing(models.Model): ) def clean(self): + if Mailing.objects.filter(email=self.email).exists(): + raise ValidationError(_("This mailing list already exists.")) if self.can_moderate(self.moderator): self.is_moderated = True else: diff --git a/club/templates/club/mailing.jinja b/club/templates/club/mailing.jinja index 1222a332..7aa88eed 100644 --- a/club/templates/club/mailing.jinja +++ b/club/templates/club/mailing.jinja @@ -6,11 +6,20 @@ {% endblock %} {% block content %} - {% if mailings %} {% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %} - {% for mailing in mailings %} + {% if mailings_not_moderated %} +

{% trans %}Mailing lists waiting for moderation{% endtrans %}

+ + {% endif %} + + {% if mailings_moderated %} + {% for mailing in mailings_moderated %}

{% trans %}Mailing{% endtrans %} {{ mailing.email_full }} {%- if user.is_owner(mailing) -%} - {% trans %}Delete{% endtrans %} @@ -87,15 +96,11 @@

{% trans %}New mailing{% endtrans %}

{% csrf_token %} - {{ form.mailing_club.errors }} - {{ form.mailing_moderator.errors }}

{{ form.mailing_email.errors }} {{ form.mailing_email }}

- {{ form.mailing_club }} - {{ form.mailing_moderator }}

diff --git a/club/views.py b/club/views.py index 151dab16..31dc0ad0 100644 --- a/club/views.py +++ b/club/views.py @@ -35,7 +35,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 django.core.exceptions import PermissionDenied +from django.core.exceptions import PermissionDenied, ValidationError, NON_FIELD_ERRORS from django.shortcuts import get_object_or_404, redirect from core.views import ( @@ -532,6 +532,9 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): kwargs["mailings_moderated"] = ( kwargs["mailings"].exclude(is_moderated=False).all() ) + kwargs["mailings_not_moderated"] = ( + kwargs["mailings"].exclude(is_moderated=True).all() + ) kwargs["form_actions"] = { "NEW_MALING": self.form_class.ACTION_NEW_MAILING, "NEW_SUBSCRIPTION": self.form_class.ACTION_NEW_SUBSCRIPTION, @@ -539,20 +542,24 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): } return kwargs - def add_new_mailing(self, cleaned_data): + def add_new_mailing(self, cleaned_data) -> ValidationError: """ Create a new mailing list from the form """ mailing = Mailing( - club=cleaned_data["mailing_club"], + club=self.get_object(), email=cleaned_data["mailing_email"], - moderator=cleaned_data["mailing_moderator"], + moderator=self.request.user, is_moderated=False, ) - mailing.clean() + try: + mailing.clean() + except ValidationError as validation_error: + return validation_error mailing.save() + return None - def add_new_subscription(self, cleaned_data): + def add_new_subscription(self, cleaned_data) -> ValidationError: """ Add mailing subscriptions for each user given and/or for the specified email in form """ @@ -568,8 +575,14 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): mailing=cleaned_data["subscription_mailing"], email=cleaned_data["subscription_email"], ) + + try: sub.clean() - sub.save() + except ValidationError as validation_error: + return validation_error + sub.save() + + return None def remove_subscription(self, cleaned_data): """ @@ -588,16 +601,21 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): resp = super(ClubMailingView, self).form_valid(form) cleaned_data = form.clean() + error = None if cleaned_data["action"] == self.form_class.ACTION_NEW_MAILING: - self.add_new_mailing(cleaned_data) + error = self.add_new_mailing(cleaned_data) if cleaned_data["action"] == self.form_class.ACTION_NEW_SUBSCRIPTION: - self.add_new_subscription(cleaned_data) + error = self.add_new_subscription(cleaned_data) if cleaned_data["action"] == self.form_class.ACTION_REMOVE_SUBSCRIPTION: self.remove_subscription(cleaned_data) + if error: + form.add_error(NON_FIELD_ERRORS, error) + return self.form_invalid(form) + return resp def get_success_url(self, **kwargs): diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index ec15c62e..5b54e273 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-05-01 22:45+0200\n" +"POT-Creation-Date: 2019-05-09 11:33+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Skia \n" "Language-Team: AE info \n" @@ -174,10 +174,10 @@ msgstr "étiquette" msgid "target type" msgstr "type de cible" -#: accounting/models.py:313 club/models.py:413 +#: accounting/models.py:313 club/models.py:415 #: club/templates/club/club_members.jinja:16 #: club/templates/club/club_old_members.jinja:8 -#: club/templates/club/mailing.jinja:32 +#: club/templates/club/mailing.jinja:41 #: counter/templates/counter/cash_summary_list.jinja:32 #: counter/templates/counter/stats.jinja:15 #: counter/templates/counter/stats.jinja:52 @@ -345,7 +345,7 @@ msgstr "Compte en banque : " #: accounting/templates/accounting/club_account_details.jinja:60 #: accounting/templates/accounting/label_list.jinja:26 #: club/templates/club/club_sellings.jinja:50 -#: club/templates/club/mailing.jinja:16 club/templates/club/mailing.jinja:34 +#: club/templates/club/mailing.jinja:25 club/templates/club/mailing.jinja:43 #: com/templates/com/mailing_admin.jinja:19 #: com/templates/com/news_admin_list.jinja:41 #: com/templates/com/news_admin_list.jinja:70 @@ -1054,7 +1054,7 @@ msgstr "description" msgid "past member" msgstr "Anciens membres" -#: club/models.py:323 club/models.py:418 +#: club/models.py:323 club/models.py:420 msgid "Email address" msgstr "Adresse email" @@ -1071,19 +1071,23 @@ msgstr "est modéré" msgid "moderator" msgstr "modérateur" -#: club/models.py:406 club/templates/club/mailing.jinja:14 +#: club/models.py:342 +msgid "This mailing list already exists." +msgstr "Cette liste de diffusion existe déjà." + +#: club/models.py:408 club/templates/club/mailing.jinja:23 msgid "Mailing" msgstr "Liste de diffusion" -#: club/models.py:425 +#: club/models.py:427 msgid "At least user or email is required" msgstr "Au moins un utilisateur ou un email est nécessaire" -#: club/models.py:433 +#: club/models.py:435 msgid "This email is already suscribed in this mailing" msgstr "Cet email est déjà abonné à cette mailing" -#: club/models.py:459 +#: club/models.py:461 msgid "Unregistered user" msgstr "Utilisateur non enregistré" @@ -1275,7 +1279,7 @@ msgstr "Gestion des laveries" msgid "Mailing lists" msgstr "Mailing listes" -#: club/templates/club/mailing.jinja:11 +#: club/templates/club/mailing.jinja:10 msgid "" "Remember : mailing lists need to be moderated, if your new created list is " "not shown wait until moderation takes action" @@ -1284,40 +1288,44 @@ msgstr "" "nouvellement créee n'est pas affichée, attendez jusqu'à qu'un modérateur " "entre en action" -#: club/templates/club/mailing.jinja:20 +#: club/templates/club/mailing.jinja:13 +msgid "Mailing lists waiting for moderation" +msgstr "Listes de diffusions en attente de modération" + +#: club/templates/club/mailing.jinja:29 msgid "Generate mailing list" msgstr "Générer la liste de diffusion" -#: club/templates/club/mailing.jinja:33 +#: club/templates/club/mailing.jinja:42 #: com/templates/com/mailing_admin.jinja:10 msgid "Email" msgstr "Email" -#: club/templates/club/mailing.jinja:49 +#: club/templates/club/mailing.jinja:58 msgid "Remove from mailing list" msgstr "Supprimer de la liste de diffusion" -#: club/templates/club/mailing.jinja:53 +#: club/templates/club/mailing.jinja:62 msgid "There is no subscriber for this mailing list" msgstr "Il n'y a pas d'abonnés dans cette liste de diffusion" -#: club/templates/club/mailing.jinja:58 +#: club/templates/club/mailing.jinja:67 msgid "No mailing list existing for this club" msgstr "Aucune mailing liste n'existe pour ce club" -#: club/templates/club/mailing.jinja:63 +#: club/templates/club/mailing.jinja:72 msgid "New member" msgstr "Nouveau membre" -#: club/templates/club/mailing.jinja:83 +#: club/templates/club/mailing.jinja:92 msgid "Add to mailing list" msgstr "Ajouter à la mailing liste" -#: club/templates/club/mailing.jinja:87 +#: club/templates/club/mailing.jinja:96 msgid "New mailing" msgstr "Nouvelle liste de diffusion" -#: club/templates/club/mailing.jinja:100 +#: club/templates/club/mailing.jinja:109 msgid "Create mailing list" msgstr "Créer une liste de diffusion" From 654099067ea579fdc5c1c17397d32fcb6d12e789 Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Thu, 9 May 2019 18:06:11 +0200 Subject: [PATCH 7/8] clubs: tests for adding mailings --- club/forms.py | 2 - club/tests.py | 75 +++++++++++++++++++++++++++- club/views.py | 14 +++++- core/management/commands/populate.py | 33 ++++++++++++ locale/fr/LC_MESSAGES/django.po | 2 +- 5 files changed, 120 insertions(+), 6 deletions(-) diff --git a/club/forms.py b/club/forms.py index 6cf4e405..dca2b05c 100644 --- a/club/forms.py +++ b/club/forms.py @@ -143,8 +143,6 @@ class MailingForm(forms.Form): if cleaned_data["action"] == self.ACTION_NEW_MAILING: self.check_required(cleaned_data, "mailing_email") - # self.check_required(cleaned_data, "mailing_club") - # self.check_required(cleaned_data, "mailing_moderator") if cleaned_data["action"] == self.ACTION_NEW_SUBSCRIPTION: self.check_required(cleaned_data, "subscription_mailing") diff --git a/club/tests.py b/club/tests.py index 25f6e019..82ddf937 100644 --- a/club/tests.py +++ b/club/tests.py @@ -22,12 +22,15 @@ # # +from django.conf import settings from django.test import TestCase +from django.utils import timezone from django.core.urlresolvers import reverse from django.core.management import call_command from core.models import User -from club.models import Club +from club.models import Club, Membership +from club.forms import MailingForm # Create your tests here. @@ -373,3 +376,73 @@ class ClubTest(TestCase): "S' Kia\\n Responsable info" in content ) + + +class MailingFormTest(TestCase): + """Perform validation tests for MailingForm""" + + def setUp(self): + call_command("populate") + self.skia = User.objects.filter(username="skia").first() + self.rbatsbak = User.objects.filter(username="rbatsbak").first() + self.guy = User.objects.filter(username="krophil").first() + self.comunity = User.objects.filter(username="comunity").first() + self.bdf = Club.objects.filter(unix_name="bdf").first() + Membership( + user=self.rbatsbak, + club=self.bdf, + start_date=timezone.now(), + role=settings.SITH_CLUB_ROLES_ID["Board member"], + ).save() + + def test_mailing_list_add_no_moderation(self): + # Test with Communication admin + self.client.login(username="comunity", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "foyer"}, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, text="Liste de diffusion foyer@utbm.fr") + + # Test with Root + self.client.login(username="root", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"}, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, text="Liste de diffusion mde@utbm.fr") + + def test_mailing_list_add_moderation(self): + self.client.login(username="rbatsbak", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"}, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertNotContains(response, text="Liste de diffusion mde@utbm.fr") + self.assertContains( + response, text="

Listes de diffusions en attente de modération

" + ) + self.assertContains(response, "
  • mde@utbm.fr") + + def test_mailing_list_forbidden(self): + # With anonymous user + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, "", status_code=403) + + # With user not in club + self.client.login(username="krophil", password="plop") + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, "", status_code=403) diff --git a/club/views.py b/club/views.py index 31dc0ad0..1d2e145e 100644 --- a/club/views.py +++ b/club/views.py @@ -563,12 +563,18 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): """ Add mailing subscriptions for each user given and/or for the specified email in form """ + users_to_save = [] + for user in cleaned_data["subscription_users"]: sub = MailingSubscription( mailing=cleaned_data["subscription_mailing"], user=user ) - sub.clean() - sub.save() + try: + sub.clean() + except ValidationError as validation_error: + return validation_error + + users_to_save.append(sub.save()) if cleaned_data["subscription_email"]: sub = MailingSubscription( @@ -582,6 +588,10 @@ class ClubMailingView(ClubTabsMixin, CanEditMixin, DetailFormView): return validation_error sub.save() + # Save users after we are sure there is no error + for user in users_to_save: + user.save() + return None def remove_subscription(self, cleaned_data): diff --git a/core/management/commands/populate.py b/core/management/commands/populate.py index cccaf098..02bd3cd3 100644 --- a/core/management/commands/populate.py +++ b/core/management/commands/populate.py @@ -837,6 +837,27 @@ Welcome to the wiki page! krophil_profile.save() krophil.profile_pict = krophil_profile krophil.save() + # Adding user Com Unity + comunity = User( + username="comunity", + last_name="Unity", + first_name="Com", + email="comunity@git.an", + date_of_birth="1942-06-12", + ) + comunity.set_password("plop") + comunity.save() + comunity.groups = [ + Group.objects.filter(name="Communication admin").first().id + ] + comunity.save() + Membership( + user=comunity, + club=bar_club, + start_date=timezone.now(), + role=settings.SITH_CLUB_ROLES_ID["Board member"], + ).save() + # Adding subscription for sli s = Subscription( member=User.objects.filter(pk=sli.pk).first(), @@ -861,6 +882,18 @@ Welcome to the wiki page! start=s.subscription_start, ) s.save() + # Com Unity + s = Subscription( + member=comunity, + subscription_type=default_subscription, + payment_method=settings.SITH_SUBSCRIPTION_PAYMENT_METHOD[0][0], + ) + s.subscription_start = s.compute_start() + s.subscription_end = s.compute_end( + duration=settings.SITH_SUBSCRIPTIONS[s.subscription_type]["duration"], + start=s.subscription_start, + ) + s.save() Selling( label=dcons.name, diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 5b54e273..8eab8c71 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -948,7 +948,7 @@ msgstr "Ce champ est obligatoire." #: club/forms.py:162 msgid "You must specify at least an user or an email address" -msgstr "" +msgstr "vous devez spécifier au moins un utilisateur ou une adresse email" #: club/forms.py:172 counter/views.py:1481 msgid "Begin date" From 81d470b9773796bba8019a1f2cf241c4930ad81a Mon Sep 17 00:00:00 2001 From: Bartuccio Antoine Date: Thu, 9 May 2019 20:32:48 +0200 Subject: [PATCH 8/8] clubs: add tests for MalingForm --- club/tests.py | 251 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 3 deletions(-) diff --git a/club/tests.py b/club/tests.py index 82ddf937..835e7f4c 100644 --- a/club/tests.py +++ b/club/tests.py @@ -24,12 +24,14 @@ from django.conf import settings from django.test import TestCase -from django.utils import timezone +from django.utils import timezone, html +from django.utils.translation import ugettext as _ from django.core.urlresolvers import reverse from django.core.management import call_command +from django.core.exceptions import ValidationError, NON_FIELD_ERRORS from core.models import User -from club.models import Club, Membership +from club.models import Club, Membership, Mailing from club.forms import MailingForm # Create your tests here. @@ -385,7 +387,7 @@ class MailingFormTest(TestCase): call_command("populate") self.skia = User.objects.filter(username="skia").first() self.rbatsbak = User.objects.filter(username="rbatsbak").first() - self.guy = User.objects.filter(username="krophil").first() + self.krophil = User.objects.filter(username="krophil").first() self.comunity = User.objects.filter(username="comunity").first() self.bdf = Club.objects.filter(unix_name="bdf").first() Membership( @@ -446,3 +448,246 @@ class MailingFormTest(TestCase): reverse("club:mailing", kwargs={"club_id": self.bdf.id}) ) self.assertContains(response, "", status_code=403) + + def test_add_new_subscription_fail_not_moderated(self): + self.client.login(username="rbatsbak", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"}, + ) + + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": self.skia.id, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertNotContains(response, "skia@git.an") + + def test_add_new_subscription_success(self): + # Prepare mailing list + self.client.login(username="comunity", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"}, + ) + + # Add single user + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": self.skia.id, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, "skia@git.an") + + # Add multiple users + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": "|%s|%s|" % (self.comunity.id, self.rbatsbak.id), + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, "richard@git.an") + self.assertContains(response, "comunity@git.an") + self.assertContains(response, "skia@git.an") + + # Add arbitrary email + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_email": "arbitrary@git.an", + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, "richard@git.an") + self.assertContains(response, "comunity@git.an") + self.assertContains(response, "skia@git.an") + self.assertContains(response, "arbitrary@git.an") + + # Add user and arbitrary email + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_email": "more.arbitrary@git.an", + "subscription_users": self.krophil.id, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + self.assertContains(response, "richard@git.an") + self.assertContains(response, "comunity@git.an") + self.assertContains(response, "skia@git.an") + self.assertContains(response, "arbitrary@git.an") + self.assertContains(response, "more.arbitrary@git.an") + self.assertContains(response, "krophil@git.an") + + def test_add_new_subscription_fail_form_errors(self): + # Prepare mailing list + self.client.login(username="comunity", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"}, + ) + + # Neither email or email is specified + response = self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + self.assertContains( + response, text=_("You must specify at least an user or an email address") + ) + + # No mailing specified + response = self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": self.krophil.id, + }, + ) + self.assertContains(response, text=_("This field is required")) + + # One of the selected users doesn't exist + response = self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": "|789|", + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + self.assertContains( + response, text=html.escape(_("One of the selected users doesn't exist")) + ) + + # An user has no email adress + self.krophil.email = "" + self.krophil.save() + + response = self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": self.krophil.id, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + self.assertContains( + response, + text=html.escape( + _("One of the selected users doesn't have an email address") + ), + ) + + self.krophil.email = "krophil@git.an" + self.krophil.save() + + # An user is added twice + + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": self.krophil.id, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + + response = self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": self.krophil.id, + "subscription_mailing": Mailing.objects.get(email="mde").id, + }, + ) + self.assertContains( + response, + text=html.escape(_("This email is already suscribed in this mailing")), + ) + + def test_remove_subscription_success(self): + # Prepare mailing list + self.client.login(username="comunity", password="plop") + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + {"action": MailingForm.ACTION_NEW_MAILING, "mailing_email": "mde"}, + ) + mde = Mailing.objects.get(email="mde") + response = self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_NEW_SUBSCRIPTION, + "subscription_users": "|%s|%s|%s|" + % (self.comunity.id, self.rbatsbak.id, self.krophil.id), + "subscription_mailing": mde.id, + }, + ) + self.assertContains(response, "comunity@git.an") + self.assertContains(response, "richard@git.an") + self.assertContains(response, "krophil@git.an") + + # Delete one user + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_REMOVE_SUBSCRIPTION, + "removal_%d" % mde.id: mde.subscriptions.get(user=self.krophil).id, + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + + self.assertContains(response, "comunity@git.an") + self.assertContains(response, "richard@git.an") + self.assertNotContains(response, "krophil@git.an") + + # Delete multiple users + self.client.post( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}), + { + "action": MailingForm.ACTION_REMOVE_SUBSCRIPTION, + "removal_%d" + % mde.id: [ + user.id + for user in mde.subscriptions.filter( + user__in=[self.rbatsbak, self.comunity] + ).all() + ], + }, + ) + response = self.client.get( + reverse("club:mailing", kwargs={"club_id": self.bdf.id}) + ) + + self.assertNotContains(response, "comunity@git.an") + self.assertNotContains(response, "richard@git.an") + self.assertNotContains(response, "krophil@git.an")