Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ The same situation applies to both `client.batch_send()` and `client.sending_api
- Permissions listing – [`general/permissions.py`](examples/general/permissions.py)

### Organizations API:
- Sub-Accounts management – [`organizations/sub_accounts.py`](examples/organizations/sub_accounts.py)
- Sub-Accounts management (list, create, delete) – [`organizations/sub_accounts.py`](examples/organizations/sub_accounts.py)

## Contributing

Expand Down
8 changes: 8 additions & 0 deletions examples/organizations/sub_accounts.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os

import mailtrap as mt
from mailtrap.models.common import DeletedObject
from mailtrap.models.organizations import SubAccount

API_KEY = os.environ["MAILTRAP_API_KEY"]
Expand All @@ -18,9 +19,16 @@ def create_sub_account(name: str) -> SubAccount:
return sub_accounts_api.create(mt.CreateSubAccountParams(name=name))


def delete_sub_account(sub_account_id: int) -> DeletedObject:
return sub_accounts_api.delete(sub_account_id=sub_account_id)


if __name__ == "__main__":
sub_accounts = list_sub_accounts()
print(sub_accounts)

created = create_sub_account("New Team Account")
print(created)

deleted = delete_sub_account(created.id)
print(deleted)
25 changes: 23 additions & 2 deletions mailtrap/api/resources/sub_accounts.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from typing import Optional

from mailtrap.http import HttpClient
from mailtrap.models.common import DeletedObject
from mailtrap.models.organizations import CreateSubAccountParams
from mailtrap.models.organizations import SubAccount

Expand Down Expand Up @@ -27,5 +30,23 @@ def create(self, sub_account_params: CreateSubAccountParams) -> SubAccount:
)
return SubAccount(**response)

def _api_path(self) -> str:
return f"/api/organizations/{self._organization_id}/sub_accounts"
def delete(self, sub_account_id: int) -> DeletedObject:
"""
Delete a sub account of the organization. Requires sub account
management permissions for this organization.

The sub account and all of its data are removed permanently and cannot
be restored. Deleting the organization's last sub account also deletes
the organization. A repeated call for the same sub account returns
a 404 error.

Rate limit: 10 requests per minute per organization.
"""
self._client.delete(self._api_path(sub_account_id))
return DeletedObject(id=sub_account_id)

def _api_path(self, sub_account_id: Optional[int] = None) -> str:
path = f"/api/organizations/{self._organization_id}/sub_accounts"
if sub_account_id is not None:
return f"{path}/{sub_account_id}"
return path
57 changes: 57 additions & 0 deletions tests/unit/api/organizations/test_sub_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from mailtrap.config import GENERAL_HOST
from mailtrap.exceptions import APIError
from mailtrap.http import HttpClient
from mailtrap.models.common import DeletedObject
from mailtrap.models.organizations import CreateSubAccountParams
from mailtrap.models.organizations import SubAccount
from tests import conftest
Expand Down Expand Up @@ -152,3 +153,59 @@ def test_create_should_return_sub_account_and_wrap_body_under_account_key(
responses.calls[0].request.body
== b'{"account": {"name": "New Team Account"}}'
)

@pytest.mark.parametrize(
"status_code,response_json,expected_error_message",
[
(
conftest.UNAUTHORIZED_STATUS_CODE,
conftest.UNAUTHORIZED_RESPONSE,
conftest.UNAUTHORIZED_ERROR_MESSAGE,
),
(
conftest.FORBIDDEN_STATUS_CODE,
conftest.FORBIDDEN_RESPONSE,
conftest.FORBIDDEN_ERROR_MESSAGE,
),
(
conftest.NOT_FOUND_STATUS_CODE,
conftest.NOT_FOUND_RESPONSE,
conftest.NOT_FOUND_ERROR_MESSAGE,
),
(
conftest.RATE_LIMIT_ERROR_STATUS_CODE,
conftest.RATE_LIMIT_ERROR_RESPONSE,
conftest.RATE_LIMIT_ERROR_MESSAGE,
),
],
)
@responses.activate
def test_delete_should_raise_api_errors(
self,
client: SubAccountsApi,
status_code: int,
response_json: dict,
expected_error_message: str,
) -> None:
responses.delete(
f"{BASE_SUB_ACCOUNTS_URL}/{SUB_ACCOUNT_ID}",
status=status_code,
json=response_json,
)

with pytest.raises(APIError) as exc_info:
client.delete(SUB_ACCOUNT_ID)

assert expected_error_message in str(exc_info.value)

@responses.activate
def test_delete_should_return_deleted_object(self, client: SubAccountsApi) -> None:
responses.delete(
f"{BASE_SUB_ACCOUNTS_URL}/{SUB_ACCOUNT_ID}",
status=204,
)

result = client.delete(SUB_ACCOUNT_ID)

assert isinstance(result, DeletedObject)
assert result.id == SUB_ACCOUNT_ID
Loading