From 23f0aafe4490b4126af6c8e12aaa340170f042c6 Mon Sep 17 00:00:00 2001 From: Folker Bernitt Date: Thu, 23 Jul 2015 13:31:50 +0200 Subject: Started work on MailStore abstraction. --- service/pixelated/adapter/mailstore/__init__.py | 38 +++++++++ .../pixelated/adapter/mailstore/leap_mailstore.py | 52 +++++++++++++ service/pixelated/adapter/model/mail.py | 8 ++ service/test/unit/adapter/mailstore/__init__.py | 15 ++++ .../unit/adapter/mailstore/test_leap_mailstore.py | 89 ++++++++++++++++++++++ .../test/unit/fixtures/mailset/new/mbox00000000 | 2 +- .../test/unit/fixtures/mailset/new/mbox00000001 | 2 +- 7 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 service/pixelated/adapter/mailstore/__init__.py create mode 100644 service/pixelated/adapter/mailstore/leap_mailstore.py create mode 100644 service/test/unit/adapter/mailstore/__init__.py create mode 100644 service/test/unit/adapter/mailstore/test_leap_mailstore.py diff --git a/service/pixelated/adapter/mailstore/__init__.py b/service/pixelated/adapter/mailstore/__init__.py new file mode 100644 index 00000000..2e7f132a --- /dev/null +++ b/service/pixelated/adapter/mailstore/__init__.py @@ -0,0 +1,38 @@ +# +# Copyright (c) 2015 ThoughtWorks, Inc. +# +# Pixelated is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pixelated 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Pixelated. If not, see . + + +class MailStore(object): + def get_mail(self, mail_id): + pass + + def get_mails(self, mail_ids): + pass + + def delete_mail(self, mail_id): + pass + + def update_mail(self, mail): + pass + + def add_mail(self, mailbox_name, mail): + pass + + def get_mailbox_names(self): + pass + + def get_mailbox_mail_ids(self, mailbox_name): + pass diff --git a/service/pixelated/adapter/mailstore/leap_mailstore.py b/service/pixelated/adapter/mailstore/leap_mailstore.py new file mode 100644 index 00000000..9d41c988 --- /dev/null +++ b/service/pixelated/adapter/mailstore/leap_mailstore.py @@ -0,0 +1,52 @@ +# +# Copyright (c) 2015 ThoughtWorks, Inc. +# +# Pixelated is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pixelated 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Pixelated. If not, see . +from leap.mail.adaptors.soledad import SoledadMailAdaptor +from twisted.internet import defer +from pixelated.adapter.mailstore import MailStore + +from leap.mail.mail import Message +from pixelated.adapter.model.mail import Mail + + +class LeapMail(Mail): + + def __init__(self, headers, body=None): + self.headers = headers + self._body = body + + @property + def body(self): + return self._body + +class LeapMailStore(MailStore): + __slots__ = ('account', 'soledad') + + def __init__(self, imapAccount, soledad): + self.account = imapAccount + self.soledad = soledad + + @defer.inlineCallbacks + def get_mail(self, mail_id): + try: + message = yield SoledadMailAdaptor().get_msg_from_mdoc_id(Message, self.soledad, mail_id) + + defer.returnValue(self._leap_message_to_leap_mail(message)) + except AttributeError: + defer.returnValue(None) + + def _leap_message_to_leap_mail(self, message): + return LeapMail(message.get_headers()) + diff --git a/service/pixelated/adapter/model/mail.py b/service/pixelated/adapter/model/mail.py index 5002974f..498ef079 100644 --- a/service/pixelated/adapter/model/mail.py +++ b/service/pixelated/adapter/model/mail.py @@ -48,6 +48,10 @@ SIZE_KEY = 'size' class Mail(object): + @property + def from_sender(self): + return self.headers['From'] + @property def to(self): return self.headers['To'] @@ -60,6 +64,10 @@ class Mail(object): def bcc(self): return self.headers['Bcc'] + @property + def subject(self): + return self.headers['Subject'] + @property def date(self): return self.headers['Date'] diff --git a/service/test/unit/adapter/mailstore/__init__.py b/service/test/unit/adapter/mailstore/__init__.py new file mode 100644 index 00000000..c5c30cde --- /dev/null +++ b/service/test/unit/adapter/mailstore/__init__.py @@ -0,0 +1,15 @@ +# +# Copyright (c) 2015 ThoughtWorks, Inc. +# +# Pixelated is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pixelated 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Pixelated. If not, see . diff --git a/service/test/unit/adapter/mailstore/test_leap_mailstore.py b/service/test/unit/adapter/mailstore/test_leap_mailstore.py new file mode 100644 index 00000000..e238695e --- /dev/null +++ b/service/test/unit/adapter/mailstore/test_leap_mailstore.py @@ -0,0 +1,89 @@ +# +# Copyright (c) 2015 ThoughtWorks, Inc. +# +# Pixelated is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pixelated 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Pixelated. If not, see . +from twisted.trial.unittest import TestCase + +from leap.mail import constants +from leap.mail.imap.account import IMAPAccount +from twisted.internet import defer + +from mockito import mock, when, any, unstub +from uuid import uuid4 +from pixelated.adapter.mailstore.leap_mailstore import LeapMailStore, LeapMail +from leap.mail.adaptors.soledad import SoledadMailAdaptor +import pkg_resources +from email.parser import Parser +import os +from leap.mail.mail import Message + + +class TestLeapMailStore(TestCase): + def setUp(self): + self.account = mock(mocked_obj=IMAPAccount) + self.soledad = mock() + + @defer.inlineCallbacks + def test_get_mail_not_exist(self): + store = LeapMailStore(self.account, self.soledad) + + mail = yield store.get_mail(_format_mdoc_id(uuid4(), 1)) + + self.assertIsNone(mail) + + @defer.inlineCallbacks + def test_get_mail(self): + mbox_uuid = str(uuid4()) + + mdoc_id = self._add_mail_fixture_to_soledad(mbox_uuid) + + store = LeapMailStore(self.account, self.soledad) + + mail = yield store.get_mail(mdoc_id) + + self.assertIsInstance(mail, LeapMail) + self.assertEqual('darby.senger@zemlak.biz', mail.from_sender) + self.assertEqual('carmel@murazikortiz.name', mail.to) + self.assertEqual('Itaque consequatur repellendus provident sunt quia.', mail.subject) + self.assertIsNone(mail.body) + + def _add_mail_fixture_to_soledad(self, mbox_uuid, mail_file='mbox00000000'): + mail = self._load_mail_from_file(mail_file) + + msg = SoledadMailAdaptor().get_msg_from_string(Message, mail.as_string()) + + msg.get_wrapper().mdoc.set_mbox_uuid(mbox_uuid) + + mdoc_id = msg.get_wrapper().mdoc.future_doc_id + fdoc_id = msg.get_wrapper().mdoc.fdoc + hdoc_id = msg.get_wrapper().mdoc.hdoc + cdoc_id = msg.get_wrapper().mdoc.cdocs[0] + + when(self.soledad).get_doc(mdoc_id).thenReturn(defer.succeed(msg.get_wrapper().mdoc.serialize())) + when(self.soledad).get_doc(fdoc_id).thenReturn(defer.succeed(msg.get_wrapper().fdoc.serialize())) + when(self.soledad).get_doc(hdoc_id).thenReturn(defer.succeed(msg.get_wrapper().hdoc.serialize())) + when(self.soledad).get_doc(cdoc_id).thenReturn(defer.succeed(msg.get_wrapper().cdocs[1].serialize())) + + return mdoc_id + + def _load_mail_from_file(self, mail_file): + mailset_dir = pkg_resources.resource_filename('test.unit.fixtures', 'mailset') + mail_file = os.path.join(mailset_dir, 'new', mail_file) + with open(mail_file) as f: + mail = Parser().parse(f) + return mail + + +def _format_mdoc_id(mbox_uuid, chash): + return constants.METAMSGID.format(mbox_uuid=mbox_uuid, chash=chash) \ No newline at end of file diff --git a/service/test/unit/fixtures/mailset/new/mbox00000000 b/service/test/unit/fixtures/mailset/new/mbox00000000 index 3d01c203..8c80257d 100644 --- a/service/test/unit/fixtures/mailset/new/mbox00000000 +++ b/service/test/unit/fixtures/mailset/new/mbox00000000 @@ -1,4 +1,4 @@ -From darby.senger@zemlak.biz +From: darby.senger@zemlak.biz Subject: Itaque consequatur repellendus provident sunt quia. To: carmel@murazikortiz.name X-TW-Pixelated-Tags: nite, macro, trash diff --git a/service/test/unit/fixtures/mailset/new/mbox00000001 b/service/test/unit/fixtures/mailset/new/mbox00000001 index fc76bba2..ba563430 100644 --- a/service/test/unit/fixtures/mailset/new/mbox00000001 +++ b/service/test/unit/fixtures/mailset/new/mbox00000001 @@ -1,4 +1,4 @@ -From madeline.littel@sanfordruel.com +From: madeline.littel@sanfordruel.com Subject: Error illum dignissimos autem eos aspernatur. To: phyllis@stiedemann.net X-TW-Pixelated-Tags: instadaily, inspiration -- cgit v1.2.3