summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorPatrick Maia and Victor Shyba <pixelated-team+pmaia+vshyba@thoughtworks.com>2014-08-26 22:06:43 +0000
committerPatrick Maia <pmaia@thoughtworks.com>2014-08-26 22:27:48 +0000
commit6592bfad8cb90d7256de949b181ed9d0b684afec (patch)
tree0541e5a280ea168d4b8603344449916c5c007593 /service
parentcf3ea5411adb12dd1bdc12ec01a17b37d974c7c3 (diff)
extracts tag and status conversion logic
Diffstat (limited to 'service')
-rw-r--r--service/pixelated/adapter/mail_service.py9
-rw-r--r--service/pixelated/adapter/pixelated_mail.py43
-rw-r--r--service/pixelated/adapter/status.py43
-rw-r--r--service/pixelated/adapter/tag.py (renamed from service/pixelated/tags.py)54
-rw-r--r--service/pixelated/user_agent.py3
-rw-r--r--service/test/adapter/mail_service_test.py3
-rw-r--r--service/test/adapter/pixelated_mail_test.py12
-rw-r--r--service/test/adapter/test_status.py35
-rw-r--r--service/test/adapter/test_tag.py46
-rw-r--r--service/test/test_tags.py57
10 files changed, 160 insertions, 145 deletions
diff --git a/service/pixelated/adapter/mail_service.py b/service/pixelated/adapter/mail_service.py
index 82925870..f2db8d16 100644
--- a/service/pixelated/adapter/mail_service.py
+++ b/service/pixelated/adapter/mail_service.py
@@ -22,7 +22,6 @@ from pixelated.bitmask_libraries.provider import LeapProvider
from pixelated.bitmask_libraries.session import LeapSessionFactory
from pixelated.bitmask_libraries.auth import LeapCredentials
from pixelated.adapter.pixelated_mail import PixelatedMail
-from pixelated.tags import Tags
class MailService:
@@ -34,7 +33,6 @@ class MailService:
self.server_name = server_name
self.mailbox_name = 'INBOX'
self.certs_home = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "certificates"))
- self.tags = Tags()
self._open_leap_session()
except:
traceback.print_exc(file=sys.stdout)
@@ -64,10 +62,11 @@ class MailService:
def _update_tag_list(self, tags):
for tag in tags:
- self.tags.add(tag)
+ pass
+ # self.tags.add(tag)
def _update_flags(self, new_tags, mail_id):
- new_tags_flag_name = ['tag_' + tag.name for tag in new_tags if tag.name not in Tags.SPECIAL_TAGS]
+ new_tags_flag_name = ['tag_' + tag.name for tag in new_tags if tag.name not in ['inbox', 'drafts', 'sent', 'trash']]
self.set_flags(mail_id, new_tags_flag_name)
def set_flags(self, mail_id, new_tags_flag_name):
@@ -80,7 +79,7 @@ class MailService:
return PixelatedMail.from_leap_mail(message)
def all_tags(self):
- return self.tags
+ return []
def thread(self, thread_id):
raise NotImplementedError()
diff --git a/service/pixelated/adapter/pixelated_mail.py b/service/pixelated/adapter/pixelated_mail.py
index 4169bb23..3e4e415b 100644
--- a/service/pixelated/adapter/pixelated_mail.py
+++ b/service/pixelated/adapter/pixelated_mail.py
@@ -13,32 +13,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/>.
-from pixelated.tags import Tag
-from pixelated.tags import Tags
+from pixelated.adapter.tag import Tag
+from pixelated.adapter.status import Status
import dateutil.parser as dateparser
class PixelatedMail:
- LEAP_FLAGS = ['\\Seen',
- '\\Answered',
- '\\Flagged',
- '\\Deleted',
- '\\Draft',
- '\\Recent',
- 'List']
-
- LEAP_FLAGS_STATUSES = {
- '\\Seen': 'read',
- '\\Answered': 'replied'
- }
-
- LEAP_FLAGS_TAGS = {
- '\\Deleted': 'trash',
- '\\Draft': 'drafts',
- '\\Recent': 'inbox'
- }
-
def __init__(self):
pass
@@ -56,8 +37,7 @@ class PixelatedMail:
return mail
def _extract_status(self):
- flags = self.leap_mail.getFlags()
- return [converted for flag, converted in self.LEAP_FLAGS_STATUSES.items() if flag in flags]
+ return Status.from_flags(self.leap_mail.getFlags())
def _extract_headers(self):
temporary_headers = {}
@@ -69,21 +49,9 @@ class PixelatedMail:
def _extract_tags(self):
flags = self.leap_mail.getFlags()
- tag_names = self._converted_tags(flags) + self._custom_tags(flags)
- tags = []
- for tag in tag_names:
- tags.append(Tag(tag))
+ tags = set(Tag.from_flag(flag) for flag in flags)
return tags
- def _converted_tags(self, flags):
- return [converted for flag, converted in self.LEAP_FLAGS_TAGS.items() if flag in flags]
-
- def _custom_tags(self, flags):
- return [self._remove_prefix(flag) for flag in self.leap_mail.getFlags() if flag.startswith('tag_')]
-
- def _remove_prefix(self, flag_name):
- return flag_name.replace('tag_', '', 1)
-
def update_tags(self, tags):
self.tags = [Tag(tag) for tag in tags]
return self.tags
@@ -93,11 +61,12 @@ class PixelatedMail:
def as_dict(self):
tags = [tag.name for tag in self.tags]
+ statuses = [status.name for status in self.status]
return {
'header': self.headers,
'ident': self.ident,
'tags': tags,
- 'status': self.status,
+ 'status': statuses,
'security_casing': self.security_casing,
'body': self.body
}
diff --git a/service/pixelated/adapter/status.py b/service/pixelated/adapter/status.py
new file mode 100644
index 00000000..2002b649
--- /dev/null
+++ b/service/pixelated/adapter/status.py
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2014 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 <http://www.gnu.org/licenses/>.
+
+class Status:
+
+ LEAP_FLAGS_STATUSES = {
+ '\\Seen': 'read',
+ '\\Answered': 'replied'
+ }
+
+ @classmethod
+ def from_flag(cls, flag):
+ return Status(cls.LEAP_FLAGS_STATUSES[flag])
+
+ @classmethod
+ def from_flags(cls, flags):
+ return set(cls.from_flag(flag) for flag in flags if flag in cls.LEAP_FLAGS_STATUSES.keys())
+
+ def __init__(self, name):
+ self.name = name
+ self.ident = name.__hash__()
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __hash__(self):
+ return self.name.__hash__()
+
+ def __repr__(self):
+ return self.name
diff --git a/service/pixelated/tags.py b/service/pixelated/adapter/tag.py
index f5c6b877..daef30fa 100644
--- a/service/pixelated/tags.py
+++ b/service/pixelated/adapter/tag.py
@@ -18,6 +18,28 @@ import json
class Tag:
+ LEAP_FLAGS_TAGS = {
+ '\\Deleted': 'trash',
+ '\\Draft': 'drafts',
+ '\\Recent': 'inbox'
+ }
+
+ @classmethod
+ def from_flags(cls, flags):
+ return set(filter(None, (cls.from_flag(flag) for flag in flags)))
+
+ @classmethod
+ def from_flag(cls, flag):
+ if flag in cls.LEAP_FLAGS_TAGS.keys():
+ return Tag(cls.LEAP_FLAGS_TAGS[flag])
+ if flag.startswith('tag_'):
+ return Tag(cls._remove_prefix(flag))
+ return None
+
+ @classmethod
+ def _remove_prefix(cls, flag_name):
+ return flag_name.replace('tag_', '', 1)
+
def __init__(self, name, default=False):
self.name = name
self.default = default
@@ -44,35 +66,3 @@ class Tag:
def __repr__(self):
return self.name
-
-
-class Tags:
-
- SPECIAL_TAGS = ['inbox', 'sent', 'drafts', 'trash']
-
- def __init__(self):
- self.tags = {}
- self.create_default_tags()
-
- def create_default_tags(self):
- for name in self.SPECIAL_TAGS:
- self.tags[name] = self.add(name)
-
- def add(self, tag_input):
- if tag_input.__class__.__name__ == 'Tag':
- tag_input = tag_input.name
- tag = Tag(tag_input, tag_input in self.SPECIAL_TAGS)
- self.tags[tag_input] = tag
- return tag
-
- def find(self, name):
- return self.tags[name]
-
- def __len__(self):
- return len(self.tags)
-
- def __iter__(self):
- return self.tags.itervalues()
-
- def as_dict(self):
- return [tag.as_dict() for tag in self.tags.values()]
diff --git a/service/pixelated/user_agent.py b/service/pixelated/user_agent.py
index 2509ea30..b9ac05bb 100644
--- a/service/pixelated/user_agent.py
+++ b/service/pixelated/user_agent.py
@@ -26,7 +26,6 @@ import pixelated.reactor_manager as reactor_manager
import pixelated.search_query as search_query
from pixelated.adapter.mail_service import MailService
from pixelated.adapter.pixelated_mail import PixelatedMail
-from pixelated.tags import Tags
static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "web-ui", "app"))
# this is a workaround for packaging
@@ -105,7 +104,7 @@ def delete_mails(mail_id):
@app.route('/tags')
def tags():
tags = mail_service.all_tags()
- return respond_json(tags.as_dict())
+ return respond_json([tag.as_dict() for tag in tags])
@app.route('/mail/<mail_id>')
diff --git a/service/test/adapter/mail_service_test.py b/service/test/adapter/mail_service_test.py
index d4a0d5c3..86194036 100644
--- a/service/test/adapter/mail_service_test.py
+++ b/service/test/adapter/mail_service_test.py
@@ -18,8 +18,7 @@ import unittest
from pixelated.adapter.mail_service import MailService
from mock import Mock, MagicMock, patch
import test_helper
-from pixelated.tags import Tag
-
+from pixelated.adapter.tag import Tag
class TestMailService(unittest.TestCase):
diff --git a/service/test/adapter/pixelated_mail_test.py b/service/test/adapter/pixelated_mail_test.py
index 308424e0..c7fe9112 100644
--- a/service/test/adapter/pixelated_mail_test.py
+++ b/service/test/adapter/pixelated_mail_test.py
@@ -16,8 +16,8 @@
import unittest
from pixelated.adapter.pixelated_mail import PixelatedMail
-from pixelated.tags import Tag
-from pixelated.tags import Tags
+from pixelated.adapter.tag import Tag
+from pixelated.adapter.status import Status
import test_helper
@@ -35,14 +35,6 @@ class TestPixelatedMail(unittest.TestCase):
pixelated_mail = PixelatedMail.from_leap_mail(test_helper.leap_mail(leap_flags=['\\Draft']))
self.assertIn(Tag('drafts'), pixelated_mail.tags)
- def test_leap_seen_flag_is_translated_to_read_status(self):
- pixelated_mail = PixelatedMail.from_leap_mail(test_helper.leap_mail(leap_flags=['\\Seen']))
- self.assertIn('read', pixelated_mail.status)
-
- def test_leap_answered_flag_is_translated_to_replied_status(self):
- pixelated_mail = PixelatedMail.from_leap_mail(test_helper.leap_mail(leap_flags=['\\Answered']))
- self.assertIn('replied', pixelated_mail.status)
-
def test_leap_flags_that_are_custom_tags_are_handled(self):
pixelated_mail = PixelatedMail.from_leap_mail(test_helper.leap_mail(extra_flags=['tag_work']))
self.assertIn(Tag('work'), pixelated_mail.tags)
diff --git a/service/test/adapter/test_status.py b/service/test/adapter/test_status.py
new file mode 100644
index 00000000..b39d4846
--- /dev/null
+++ b/service/test/adapter/test_status.py
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2014 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 <http://www.gnu.org/licenses/>.
+import unittest
+
+from pixelated.adapter.status import Status
+import test_helper
+
+
+class TestStatus(unittest.TestCase):
+
+ def test_leap_seen_flag_is_translated_to_read_status(self):
+ status = Status.from_flag('\\Seen')
+ self.assertEquals(Status('read'), status)
+
+ def test_leap_answered_flag_is_translated_to_replied_status(self):
+ status = Status.from_flag('\\Answered')
+ self.assertEquals(Status('replied'), status)
+
+ def test_bulk_conversion(self):
+ statuses = Status.from_flags(['\\Answered', '\\Seen', '\\Recent', 'tag_a_custom'])
+ self.assertEquals(set([Status('read'), Status('replied')]), statuses)
+
diff --git a/service/test/adapter/test_tag.py b/service/test/adapter/test_tag.py
new file mode 100644
index 00000000..30bc1550
--- /dev/null
+++ b/service/test/adapter/test_tag.py
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2014 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 <http://www.gnu.org/licenses/>.
+import unittest
+
+from pixelated.adapter.tag import Tag
+import test_helper
+
+
+class TestTag(unittest.TestCase):
+
+ def test_leap_recent_flag_is_translated_to_inbox_tag(self):
+ tag = Tag.from_flag('\\Recent')
+ self.assertEquals(Tag('inbox'), tag)
+
+ def test_leap_deleted_flag_is_translated_to_trash_tag(self):
+ tag = Tag.from_flag('\\Deleted')
+ self.assertEquals(Tag('trash'), tag)
+
+ def test_leap_draft_flag_is_translated_to_draft_tag(self):
+ tag = Tag.from_flag('\\Draft')
+ self.assertEquals(Tag('drafts'), tag)
+
+ def test_leap_flags_that_are_custom_tags_are_handled(self):
+ tag = Tag.from_flag('tag_work')
+ self.assertEquals(Tag('work'), tag)
+
+ def test_custom_tags_containing_our_prefix_are_handled(self):
+ tag = Tag.from_flag('tag_tag_work_tag_')
+ self.assertEquals(Tag('tag_work_tag_'), tag)
+
+ def test_bulk_conversion(self):
+ tags = Tag.from_flags(['\\Answered', '\\Seen', '\\Recent', 'tag_a_custom', 'List'])
+ self.assertEquals(set([Tag('inbox'), Tag('a_custom')]), tags)
diff --git a/service/test/test_tags.py b/service/test/test_tags.py
deleted file mode 100644
index abd59b20..00000000
--- a/service/test/test_tags.py
+++ /dev/null
@@ -1,57 +0,0 @@
-#
-# Copyright (c) 2014 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 <http://www.gnu.org/licenses/>.
-import unittest
-from pixelated.tags import Tags, Tag
-
-
-class TagTestCase(unittest.TestCase):
-
- def test_create_tag(self):
- tag = Tag('test', True)
- self.assertEqual(tag.name, 'test')
-
-
-class TagsTestCase(unittest.TestCase):
-
- def test_add_tag_to_collection(self):
- tag_collection = Tags()
- tag_collection.add('test')
- self.assertEqual(len(tag_collection), len(Tags()) + 1)
- tag_collection.add('test2')
- self.assertEqual(len(tag_collection), len(Tags()) + 2)
-
- def test_no_tag_duplication(self):
- tag_collection = Tags()
- tag_collection.add('test')
- self.assertEqual(len(tag_collection), len(Tags()) + 1)
- tag_collection.add('test')
- self.assertEqual(len(tag_collection), len(Tags()) + 1)
-
- def test_find_tag_on_collection(self):
- tag_collection = Tags()
- tag_collection.add('test')
- tag_collection.add('test2')
- self.assertEqual(tag_collection.find('test'), Tag('test', True))
-
- def test_special_tags_always_exist(self):
- special_tags = ['inbox', 'sent', 'drafts', 'trash']
- tag_collection = Tags()
- for tag in special_tags:
- self.assertIn(Tag(tag, True), tag_collection)
-
- def test_special_tags_are_default(self):
- tags = Tags()
- self.assertTrue(tags.find('inbox').default)