def post(self, request, list_id): """ Subscribes an email address to a mailing list via POST and redirects to the `list_summary` view. """ try: user_addresses = [request.user.email] + request.user.other_emails form = ListSubscribe(user_addresses, request.POST) if form.is_valid(): email = request.POST.get('email') response = self.mailing_list.subscribe( email, pre_verified=True, pre_confirmed=True) if (type(response) == dict and response.get('token_owner') == 'moderator'): messages.success( request, _('Your subscription request has been' ' submitted and is waiting for moderator' ' approval.')) else: messages.success(request, _('You are subscribed to %s.') % self.mailing_list.fqdn_listname) else: messages.error(request, _('Something went wrong. Please try again.')) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e.msg) return redirect('list_summary', self.mailing_list.list_id)
def handle_subscription_request(request, list_id, request_id, action): """ Handle a subscription request. Possible actions: - accept - defer - reject - discard """ confirmation_messages = { 'accept': _('The request has been accepted.'), 'reject': _('The request has been rejected.'), 'discard': _('The request has been discarded.'), 'defer': _('The request has been defered.'), } try: m_list = List.objects.get_or_404(fqdn_listname=list_id) # Moderate request and add feedback message to session. m_list.moderate_request(request_id, action) messages.success(request, confirmation_messages[action]) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: if e.code == 409: messages.success(request, _('The request was already moderated: %s') % e.reason) else: messages.error(request, _('The request could not be moderated: %s') % e.reason) return redirect('list_subscription_requests', m_list.list_id)
def list_mass_subscribe(request, list_id): mailing_list = List.objects.get_or_404(fqdn_listname=list_id) if request.method == 'POST': form = ListMassSubscription(request.POST) if form.is_valid(): for data in form.cleaned_data['emails']: try: # Parse the data to get the address and the display name display_name, address = email.utils.parseaddr(data) validate_email(address) mailing_list.subscribe(address=address, display_name=display_name, pre_verified=True, pre_confirmed=True, pre_approved=True) messages.success( request, _('The address %(address)s has been' ' subscribed to %(list)s.') % {'address': address, 'list': mailing_list.fqdn_listname}) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e) except ValidationError: messages.error(request, _('The email address %s' ' is not valid.') % address) else: form = ListMassSubscription() return render(request, 'postorius/lists/mass_subscribe.html', {'form': form, 'list': mailing_list})
def post(self, request, list_id): """ Subscribes an email address to a mailing list via POST and redirects to the `list_summary` view. """ try: user_emails = EmailAddress.objects.filter( user=request.user, verified=True).order_by( "email").values_list("email", flat=True) form = ListSubscribe(user_emails, request.POST) if form.is_valid(): email = request.POST.get('email') response = self.mailing_list.subscribe( email, pre_verified=True, pre_confirmed=True) if (type(response) == dict and response.get('token_owner') == 'moderator'): messages.success( request, _('Your subscription request has been' ' submitted and is waiting for moderator' ' approval.')) else: messages.success(request, _('You are subscribed to %s.') % self.mailing_list.fqdn_listname) else: messages.error(request, _('Something went wrong. Please try again.')) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e.msg) return redirect('list_summary', self.mailing_list.list_id)
def list_moderation(request, list_id, held_id=-1): mailing_list = List.objects.get_or_404(fqdn_listname=list_id) if request.method == 'POST': form = MultipleChoiceForm(request.POST) if form.is_valid(): message_ids = form.cleaned_data['choices'] try: if 'accept' in request.POST: _perform_action(message_ids, mailing_list.accept_message) messages.success(request, _('The selected messages were accepted')) elif 'reject' in request.POST: _perform_action(message_ids, mailing_list.reject_message) messages.success(request, _('The selected messages were rejected')) elif 'discard' in request.POST: _perform_action(message_ids, mailing_list.discard_message) messages.success(request, _('The selected messages were discarded')) except MailmanApiError: return utils.render_api_error(request) except HTTPError: messages.error(request, _('Message could not be found')) else: form = MultipleChoiceForm() held_messages = paginate( mailing_list.get_held_page, request.GET.get('page'), request.GET.get('count'), paginator_class=MailmanPaginator) context = { 'list': mailing_list, 'held_messages': held_messages, 'form': form, } return render(request, 'postorius/lists/held_messages.html', context)
def list_mass_subscribe(request, list_id): mailing_list = utils.get_client().get_list(list_id) if request.method == 'POST': form = ListMassSubscription(request.POST) if form.is_valid(): for data in form.cleaned_data['emails']: try: # Parse the data to get the address and the display name display_name, address = email.utils.parseaddr(data) validate_email(address) mailing_list.subscribe(address=address, display_name=display_name, pre_verified=True, pre_confirmed=True, pre_approved=True) messages.success( request, _('The address %(address)s has been' ' subscribed to %(list)s.') % {'address': address, 'list': mailing_list.fqdn_listname}) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e) except ValidationError: messages.error(request, _('The email address %s' ' is not valid.') % address) else: form = ListMassSubscription() return render(request, 'postorius/lists/mass_subscribe.html', {'form': form, 'list': mailing_list})
def list_index(request, template='postorius/index.html'): """Show a table of all public mailing lists. """ if request.method == 'POST': return redirect("list_summary", list_id=request.POST["list"]) lists = [] error = None only_public = True if request.user.is_superuser: only_public = False try: # FIXME: this is not paginated, all lists will # always be retrieved. lists = sorted(List.objects.all(only_public=only_public), key=lambda l: l.fqdn_listname) logger.debug(lists) except MailmanApiError: return utils.render_api_error(request) choosable_domains = _get_choosable_domains(request) return render(request, template, {'error': error, 'lists': paginate( lists, request.GET.get('page'), request.GET.get('count', 10)), 'domain_count': len(choosable_domains)})
def post(self, request, list_id): try: user_emails = [request.user.email] + request.user.other_emails form = ListSubscribe(user_emails, request.POST) # Find the currently subscribed email old_email = None for address in user_emails: try: self.mailing_list.get_member(address) except ValueError: pass else: old_email = address break # no need to test more addresses assert old_email is not None if form.is_valid(): email = form.cleaned_data['email'] if old_email == email: messages.error(request, _('You are already subscribed')) else: self.mailing_list.unsubscribe(old_email) # Since the action is done via the web UI, no email # confirmation is needed. self.mailing_list.subscribe(email, pre_confirmed=True) messages.success(request, _('Subscription changed to %s') % email) else: messages.error(request, _('Something went wrong. Please try again.')) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, e.msg) return redirect('list_summary', self.mailing_list.list_id)
def remove_role(request, list_id=None, role=None, address=None, template='postorius/lists/confirm_remove_role.html'): """Removes a list moderator or owner.""" try: the_list = List.objects.get_or_404(fqdn_listname=list_id) except MailmanApiError: return utils.render_api_error(request) redirect_on_success = redirect('list_members', the_list.list_id, role) roster = getattr(the_list, '{}s'.format(role)) if address not in roster: messages.error(request, _('The user %(email)s is not in the %(role)s group') % {'email': address, 'role': role}) return redirect('list_members', the_list.list_id, role) if role == 'owner': if len(roster) == 1: messages.error(request, _('Removing the last owner is impossible')) return redirect('list_members', the_list.list_id, role) # the user may not have a other_emails property if it's a superuser user_addresses = set([request.user.email]) | \ set(getattr(request.user, 'other_emails', [])) if address in user_addresses: # The user is removing themselves, redirect to the list info page # because they won't have access to the members page anyway. redirect_on_success = redirect('list_summary', the_list.list_id) if request.method == 'POST': try: the_list.remove_role(role, address) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, _('The user could not be removed: %(msg)s') % {'msg': e.msg}) return redirect('list_members', the_list.list_id, role) messages.success(request, _('The user %(address)s has been removed' ' from the %(role)s group.') % {'address': address, 'role': role}) return redirect_on_success return render(request, template, {'role': role, 'address': address, 'list_id': the_list.list_id})
def remove_role(request, list_id=None, role=None, address=None, template='postorius/lists/confirm_remove_role.html'): """Removes a list moderator or owner.""" try: the_list = List.objects.get_or_404(fqdn_listname=list_id) except MailmanApiError: return utils.render_api_error(request) redirect_on_success = redirect('list_members', the_list.list_id, role) roster = getattr(the_list, '{}s'.format(role)) if address not in roster: messages.error(request, _('The user %(email)s is not in the %(role)s group') % {'email': address, 'role': role}) return redirect('list_members', the_list.list_id, role) if role == 'owner': if len(roster) == 1: messages.error(request, _('Removing the last owner is impossible')) return redirect('list_members', the_list.list_id, role) user_emails = EmailAddress.objects.filter( user=request.user, verified=True).order_by( "email").values_list("email", flat=True) if address in user_emails: # The user is removing themselves, redirect to the list info page # because they won't have access to the members page anyway. redirect_on_success = redirect('list_summary', the_list.list_id) if request.method == 'POST': try: the_list.remove_role(role, address) except MailmanApiError: return utils.render_api_error(request) except HTTPError as e: messages.error(request, _('The user could not be removed: %(msg)s') % {'msg': e.msg}) return redirect('list_members', the_list.list_id, role) messages.success(request, _('The user %(address)s has been removed' ' from the %(role)s group.') % {'address': address, 'role': role}) return redirect_on_success return render(request, template, {'role': role, 'address': address, 'list_id': the_list.list_id})
def list_subscription_requests(request, list_id): """Shows a list of held messages. """ try: m_list = List.objects.get_or_404(fqdn_listname=list_id) except MailmanApiError: return utils.render_api_error(request) return render(request, 'postorius/lists/subscription_requests.html', {'list': m_list})
def post(self, request, *args, **kwargs): email = request.POST['email'] try: self.mailing_list.unsubscribe(email) messages.success(request, _('%s has been unsubscribed' ' from this list.') % email) except MailmanApiError: return utils.render_api_error(request) except ValueError as e: messages.error(request, e) return redirect('list_summary', self.mailing_list.list_id)
def list_settings(request, list_id=None, visible_section=None, template='postorius/lists/settings.html'): """ View and edit the settings of a list. The function requires the user to be logged in and have the permissions necessary to perform the action. Use /<NAMEOFTHESECTION>/<NAMEOFTHEOPTION> to show only parts of the settings <param> is optional / is used to differ in between section and option might result in using //option """ if visible_section is None: visible_section = 'list_identity' try: form_class = SETTINGS_FORMS[visible_section] except KeyError: raise Http404('No such settings section') try: m_list = List.objects.get_or_404(fqdn_listname=list_id) list_settings = m_list.settings except (MailmanApiError, HTTPError): return utils.render_api_error(request) # List settings are grouped an processed in different forms. if request.method == 'POST': initial_data = dict( (key, unicode(value)) for key, value in list_settings.items()) form = form_class(request.POST, mlist=m_list, initial=initial_data) if form.is_valid(): try: for key in form.changed_data: if key in form_class.mlist_properties: setattr(m_list, key, form.cleaned_data[key]) else: list_settings[key] = form.cleaned_data[key] list_settings.save() messages.success(request, _('The settings have been updated.')) except HTTPError as e: messages.error(request, _('An error occured: %s') % e.reason) return redirect('list_settings', m_list.list_id, visible_section) else: form = form_class(initial=dict(list_settings), mlist=m_list) return render(request, template, { 'form': form, 'section_names': SETTINGS_SECTION_NAMES, 'list': m_list, 'visible_section': visible_section, })
def list_settings(request, list_id=None, visible_section=None, template='postorius/lists/settings.html'): """ View and edit the settings of a list. The function requires the user to be logged in and have the permissions necessary to perform the action. Use /<NAMEOFTHESECTION>/<NAMEOFTHEOPTION> to show only parts of the settings <param> is optional / is used to differ in between section and option might result in using //option """ if visible_section is None: visible_section = 'list_identity' try: form_class = SETTINGS_FORMS[visible_section] except KeyError: raise Http404('No such settings section') try: m_list = List.objects.get_or_404(fqdn_listname=list_id) list_settings = m_list.settings except (MailmanApiError, HTTPError): return utils.render_api_error(request) # List settings are grouped an processed in different forms. if request.method == 'POST': form = form_class(request.POST, mlist=m_list) if form.is_valid(): try: for key in form.fields.keys(): if key in form_class.mlist_properties: setattr(m_list, key, form.cleaned_data[key]) else: list_settings[key] = form.cleaned_data[key] list_settings.save() messages.success(request, _('The settings have been updated.')) except HTTPError as e: messages.error(request, _('An error occured: %s') % e.reason) return redirect('list_settings', m_list.list_id, visible_section) else: form = form_class(initial=dict(list_settings), mlist=m_list) return render(request, template, { 'form': form, 'section_names': SETTINGS_SECTION_NAMES, 'list': m_list, 'visible_section': visible_section, })
def list_delete(request, list_id): """Deletes a list but asks for confirmation first. """ try: the_list = List.objects.get_or_404(fqdn_listname=list_id) except MailmanApiError: return utils.render_api_error(request) if request.method == 'POST': the_list.delete() return redirect("list_index") else: submit_url = reverse('list_delete', kwargs={'list_id': list_id}) cancel_url = reverse('list_index',) return render(request, 'postorius/lists/confirm_delete.html', {'submit_url': submit_url, 'cancel_url': cancel_url, 'list': the_list})
def csv_view(request, list_id): """Export all the subscriber in csv """ mm_lists = [] try: mm_lists = List.objects.get_or_404(fqdn_listname=list_id) except MailmanApiError: return utils.render_api_error(request) response = HttpResponse(content_type='text/csv') response['Content-Disposition'] = ( 'attachment; filename="Subscribers.csv"') writer = csv.writer(response) if mm_lists: for i in mm_lists.members: writer.writerow([i.email]) return response
def moderate_held_message(request, list_id): if request.method != 'POST': return HttpResponseNotAllowed(['POST']) msg_id = request.POST['msgid'] try: mailing_list = List.objects.get_or_404(fqdn_listname=list_id) if 'accept' in request.POST: mailing_list.accept_message(msg_id) messages.success(request, _('The message was accepted')) elif 'reject' in request.POST: mailing_list.reject_message(msg_id) messages.success(request, _('The message was rejected')) elif 'discard' in request.POST: mailing_list.discard_message(msg_id) messages.success(request, _('The message was discarded')) except MailmanApiError: return utils.render_api_error(request) return redirect('list_held_messages', list_id)
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: for address in form.cleaned_data['emails']: try: validate_email(address) self.mailing_list.unsubscribe(address.lower()) messages.success( request, _('The address %(address)s has been' ' unsubscribed from %(list)s.') % {'address': address, 'list': self.mailing_list.fqdn_listname}) except MailmanApiError: return utils.render_api_error(request) except (HTTPError, ValueError) as e: messages.error(request, e) except ValidationError: messages.error(request, _('The email address %s' ' is not valid.') % address) return redirect('mass_removal', self.mailing_list.list_id)
def list_index(request, template='postorius/index.html'): """Show a table of all public mailing lists. """ if request.method == 'POST': return redirect("list_summary", list_id=request.POST["list"]) lists = [] error = None only_public = True if request.user.is_superuser: only_public = False try: lists = sorted(List.objects.all(only_public=only_public), key=lambda l: l.fqdn_listname) logger.debug(lists) except MailmanApiError: return utils.render_api_error(request) choosable_domains = _get_choosable_domains(request) return render(request, template, {'count_options': [10, 25, 50, 100, 200], 'error': error, 'lists': utils.paginate(request, lists, count=request.GET.get('count', 10)), 'domain_count': len(choosable_domains)})
def list_moderation(request, list_id, held_id=-1): mailing_list = utils.get_client().get_list(list_id) if request.method == 'POST': form = MultipleChoiceForm(request.POST) if form.is_valid(): message_ids = form.cleaned_data['choices'] try: if 'accept' in request.POST: _perform_action(message_ids, mailing_list.accept_message) messages.success(request, _('The selected messages were accepted')) elif 'reject' in request.POST: _perform_action(message_ids, mailing_list.reject_message) messages.success(request, _('The selected messages were rejected')) elif 'discard' in request.POST: _perform_action(message_ids, mailing_list.discard_message) messages.success(request, _('The selected messages were discarded')) except MailmanApiError: return utils.render_api_error(request) except HTTPError: messages.error(request, _('Message could not be found')) else: form = MultipleChoiceForm() held_messages = utils.paginate( request, mailing_list.get_held_page, count=request.GET.get('count', 20), paginator_class=utils.MailmanPaginator) context = { 'list': mailing_list, 'count_options': [25, 50, 100, 200], 'held_messages': held_messages, 'form': form, } return render(request, 'postorius/lists/held_messages.html', context)
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 as e: messages.error(request, e) return render(request, 'postorius/lists/confirm_removeall_subscribers.html', {'list': mlist}) except MailmanApiError: return utils.render_api_error(request)
def _get_choosable_domains(request): try: domains = Domain.objects.all() except MailmanApiError: return utils.render_api_error(request) return [(d.mail_host, d.mail_host) for d in domains]