diff --git a/opwen_email_server/actions.py b/opwen_email_server/actions.py index e5df6df3..d082b858 100644 --- a/opwen_email_server/actions.py +++ b/opwen_email_server/actions.py @@ -18,6 +18,7 @@ from opwen_email_server.services.storage import AzureObjectStorage from opwen_email_server.services.storage import AzureTextStorage from opwen_email_server.utils.email_parser import MimeEmailParser +from opwen_email_server.utils.email_parser import descending_timestamp from opwen_email_server.utils.email_parser import ensure_has_sent_at from opwen_email_server.utils.email_parser import get_domain from opwen_email_server.utils.email_parser import get_domains @@ -122,8 +123,9 @@ def _action(self, resource_id): # type: ignore for email_address in self._get_pivot(email): domain = get_domain(email_address) + desc_prefix = descending_timestamp(email['sent_at']) if domain.endswith(mailbox.MAILBOX_DOMAIN): - index = f"{domain}/{email_address}/{self._folder}/{email['sent_at']}/{resource_id}" + index = f"{domain}/{email_address}/{self._folder}/{desc_prefix}/{resource_id}" self._mailbox_storage.store_text(index, 'indexed') self.log_event(events.MAILBOX_EMAIL_INDEXED, {'folder': self._folder}) # noqa: E501 # yapf: disable diff --git a/opwen_email_server/constants/mailbox.py b/opwen_email_server/constants/mailbox.py index 4388b738..cc15cc27 100644 --- a/opwen_email_server/constants/mailbox.py +++ b/opwen_email_server/constants/mailbox.py @@ -3,3 +3,4 @@ MAILBOX_DOMAIN = 'lokole.ca' # type: Final RECEIVED_FOLDER = 'received' # type: Final SENT_FOLDER = 'sent' # type: Final +FUTURE_TIMESTAMP = 2100000000 # type: Final diff --git a/opwen_email_server/integration/webapp.py b/opwen_email_server/integration/webapp.py index 19c5cac7..8ccc8a5f 100644 --- a/opwen_email_server/integration/webapp.py +++ b/opwen_email_server/integration/webapp.py @@ -24,6 +24,7 @@ from opwen_email_server.services.storage import AzureObjectStorage from opwen_email_server.services.storage import AzureTextStorage from opwen_email_server.utils.collections import chunks +from opwen_email_server.utils.email_parser import descending_timestamp from opwen_email_server.utils.email_parser import ensure_has_sent_at from opwen_email_server.utils.email_parser import get_domain from opwen_email_server.utils.email_parser import get_recipients @@ -226,7 +227,9 @@ def _delete(self, email_address: str, uids: Iterable[str]): else: continue - self._mailbox_storage.delete(f"{domain}/{email_address}/{folder}/{email['sent_at']}/{uid}") + desc_prefix = descending_timestamp(email['sent_at']) + + self._mailbox_storage.delete(f"{domain}/{email_address}/{folder}/{desc_prefix}/{uid}") def _mark_sent(self, uids: Iterable[str]): pass diff --git a/opwen_email_server/utils/email_parser.py b/opwen_email_server/utils/email_parser.py index d54aa91e..04e62c21 100644 --- a/opwen_email_server/utils/email_parser.py +++ b/opwen_email_server/utils/email_parser.py @@ -21,6 +21,7 @@ from opwen_email_server.config import MAX_HEIGHT_IMAGES from opwen_email_server.config import MAX_WIDTH_IMAGES +from opwen_email_server.constants import mailbox from opwen_email_server.utils.log import LogMixin from opwen_email_server.utils.serialization import to_base64 @@ -225,6 +226,10 @@ def format_inline_images(email: dict, on_error: Callable) -> dict: return new_email +def descending_timestamp(email_sent_at: str) -> str: + return str(mailbox.FUTURE_TIMESTAMP - int(datetime.fromisoformat(email_sent_at).timestamp())) + + class MimeEmailParser(LogMixin): def __call__(self, mime_email: str) -> dict: email = parse_mime_email(mime_email) diff --git a/tests/opwen_email_server/test_actions.py b/tests/opwen_email_server/test_actions.py index adaeb5d3..7aae6104 100644 --- a/tests/opwen_email_server/test_actions.py +++ b/tests/opwen_email_server/test_actions.py @@ -152,9 +152,9 @@ def test_200(self): self.assertEqual(status, 200) self.email_storage.fetch_object.assert_called_once_with(email_id) - self.mailbox_storage.store_text.assert_any_call('bar.lokole.ca/1@bar.lokole.ca/received/2019-10-26 22:47/123', + self.mailbox_storage.store_text.assert_any_call('bar.lokole.ca/1@bar.lokole.ca/received/527869980/123', 'indexed') - self.mailbox_storage.store_text.assert_any_call('baz.lokole.ca/2@baz.lokole.ca/received/2019-10-26 22:47/123', + self.mailbox_storage.store_text.assert_any_call('baz.lokole.ca/2@baz.lokole.ca/received/527869980/123', 'indexed') self.assertEqual(self.mailbox_storage.store_text.call_count, 2) @@ -185,8 +185,8 @@ def test_200(self): self.assertEqual(status, 200) self.email_storage.fetch_object.assert_called_once_with(email_id) - self.mailbox_storage.store_text.assert_called_once_with( - 'foo.lokole.ca/foo@foo.lokole.ca/sent/2019-10-26 22:47/123', 'indexed') + self.mailbox_storage.store_text.assert_called_once_with('foo.lokole.ca/foo@foo.lokole.ca/sent/527869980/123', + 'indexed') def _execute_action(self, *args, **kwargs): action = actions.IndexSentEmailForMailbox( diff --git a/tests/opwen_email_server/utils/test_email_parser.py b/tests/opwen_email_server/utils/test_email_parser.py index ca10e44b..42c34924 100644 --- a/tests/opwen_email_server/utils/test_email_parser.py +++ b/tests/opwen_email_server/utils/test_email_parser.py @@ -289,3 +289,62 @@ def test_format_attachments_with_image(self): self.assertNotEqual(input_content, output_content) self.assertEqual(input_filename, output_filename) + + +class DescendingTimestampTests(TestCase): + def test_descending_timestamp_correct(self): + sent_at = '2020-02-01 21:09' + + sent_at_timestamp = email_parser.descending_timestamp(sent_at) + + self.assertEqual(sent_at_timestamp, '519408660') + + def test_descending_timestamp_order_by_year(self): + january_2020 = '2020-01-01 22:09' + january_2021 = '2021-01-01 22:09' + + january_2020_timestamp = email_parser.descending_timestamp(january_2020) + january_2021_timestamp = email_parser.descending_timestamp(january_2021) + + timestamp_ordering = sorted([january_2020_timestamp, january_2021_timestamp]) + self.assertEqual(timestamp_ordering, [january_2021_timestamp, january_2020_timestamp]) + + def test_descending_timestamp_order_by_month(self): + january = '2020-01-01 22:09' + february = '2020-02-02 22:09' + + january_timestamp = email_parser.descending_timestamp(january) + february_timestamp = email_parser.descending_timestamp(february) + + timestamp_ordering = sorted([january_timestamp, february_timestamp]) + self.assertEqual(timestamp_ordering, [february_timestamp, january_timestamp]) + + def test_descending_timestamp_order_by_day(self): + january_1st = '2020-01-01 22:09' + january_2nd = '2020-01-02 22:09' + + january_1_timestamp = email_parser.descending_timestamp(january_1st) + january_2_timestamp = email_parser.descending_timestamp(january_2nd) + + timestamp_ordering = sorted([january_1_timestamp, january_2_timestamp]) + self.assertEqual(timestamp_ordering, [january_2_timestamp, january_1_timestamp]) + + def test_descending_timestamp_order_by_hour(self): + january_1st_22h09m = '2020-01-01 22:09' + january_1st_23h09m = '2020-01-01 23:09' + + january_22h09m_timestamp = email_parser.descending_timestamp(january_1st_22h09m) + january_23h09m_timestamp = email_parser.descending_timestamp(january_1st_23h09m) + + timestamp_ordering = sorted([january_22h09m_timestamp, january_23h09m_timestamp]) + self.assertEqual(timestamp_ordering, [january_23h09m_timestamp, january_22h09m_timestamp]) + + def test_descending_timestamp_order_by_minute(self): + january_1st_22h09m = '2020-01-01 22:09' + january_1st_22h11m = '2020-01-01 22:11' + + january_22h09m_timestamp = email_parser.descending_timestamp(january_1st_22h09m) + january_22h11m_timestamp = email_parser.descending_timestamp(january_1st_22h11m) + + timestamp_ordering = sorted([january_22h09m_timestamp, january_22h11m_timestamp]) + self.assertEqual(timestamp_ordering, [january_22h11m_timestamp, january_22h09m_timestamp])