# # 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 import forms from django.conf import settings from django.utils.translation import gettext_lazy as _ from club.models import Club, Mailing, MailingSubscription, Membership from core.models import User from core.views.forms import SelectDate, SelectDateTime from core.views.widgets.select import AutoCompleteSelectMultipleUser from counter.models import Counter class ClubEditForm(forms.ModelForm): class Meta: model = Club fields = ["address", "logo", "short_description"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["short_description"].widget = forms.Textarea() class MailingForm(forms.Form): """Form handling mailing lists right.""" ACTION_NEW_MAILING = 1 ACTION_NEW_SUBSCRIPTION = 2 ACTION_REMOVE_SUBSCRIPTION = 3 subscription_users = forms.ModelMultipleChoiceField( label=_("Users to add"), help_text=_("Search users to add (one or more)."), required=False, widget=AutoCompleteSelectMultipleUser, queryset=User.objects.all(), ) def __init__(self, club_id, user_id, mailings, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["action"] = forms.TypedChoiceField( choices=( (self.ACTION_NEW_MAILING, _("New Mailing")), (self.ACTION_NEW_SUBSCRIPTION, _("Subscribe")), (self.ACTION_REMOVE_SUBSCRIPTION, _("Remove")), ), coerce=int, label=_("Action"), initial=1, required=True, 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",) 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 self.fields["subscription_mailing"].queryset = Mailing.objects.filter( club__id=club_id, is_moderated=True ) 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().clean() users = [] for user in cleaned_data["subscription_users"]: 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().clean() if "action" not 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") 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 SellingsForm(forms.Form): begin_date = forms.DateTimeField( label=_("Begin date"), widget=SelectDateTime, required=False ) end_date = forms.DateTimeField( label=_("End date"), widget=SelectDateTime, required=False ) counters = forms.ModelMultipleChoiceField( Counter.objects.order_by("name").all(), label=_("Counter"), required=False ) def __init__(self, club, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["products"] = forms.ModelMultipleChoiceField( club.products.order_by("name").filter(archived=False).all(), label=_("Products"), required=False, ) self.fields["archived_products"] = forms.ModelMultipleChoiceField( club.products.order_by("name").filter(archived=True).all(), label=_("Archived products"), required=False, ) class ClubMemberForm(forms.Form): """Form handling the members of a club.""" error_css_class = "error" required_css_class = "required" users = forms.ModelMultipleChoiceField( label=_("Users to add"), help_text=_("Search users to add (one or more)."), required=False, widget=AutoCompleteSelectMultipleUser, queryset=User.objects.all(), ) 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().__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) ] ).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().clean() users = [] for user in cleaned_data["users"]: 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().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