diff --git a/src/postorius/forms.py b/src/postorius/forms.py index 5d6e7d0..0fde621 100644 --- a/src/postorius/forms.py +++ b/src/postorius/forms.py @@ -736,6 +736,24 @@ layout = [["Mass subscription", "emails"]] +class ListMassRemoval(FieldsetForm): + + """Form fields to remove multiple list users. + """ + emails = forms.CharField( + label=_('Emails to Unsubscribe'), + widget=forms.Textarea, + ) + + class Meta: + + """ + Class to define the name of the fieldsets and what should be + included in each. + """ + layout = [["Mass Removal", "emails"]] + + class UserPreferences(FieldsetForm): """ diff --git a/src/postorius/static/postorius/js/script.js b/src/postorius/static/postorius/js/script.js index 9651f3a..fbd37a8 100755 --- a/src/postorius/static/postorius/js/script.js +++ b/src/postorius/static/postorius/js/script.js @@ -1,5 +1,4 @@ $(document).ready(function(){ $('.collapse').collapse({ - toggle: false, - }); +toggle: false, }); diff --git a/src/postorius/templates/postorius/base.html b/src/postorius/templates/postorius/base.html index 4c0c435..3dc4283 100644 --- a/src/postorius/templates/postorius/base.html +++ b/src/postorius/templates/postorius/base.html @@ -10,11 +10,9 @@ - - @@ -67,7 +65,6 @@ - - + {% block additionaljs %}{% endblock %} diff --git a/src/postorius/templates/postorius/lists/confirm_removeall_subscribers.html b/src/postorius/templates/postorius/lists/confirm_removeall_subscribers.html new file mode 100644 index 0000000..398388c --- /dev/null +++ b/src/postorius/templates/postorius/lists/confirm_removeall_subscribers.html @@ -0,0 +1,14 @@ +{% extends "postorius/base.html" %} +{% load url from future %} +{% load i18n %} +{% load nav_helpers %} + +{% block main %} +

{% trans 'Confirm Removal of All Members' %}

+

{% trans "Are you sure you want to unsubscribe all members from " %}{{list_id}}{% trans " ?"%}

+
+
+ {% csrf_token %} + + {% trans "Cancel" %} +{% endblock main %} diff --git a/src/postorius/templates/postorius/lists/mass_removal.html b/src/postorius/templates/postorius/lists/mass_removal.html new file mode 100644 index 0000000..8ba5427 --- /dev/null +++ b/src/postorius/templates/postorius/lists/mass_removal.html @@ -0,0 +1,17 @@ +{% extends postorius_base_template %} +{% load url from future %} +{% load i18n %} +{% load nav_helpers %} + +{% block main %} + {% list_nav 'mass_removal' "Mass Removal" %} + + {% csrf_token %} + {{ form.as_p }} +
+ + {% trans 'Unsubscribe All' %} +
+
+ +{% endblock main %} diff --git a/src/postorius/templates/postorius/lists/members.html b/src/postorius/templates/postorius/lists/members.html index f14151e..f532595 100644 --- a/src/postorius/templates/postorius/lists/members.html +++ b/src/postorius/templates/postorius/lists/members.html @@ -10,7 +10,6 @@ {% block main %} {% list_nav 'list_members' "List Members" %} -

{% trans "Owners" %}

{{ owner_form.email.errors }} @@ -66,7 +65,6 @@

{% trans "Members" %}

- diff --git a/src/postorius/templates/postorius/menu/list_nav.html b/src/postorius/templates/postorius/menu/list_nav.html index 4311652..15960e4 100644 --- a/src/postorius/templates/postorius/menu/list_nav.html +++ b/src/postorius/templates/postorius/menu/list_nav.html @@ -18,6 +18,9 @@ {% if user.is_superuser or user.is_list_owner %}
  • {% trans "Mass Subscribe" %}
  • {% endif %} + {% if user.is_superuser or user.is_list_moderator %} +
  • {% trans "Mass Removal" %}
  • + {% endif %} {% if user.is_superuser or user.is_list_owner %}
  • {% trans "Archivers" %}
  • {% endif %} diff --git a/src/postorius/urls.py b/src/postorius/urls.py index 2dfde4d..65459c9 100644 --- a/src/postorius/urls.py +++ b/src/postorius/urls.py @@ -53,6 +53,9 @@ url(r'^mass_subscribe/$', ListMassSubscribeView.as_view( ), name='mass_subscribe'), + url(r'^mass_removal/$', + ListMassRemovalView.as_view( + ), name='mass_removal'), url(r'^delete$', 'list_delete', name='list_delete'), url(r'^held_messages/(?P[^/]+)/' @@ -77,6 +80,8 @@ '(?:/(?P.*))?$', 'list_settings', name='list_settings'), + url(r'^unsubscribe_all$', + 'remove_all_subscribers', name='unsubscribe_all'), url(r'^archival_options$', 'list_archival_options', name='list_archival_options'), diff --git a/src/postorius/views/list.py b/src/postorius/views/list.py index 482dbce..dfaf0a9 100644 --- a/src/postorius/views/list.py +++ b/src/postorius/views/list.py @@ -266,6 +266,43 @@ return redirect('mass_subscribe', self.mailing_list.list_id) +class ListMassRemovalView(MailingListView): + + """Class For Mass Removal""" + + @method_decorator(list_owner_required) + def get(self, request, *args, **kwargs): + form = ListMassRemoval() + return render_to_response('postorius/lists/mass_removal.html', + {'form': form, 'list': self.mailing_list}, + context_instance=RequestContext(request)) + + def post(self, request, *args, **kwargs): + form = ListMassRemoval(request.POST) + if not form.is_valid(): + messages.error(request, 'Please fill out the form correctly.') + else: + emails = request.POST["emails"].splitlines() + for email in emails: + try: + validate_email(email) + self.mailing_list.unsubscribe(email.lower()) + messages.success(request, + 'The address %s has been unsubscribed from %s.' % + (email, self.mailing_list.fqdn_listname)) + except MailmanApiError: + return utils.render_api_error(request) + except HTTPError, e: + messages.error(request, e) + except ValueError, e: + messages.error(request, e) + except ValidationError: + messages.error(request, + 'The email address %s is not valid.' % + email) + return redirect('mass_removal', self.mailing_list.list_id) + + def _get_choosable_domains(request): try: domains = Domain.objects.all() @@ -696,6 +733,32 @@ @list_owner_required +def remove_all_subscribers(request, list_id): + + """Empty the list by unsubscribing all members.""" + + try: + mlist = List.objects.get_or_404(fqdn_listname=list_id) + if len(mlist.members) == 0: + messages.error(request, 'No member is subscribed to the list currently.') + return redirect('mass_removal', mlist.list_id) + if request.method == 'POST': + try: + for names in mlist.members: + mlist.unsubscribe(names.email) + messages.success(request, + 'All members have been unsubscribed from the list.') + return redirect('list_members', mlist.list_id) + except Exception, e: + messages.error(request, e) + return render_to_response('postorius/lists/confirm_removeall_subscribers.html', + {'list_id': mlist.list_id}, + context_instance=RequestContext(request)) + except MailmanApiError: + return utils.render_api_error(request) + + +@list_owner_required def list_archival_options(request, list_id): """ Activate or deactivate list archivers.