Skip to content

Commit

Permalink
Delete indices with client (#307)
Browse files Browse the repository at this point in the history
* Clean up mailbox indices on client deletion

* Clean up pending index on client deletion
  • Loading branch information
c-w authored Jan 30, 2020
1 parent c1d7f07 commit e655daf
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 7 deletions.
15 changes: 13 additions & 2 deletions opwen_email_server/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ def _action(self, resource_id): # type: ignore
email = self._email_storage.fetch_object(resource_id)

for email_address in self._get_pivot(email):
index = f"{email_address}/{self._folder}/{email['sent_at']}/{resource_id}"
domain = get_domain(email_address)
index = f"{domain}/{email_address}/{self._folder}/{email['sent_at']}/{resource_id}"
self._mailbox_storage.store_text(index, 'indexed')

self.log_event(events.MAILBOX_EMAIL_INDEXED, {'folder': self._folder}) # noqa: E501 # yapf: disable
Expand Down Expand Up @@ -400,11 +401,14 @@ def _action(self, domain, **auth_args): # type: ignore

class DeleteClient(_Action):
def __init__(self, auth: AzureAuth, delete_mailbox: Callable[[str, str], None],
delete_mx_records: Callable[[str], None]):
delete_mx_records: Callable[[str], None], mailbox_storage: AzureTextStorage,
pending_storage: AzureTextStorage):

self._auth = auth
self._delete_mailbox = delete_mailbox
self._delete_mx_records = delete_mx_records
self._mailbox_storage = mailbox_storage
self._pending_storage = pending_storage

def _action(self, domain, **auth_args): # type: ignore
if not is_lowercase(domain):
Expand All @@ -419,11 +423,18 @@ def _action(self, domain, **auth_args): # type: ignore

self._delete_mailbox(client_id, domain)
self._delete_mx_records(domain)
self._delete_index(self._pending_storage, domain)
self._delete_index(self._mailbox_storage, domain)
self._auth.delete(client_id, domain)

self.log_event(events.CLIENT_DELETED, {'domain': domain}) # noqa: E501 # yapf: disable
return 'OK', 200

@classmethod
def _delete_index(cls, storage: AzureTextStorage, domain: str) -> None:
for prefix in storage.iter(f'{domain}/'):
storage.delete(f'{domain}/{prefix}')


class CalculateNumberOfUsersMetric(_Action):
def __init__(self, auth: AzureAuth, user_storage: AzureObjectStorage):
Expand Down
3 changes: 3 additions & 0 deletions opwen_email_server/integration/connexion.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from opwen_email_server.integration.azure import get_auth
from opwen_email_server.integration.azure import get_client_storage
from opwen_email_server.integration.azure import get_email_storage
from opwen_email_server.integration.azure import get_mailbox_storage
from opwen_email_server.integration.azure import get_pending_storage
from opwen_email_server.integration.azure import get_raw_email_storage
from opwen_email_server.integration.azure import get_user_storage
Expand Down Expand Up @@ -62,6 +63,8 @@
secret=config.DNS_SECRET,
provider=config.DNS_PROVIDER,
),
mailbox_storage=get_mailbox_storage(),
pending_storage=get_pending_storage(),
)

metrics_users = CalculateNumberOfUsersMetric(
Expand Down
7 changes: 5 additions & 2 deletions opwen_email_server/integration/webapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ def sent(self, email_address: str, page: int) -> Iterable[dict]:
return self._iter_mailbox(email_address, page, mailbox.SENT_FOLDER)

def _iter_mailbox(self, email_address: str, page: int, folder: str) -> Iterable[dict]:
emails = self._mailbox_storage.iter(f'{email_address}/{folder}')
domain = get_domain(email_address)
emails = self._mailbox_storage.iter(f'{domain}/{email_address}/{folder}')
for i, resource_ids in enumerate(chunks(emails, AppConfig.EMAILS_PER_PAGE), start=1):
if i != page:
continue
Expand All @@ -220,6 +221,8 @@ def num_pending(self) -> int:
return 0

def _delete(self, email_address: str, uids: Iterable[str]):
domain = get_domain(email_address)

for uid in uids:
email = self.get(uid)
if not email:
Expand All @@ -232,7 +235,7 @@ def _delete(self, email_address: str, uids: Iterable[str]):
else:
continue

self._mailbox_storage.delete(f"{email_address}/{folder}/{email['sent_at']}/{uid}")
self._mailbox_storage.delete(f"{domain}/{email_address}/{folder}/{email['sent_at']}/{uid}")
self._email_storage.delete(uid)

def _mark_sent(self, uids: Iterable[str]):
Expand Down
23 changes: 20 additions & 3 deletions tests/opwen_email_server/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,10 @@ 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('1@bar.lokole.ca/received/2019-10-26 22:47/123', 'indexed')
self.mailbox_storage.store_text.assert_any_call('2@baz.lokole.ca/received/2019-10-26 22:47/123', 'indexed')
self.mailbox_storage.store_text.assert_any_call('bar.lokole.ca/1@bar.lokole.ca/received/2019-10-26 22:47/123',
'indexed')
self.mailbox_storage.store_text.assert_any_call('baz.lokole.ca/2@baz.lokole.ca/received/2019-10-26 22:47/123',
'indexed')
self.assertEqual(self.mailbox_storage.store_text.call_count, 2)

def _execute_action(self, *args, **kwargs):
Expand Down Expand Up @@ -183,7 +185,7 @@ 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@foo/sent/2019-10-26 22:47/123', 'indexed')
self.mailbox_storage.store_text.assert_called_once_with('foo/foo@foo/sent/2019-10-26 22:47/123', 'indexed')

def _execute_action(self, *args, **kwargs):
action = actions.IndexSentEmailForMailbox(
Expand Down Expand Up @@ -633,6 +635,8 @@ def setUp(self):
self.auth = Mock()
self.delete_mailbox = MagicMock()
self.delete_mx_records = MagicMock()
self.mailbox_storage = Mock()
self.pending_storage = Mock()

def test_400(self):
domain = 'TEST.com'
Expand Down Expand Up @@ -674,6 +678,8 @@ def test_200(self):

self.auth.client_id_for.return_value = client_id
self.auth.is_owner.return_value = True
self.mailbox_storage.iter.return_value = ['1/2/a', '1/2/b']
self.pending_storage.iter.return_value = ['c', 'd', 'e']

_, status = self._execute_action(domain, user=user)

Expand All @@ -683,12 +689,23 @@ def test_200(self):
self.auth.delete.assert_called_once_with(client_id, domain)
self.delete_mailbox.assert_called_once_with(client_id, domain)
self.delete_mx_records.assert_called_once_with(domain)
self.mailbox_storage.iter.assert_called_once_with(f'{domain}/')
self.mailbox_storage.delete.assert_any_call(f'{domain}/1/2/a')
self.mailbox_storage.delete.assert_any_call(f'{domain}/1/2/b')
self.assertEqual(self.mailbox_storage.delete.call_count, 2)
self.pending_storage.iter.assert_called_once_with(f'{domain}/')
self.pending_storage.delete.assert_any_call(f'{domain}/c')
self.pending_storage.delete.assert_any_call(f'{domain}/d')
self.pending_storage.delete.assert_any_call(f'{domain}/e')
self.assertEqual(self.pending_storage.delete.call_count, 3)

def _execute_action(self, *args, **kwargs):
action = actions.DeleteClient(
auth=self.auth,
delete_mailbox=self.delete_mailbox,
delete_mx_records=self.delete_mx_records,
mailbox_storage=self.mailbox_storage,
pending_storage=self.pending_storage,
)

return action(*args, **kwargs)
Expand Down

0 comments on commit e655daf

Please sign in to comment.