clubs: add bulk deletion on mailing lists

This commit is contained in:
2019-05-01 22:52:22 +02:00
parent 24fb714c5e
commit 1d07195881
6 changed files with 209 additions and 144 deletions

View File

@ -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")

View File

@ -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)

View File

@ -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 @@
<b>{% trans %}Remember : mailing lists need to be moderated, if your new created list is not shown wait until moderation takes action{% endtrans %}</b>
{% for mailing in mailings %}
{% if mailing.is_moderated %}
<h2>{% trans %}Mailing{% endtrans %} {{ mailing.email_full }}
<h2>{% trans %}Mailing{% endtrans %} {{ mailing.email_full }}
{%- if user.is_owner(mailing) -%}
<a href="{{ url('club:mailing_delete', mailing_id=mailing.id) }}"> - {% trans %}Delete{% endtrans %}</a>
{%- endif -%}
@ -19,27 +19,38 @@
<form method="GET" action="{{ url('club:mailing_generate', mailing_id=mailing.id) }}" style="display:inline-block;">
<input type="submit" name="generateMalingList" value="{% trans %}Generate mailing list{% endtrans %}">
</form>
<form method="GET" action="{{ url('club:mailing_clean', mailing_id=mailing.id) }}" style="display:inline-block;">
<input type="submit" name="cleanMailingList" value="{% trans %}Clean mailing list{% endtrans %}">
{% set form_mailing_removal = form["removal_" + mailing.id|string] %}
{% if form_mailing_removal.field.choices %}
{% set ms = dict(mailing.subscriptions.all() | groupby('id')) %}
<form action="{{ url('club:mailing', club_id=club.id) }}" id="{{ form_mailing_removal.auto_id }}" method="post" enctype="multipart/form-data">
<p style="margin-bottom: 1em;">{{ select_all_checkbox(form_mailing_removal.auto_id) }}</p>
{% csrf_token %}
<input hidden type="number" name="{{ form.action.name }}" value="{{ form_actions.REMOVE_SUBSCRIPTION }}" />
<table>
<thead>
<tr>
<td>{% trans %}User{% endtrans %}</td>
<td>{% trans %}Email{% endtrans %}</td>
<td>{% trans %}Delete{% endtrans %}</td>
</tr>
</thead>
<tbody>
{% for widget in form_mailing_removal.subwidgets %}
{% set user = ms[widget.data.value][0] %}
<tr>
<td>{{ user.get_username }}</td>
<td>{{ user.get_email }}</td>
<td>{{ widget.tag() }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{{ form_mailing_removal.errors }}
<p><input type="submit" value="{% trans %}Remove from mailing list{% endtrans %}" /></p>
</form>
<hr>
<table>
<tr>
<th>{% trans %}User{% endtrans %}</th>
<th colspan="2">{% trans %}Email{%endtrans%}</th>
</tr>
{% for subscriber in mailing.subscriptions.all() %}
<tr>
{% if subscriber.user %}
<td>{{ subscriber.user }}</td>
{% else %}
<td>{% trans %}Unregistered user{% endtrans %}</td>
{% endif %}
<td>{{ subscriber.get_email }}</td>
<td><a href="{{ url('club:mailing_subscription_delete', mailing_subscription_id=subscriber.id) }}">{% trans %}Delete{% endtrans %}</a></td>
</tr>
{% endfor %}
</table>
{% else %}
<p><b>{% trans %}There is no subscriber for this mailing list{% endtrans %}</b></p>
{% endif %}
{% endfor %}

View File

@ -70,11 +70,6 @@ urlpatterns = [
MailingAutoGenerationView.as_view(),
name="mailing_generate",
),
url(
r"^(?P<mailing_id>[0-9]+)/mailing/clean$",
MailingAutoCleanView.as_view(),
name="mailing_clean",
),
url(
r"^(?P<mailing_id>[0-9]+)/mailing/delete$",
MailingDeleteView.as_view(),

View File

@ -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"""