summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--service/pixelated/adapter/mailstore/leap_mailstore.py23
-rw-r--r--service/pixelated/adapter/mailstore/mailstore.py3
-rw-r--r--service/test/unit/adapter/mailstore/test_leap_mailstore.py78
3 files changed, 86 insertions, 18 deletions
diff --git a/service/pixelated/adapter/mailstore/leap_mailstore.py b/service/pixelated/adapter/mailstore/leap_mailstore.py
index 9b1afdd4..b72c8804 100644
--- a/service/pixelated/adapter/mailstore/leap_mailstore.py
+++ b/service/pixelated/adapter/mailstore/leap_mailstore.py
@@ -13,7 +13,9 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+import base64
from email.header import decode_header
+import quopri
import re
from uuid import uuid4
from leap.mail.adaptors.soledad import SoledadMailAdaptor
@@ -177,6 +179,27 @@ class LeapMailStore(MailStore):
return defer.gatherResults(deferreds, consumeErrors=True)
@defer.inlineCallbacks
+ def get_mail_attachment(self, attachment_id):
+ results = yield self.soledad.get_from_index('by-type-and-payloadhash', 'cnt', attachment_id) if attachment_id else []
+ if len(results):
+ content = results[0]
+ defer.returnValue({'content-type': content.content_type, 'content': self._try_decode(
+ content.raw, content.content_transfer_encoding)})
+ else:
+ raise ValueError('No attachment with id %s found!' % attachment_id)
+
+ def _try_decode(self, raw, encoding):
+ encoding = encoding.lower()
+ if encoding == 'base64':
+ data = base64.decodestring(raw)
+ elif encoding == 'quoted-printable':
+ data = quopri.decodestring(raw)
+ else:
+ data = str(raw)
+
+ return bytearray(data)
+
+ @defer.inlineCallbacks
def update_mail(self, mail):
message = yield self._fetch_msg_from_soledad(mail.mail_id)
message.get_wrapper().set_tags(tuple(mail.tags))
diff --git a/service/pixelated/adapter/mailstore/mailstore.py b/service/pixelated/adapter/mailstore/mailstore.py
index 425def92..60716dfe 100644
--- a/service/pixelated/adapter/mailstore/mailstore.py
+++ b/service/pixelated/adapter/mailstore/mailstore.py
@@ -19,6 +19,9 @@ class MailStore(object):
def get_mail(self, mail_id):
pass
+ def get_mail_attachment(self, attachment_id):
+ pass
+
def get_mails(self, mail_ids):
pass
diff --git a/service/test/unit/adapter/mailstore/test_leap_mailstore.py b/service/test/unit/adapter/mailstore/test_leap_mailstore.py
index 09c92980..7cbd1405 100644
--- a/service/test/unit/adapter/mailstore/test_leap_mailstore.py
+++ b/service/test/unit/adapter/mailstore/test_leap_mailstore.py
@@ -14,11 +14,13 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+import base64
from email.header import Header
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import json
+import quopri
from uuid import uuid4
from email.parser import Parser
import os
@@ -30,7 +32,7 @@ from leap.mail import constants
from twisted.internet import defer
from mockito import mock, when, verify, any as ANY
import test.support.mockito
-from leap.mail.adaptors.soledad import SoledadMailAdaptor, MailboxWrapper
+from leap.mail.adaptors.soledad import SoledadMailAdaptor, MailboxWrapper, ContentDocWrapper
import pkg_resources
from leap.mail.mail import Message
from pixelated.adapter.mailstore import underscore_uuid
@@ -60,7 +62,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_get_mail(self):
- mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000000')
+ mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
store = LeapMailStore(self.soledad)
@@ -76,7 +78,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_get_mail_from_mailbox(self):
other, _ = self._mock_get_mailbox('OTHER', create_new_uuid=True)
- mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000000', other.uuid)
+ mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000000', other.uuid)
store = LeapMailStore(self.soledad)
@@ -86,8 +88,8 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_get_two_different_mails(self):
- first_mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000000')
- second_mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000001')
+ first_mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
+ second_mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000001')
store = LeapMailStore(self.soledad)
@@ -100,8 +102,8 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_get_mails(self):
- first_mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000000')
- second_mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000001')
+ first_mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
+ second_mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000001')
store = LeapMailStore(self.soledad)
@@ -124,7 +126,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_get_mail_with_body(self):
expeted_body = 'Dignissimos ducimus veritatis. Est tenetur consequatur quia occaecati. Vel sit sit voluptas.\n\nEarum distinctio eos. Accusantium qui sint ut quia assumenda. Facere dignissimos inventore autem sit amet. Pariatur voluptatem sint est.\n\nUt recusandae praesentium aspernatur. Exercitationem amet placeat deserunt quae consequatur eum. Unde doloremque suscipit quia.\n\n'
- mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000000')
+ mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
store = LeapMailStore(self.soledad)
@@ -133,8 +135,47 @@ class TestLeapMailStore(TestCase):
self.assertEqual(expeted_body, mail.body)
@defer.inlineCallbacks
+ def test_get_mail_attachment(self):
+ attachment_id = 'AAAA9AAD9E153D24265395203C53884506ABA276394B9FEC02B214BF9E77E48E'
+ doc = ContentDocWrapper(content_type='foo/bar', raw='asdf')
+ when(self.soledad).get_from_index('by-type-and-payloadhash', 'cnt', attachment_id).thenReturn(defer.succeed([doc]))
+ store = LeapMailStore(self.soledad)
+
+ attachment = yield store.get_mail_attachment(attachment_id)
+
+ self.assertEqual({'content-type': 'foo/bar', 'content': bytearray('asdf')}, attachment)
+
+ @defer.inlineCallbacks
+ def test_get_mail_attachment_different_content_encodings(self):
+ attachment_id = '1B0A9AAD9E153D24265395203C53884506ABA276394B9FEC02B214BF9E77E48E'
+ encoding_examples = [('', 'asdf', 'asdf'),
+ ('base64', 'asdf', 'YXNkZg=='),
+ ('quoted-printable', 'äsdf', '=C3=A4sdf')]
+
+ for transfer_encoding, data, encoded_data in encoding_examples:
+ doc = ContentDocWrapper(content_type='foo/bar', raw=encoded_data,
+ content_transfer_encoding=transfer_encoding)
+ when(self.soledad).get_from_index('by-type-and-payloadhash', 'cnt', attachment_id).thenReturn(defer.succeed([doc]))
+ store = LeapMailStore(self.soledad)
+
+ attachment = yield store.get_mail_attachment(attachment_id)
+
+ self.assertEqual(bytearray(data), attachment['content'])
+
+ @defer.inlineCallbacks
+ def test_get_mail_attachment_throws_exception_if_attachment_does_not_exist(self):
+ attachment_id = '1B0A9AAD9E153D24265395203C53884506ABA276394B9FEC02B214BF9E77E48E'
+ when(self.soledad).get_from_index('by-type-and-payloadhash', 'cnt', attachment_id).thenReturn(defer.succeed([]))
+ store = LeapMailStore(self.soledad)
+ try:
+ yield store.get_mail_attachment(attachment_id)
+ self.fail('ValueError exception expected')
+ except ValueError:
+ pass
+
+ @defer.inlineCallbacks
def test_update_mail(self):
- mdoc_id, fdoc_id = self._add_mail_fixture_to_soledad('mbox00000000')
+ mdoc_id, fdoc_id = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
soledad_fdoc = self.doc_by_id[fdoc_id]
when(self.soledad).put_doc(soledad_fdoc).thenReturn(defer.succeed(None))
@@ -151,8 +192,8 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_all_mails(self):
- first_mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000000')
- second_mdoc_id, _ = self._add_mail_fixture_to_soledad('mbox00000001')
+ first_mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
+ second_mdoc_id, _ = self._add_mail_fixture_to_soledad_from_file('mbox00000001')
when(self.soledad).get_from_index('by-type', 'meta').thenReturn(defer.succeed([self.doc_by_id[first_mdoc_id], self.doc_by_id[second_mdoc_id]]))
store = LeapMailStore(self.soledad)
@@ -260,7 +301,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_delete_mail(self):
- mdoc_id, fdoc_id = self._add_mail_fixture_to_soledad('mbox00000000')
+ mdoc_id, fdoc_id = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
store = LeapMailStore(self.soledad)
@@ -270,7 +311,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_get_mailbox_mail_ids(self):
- mdoc_id, fdoc_id = self._add_mail_fixture_to_soledad('mbox00000000')
+ mdoc_id, fdoc_id = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
when(self.soledad).get_from_index('by-type-and-mbox-uuid', 'flags', underscore_uuid(self.mbox_uuid)).thenReturn(defer.succeed([self.doc_by_id[fdoc_id]]))
self._mock_get_mailbox('INBOX')
store = LeapMailStore(self.soledad)
@@ -294,7 +335,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_copy_mail_to_mailbox(self):
expected_message = self._add_create_mail_mocks_to_soledad_from_fixture_file('mbox00000000')
- mail_id, fdoc_id = self._add_mail_fixture_to_soledad('mbox00000000')
+ mail_id, fdoc_id = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
self._mock_get_mailbox('TRASH')
store = LeapMailStore(self.soledad)
@@ -305,7 +346,7 @@ class TestLeapMailStore(TestCase):
@defer.inlineCallbacks
def test_move_to_mailbox(self):
expected_message = self._add_create_mail_mocks_to_soledad_from_fixture_file('mbox00000000')
- mail_id, fdoc_id = self._add_mail_fixture_to_soledad('mbox00000000')
+ mail_id, fdoc_id = self._add_mail_fixture_to_soledad_from_file('mbox00000000')
self._mock_get_mailbox('TRASH')
store = LeapMailStore(self.soledad)
@@ -343,11 +384,13 @@ class TestLeapMailStore(TestCase):
return mbox, soledad_doc
- def _add_mail_fixture_to_soledad(self, mail_file, mbox_uuid=None):
+ def _add_mail_fixture_to_soledad_from_file(self, mail_file, mbox_uuid=None):
mail = self._load_mail_from_file(mail_file)
+ return self._add_mail_fixture_to_soledad(mail, mbox_uuid)
+
+ def _add_mail_fixture_to_soledad(self, mail, mbox_uuid=None):
msg = self._convert_mail_to_leap_message(mail, mbox_uuid)
wrapper = msg.get_wrapper()
-
mdoc_id = wrapper.mdoc.future_doc_id
fdoc_id = wrapper.mdoc.fdoc
hdoc_id = wrapper.mdoc.hdoc
@@ -357,7 +400,6 @@ class TestLeapMailStore(TestCase):
self._mock_get_soledad_doc(fdoc_id, wrapper.fdoc)
self._mock_get_soledad_doc(hdoc_id, wrapper.hdoc)
self._mock_get_soledad_doc(cdoc_id, wrapper.cdocs[1])
-
return mdoc_id, fdoc_id
def _add_create_mail_mocks_to_soledad_from_fixture_file(self, mail_file):