diff --git a/example_project/settings.py b/example_project/settings.py
index 99aacd1..1146d54 100644
--- a/example_project/settings.py
+++ b/example_project/settings.py
@@ -63,6 +63,7 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'postorius',
+ 'django_mailman3',
'django_browserid',
)
@@ -199,22 +200,27 @@
# EMAIL_CONFIRMATION_SUBJECT = 'Confirmation needed'
# You can enable logging by uncommenting the following lines
-# LOGGING = {
-# 'version': 1,
-# 'disable_existing_loggers': False,
-# 'handlers': {
-# 'console': {
-# 'class': 'logging.StreamHandler'
-# },
-# },
-# 'loggers': {
-# 'django': {
-# 'handlers': ['console'],
-# 'level': 'INFO',
-# },
-# 'django_browserid': {
-# 'handlers': ['console'],
-# 'level': 'DEBUG',
-# },
-# },
-# }
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'handlers': {
+ 'console': {
+ # 'class': 'logging.StreamHandler'
+ 'class': 'logging.NullHandler'
+ },
+ },
+ 'loggers': {
+ 'django': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'postorius': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'django_browserid': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ },
+}
diff --git a/setup.py b/setup.py
index 2bb5baf..81c41ef 100644
--- a/setup.py
+++ b/setup.py
@@ -36,6 +36,7 @@
install_requires=[
'Django>=1.8',
'Django<1.10',
+ 'django-mailman3',
'django-browserid',
'mailmanclient',
],
diff --git a/src/postorius/lib/scrub.py b/src/postorius/lib/scrub.py
deleted file mode 100644
index 86952a6..0000000
--- a/src/postorius/lib/scrub.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# Copyright (C) 2011-2012 by the Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# 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 Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-"""Cleanse a message for archiving."""
-
-from __future__ import absolute_import, unicode_literals
-
-import os
-import re
-import binascii
-from mimetypes import guess_all_extensions
-from email.header import decode_header, make_header
-from email.errors import HeaderParseError
-
-pre = re.compile(r'[/\\:]')
-sre = re.compile(r'[^-\w.]')
-dre = re.compile(r'^\.*')
-
-BR = '
\n'
-
-NEXT_PART = re.compile(r'--------------[ ]next[ ]part[ ]--------------\n')
-
-
-def guess_extension(ctype, ext):
- all_exts = guess_all_extensions(ctype, strict=False)
- if ext in all_exts:
- return ext
- return all_exts and all_exts[0]
-
-
-def get_charset(message, default="ascii", guess=False):
- if message.get_content_charset():
- return message.get_content_charset().decode("ascii")
- if message.get_charset():
- return message.get_charset().decode("ascii")
- charset = default
- if not guess:
- return charset
- text = message.get_payload(decode=True)
- for encoding in ["ascii", "utf-8", "iso-8859-15"]:
- try:
- text.decode(encoding)
- except UnicodeDecodeError:
- continue
- else:
- charset = encoding
- break
- return charset
-
-
-def oneline(s):
- """Inspired by mailman.utilities.string.oneline"""
- try:
- h = make_header(decode_header(s))
- ustr = h.__unicode__()
- return ''.join(ustr.splitlines())
- except (LookupError, UnicodeError, ValueError, HeaderParseError):
- return ''.join(s.splitlines())
-
-
-class Scrubber(object):
- def __init__(self, msg):
- self.msg = msg
-
- def scrub(self):
- attachments = []
- for part_num, part in enumerate(self.msg.walk()):
- ctype = part.get_content_type()
- if not isinstance(ctype, unicode):
- ctype = ctype.decode("ascii")
- if ctype == 'text/plain':
- disposition = part.get('content-disposition')
- if disposition and disposition.decode(
- "ascii", "replace").strip().startswith("attachment"):
- attachments.append(self.parse_attachment(part, part_num))
- part.set_payload('')
- elif ctype == 'text/html':
- attachments.append(self.parse_attachment(part, part_num,
- filter_html=False))
- part.set_payload('')
- elif ctype == 'message/rfc822':
- attachments.append(self.parse_attachment(part, part_num))
- part.set_payload('')
- elif part.get_payload() and not part.is_multipart():
- payload = part.get_payload(decode=True)
- ctype = part.get_content_type()
- if not isinstance(ctype, unicode):
- ctype.decode("ascii")
- if payload is None:
- continue
- attachments.append(self.parse_attachment(part, part_num))
- if self.msg.is_multipart():
- text = []
- for part in self.msg.walk():
- if not part.get_payload() or part.is_multipart():
- continue
- partctype = part.get_content_type()
- if partctype != 'text/plain' and partctype != 'text/html':
- continue
- try:
- t = part.get_payload(decode=True) or ''
- except (binascii.Error, TypeError):
- t = part.get_payload() or ''
- partcharset = get_charset(part, guess=True)
- try:
- t = t.decode(partcharset, 'replace')
- except (UnicodeError, LookupError, ValueError,
- AssertionError):
- t = t.decode('ascii', 'replace')
- if isinstance(t, basestring):
- if not t.endswith('\n'):
- t += '\n'
- text.append(t)
-
- text = u"\n".join(text)
- else:
- text = self.msg.get_payload(decode=True)
- charset = get_charset(self.msg, guess=True)
- try:
- text = text.decode(charset, "replace")
- except (UnicodeError, LookupError, ValueError, AssertionError):
- text = text.decode('ascii', 'replace')
-
- next_part_match = NEXT_PART.search(text)
- if next_part_match:
- text = text[0:next_part_match.start(0)]
-
- return (text, attachments)
-
- def parse_attachment(self, part, counter, filter_html=True):
- decodedpayload = part.get_payload(decode=True)
- ctype = part.get_content_type()
- if not isinstance(ctype, unicode):
- ctype = ctype.decode("ascii")
- charset = get_charset(part, default=None, guess=False)
- try:
- filename = oneline(part.get_filename(''))
- except (TypeError, UnicodeDecodeError):
- filename = u"attachment.bin"
- filename, fnext = os.path.splitext(filename)
- ext = fnext or guess_extension(ctype, fnext)
- if not ext:
- if ctype == 'message/rfc822':
- ext = '.txt'
- else:
- ext = '.bin'
- ext = sre.sub('', ext)
- if not filename:
- filebase = u'attachment'
- else:
- parts = pre.split(filename)
- filename = parts[-1]
- filename = dre.sub('', filename)
- filename = sre.sub('', filename)
- filebase = filename
- if ctype == 'message/rfc822':
- submsg = part.get_payload()
- decodedpayload = str(submsg)
- return (counter, filebase + ext, ctype, charset, decodedpayload)
diff --git a/src/postorius/templatetags/pagination.py b/src/postorius/templatetags/pagination.py
deleted file mode 100644
index f73fb7f..0000000
--- a/src/postorius/templatetags/pagination.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (C) 1998-2016 by the Free Software Foundation, Inc.
-#
-# This file is part of Postorius.
-#
-# Postorius is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free
-# Software Foundation, either version 3 of the License, or (at your option)
-# any later version.
-#
-# Postorius 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
-# Postorius. If not, see .
-
-from django import template
-from django.utils.html import conditional_escape
-
-
-register = template.Library()
-
-
-@register.simple_tag(takes_context=True)
-def add_to_query_string(context, *args, **kwargs):
- """Adds or replaces parameters in the query string"""
- qs = context["request"].GET.copy()
- # create a dict from every args couple
- new_qs_elements = dict(zip(args[::2], args[1::2]))
- new_qs_elements.update(kwargs)
- # don't use the .update() method, it appends instead of overwriting.
- for key, value in new_qs_elements.iteritems():
- qs[key] = value
- return conditional_escape(qs.urlencode())
diff --git a/src/postorius/tests/mailman_api_tests/test_list_member_options.py b/src/postorius/tests/mailman_api_tests/test_list_member_options.py
index 78bc29d..6fd7fa9 100644
--- a/src/postorius/tests/mailman_api_tests/test_list_member_options.py
+++ b/src/postorius/tests/mailman_api_tests/test_list_member_options.py
@@ -87,7 +87,6 @@
UserPreferences)
def test_moderation_action(self):
- member = self.foo_list.get_member('test@example.com')
self.assertIsNone(
self.foo_list.get_member('test@example.com').moderation_action)
self.client.login(username='testsu', password='testpass')
diff --git a/src/postorius/tests/utils.py b/src/postorius/tests/utils.py
index e3c18c6..47b0ec0 100644
--- a/src/postorius/tests/utils.py
+++ b/src/postorius/tests/utils.py
@@ -21,9 +21,10 @@
from django.conf import settings
from django.contrib import messages
from django.core.urlresolvers import reverse
-from django.test import RequestFactory, TestCase
+from django.test import TestCase
from mock import MagicMock
from six.moves.urllib_parse import quote
+from django_mailman3.tests.utils import get_flash_messages
from postorius.utils import get_client
from mailmanclient.testing.vcr_helpers import get_vcr
@@ -88,20 +89,6 @@
return mock_object
-def get_flash_messages(response, empty=True):
- if "messages" not in response.cookies:
- return []
- # A RequestFactory will not run the messages middleware, and thus will
- # not delete the messages after retrieval.
- dummy_request = RequestFactory().get("/")
- dummy_request.COOKIES["messages"] = response.cookies["messages"].value
- msgs = list(messages.storage.cookie.CookieStorage(dummy_request))
- if empty:
- del response.client.cookies["messages"]
- return msgs
-get_flash_messages.__test__ = False
-
-
class ViewTestCase(TestCase):
use_vcr = True
diff --git a/src/postorius/views/rest.py b/src/postorius/views/rest.py
index 1d21b55..18043e8 100644
--- a/src/postorius/views/rest.py
+++ b/src/postorius/views/rest.py
@@ -28,7 +28,7 @@
from postorius.auth.decorators import list_moderator_required
from postorius.models import List
-from postorius.lib.scrub import Scrubber
+from django_mailman3.lib.scrub import Scrubber
def parse(message):