mailbox-org-api 2.4__tar.gz → 2.5.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/PKG-INFO +1 -1
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api/APIClient.py +75 -47
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api.egg-info/PKG-INFO +1 -1
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/pyproject.toml +1 -1
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/setup.py +1 -1
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/tests/TestAPIClient.py +7 -3
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/LICENSE +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/README.md +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api/APIError.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api/Account.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api/Invoice.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api/Mail.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api/__init__.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api.egg-info/SOURCES.txt +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api.egg-info/dependency_links.txt +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/mailbox_org_api.egg-info/top_level.txt +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/setup.cfg +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/tests/TestAccount.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/tests/TestInvoice.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/tests/TestMail.py +0 -0
- {mailbox_org_api-2.4 → mailbox_org_api-2.5.1}/tests/__init__.py +0 -0
|
@@ -24,7 +24,7 @@ class APIClient:
|
|
|
24
24
|
Object for API Client
|
|
25
25
|
"""
|
|
26
26
|
|
|
27
|
-
def __init__(self, debug_output=False, max_retries=5):
|
|
27
|
+
def __init__(self, debug_output=False, max_retries=5, request_timeout: int = 30):
|
|
28
28
|
# URL of the API
|
|
29
29
|
self.url = "https://api.mailbox.org/v1/"
|
|
30
30
|
|
|
@@ -60,6 +60,8 @@ class APIClient:
|
|
|
60
60
|
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
61
61
|
self.session.mount('https://', adapter)
|
|
62
62
|
|
|
63
|
+
self.request_timeout = request_timeout
|
|
64
|
+
|
|
63
65
|
# Increment the request ID
|
|
64
66
|
def get_jsonrpc_id(self):
|
|
65
67
|
"""Method to create the JSON RPC request ID. """
|
|
@@ -90,20 +92,26 @@ class APIClient:
|
|
|
90
92
|
# Check if any parameter is 'password' or 'pass'.
|
|
91
93
|
# Check explicit for these strings as not to interfere with possible other
|
|
92
94
|
# parameters containing a substring.
|
|
95
|
+
sensitive_keys = ['password', 'pass', 'password_hash', 'new_account_password', 'token',
|
|
96
|
+
'HPLS-AUTH', 'auth_id', 'telephone_password']
|
|
93
97
|
for param in print_request['params']:
|
|
94
|
-
if param
|
|
95
|
-
# If True, replace the logged value with 'xxx'
|
|
98
|
+
if param in sensitive_keys:
|
|
96
99
|
print_request['params'][param] = 'xxx'
|
|
97
100
|
|
|
98
101
|
# Print the clean version of the request
|
|
99
102
|
print('API full request:\t', print_request)
|
|
100
103
|
|
|
101
|
-
api_response = self.session.post(self.url, data=json.dumps(request))
|
|
102
104
|
try:
|
|
103
|
-
|
|
105
|
+
response = self.session.post(self.url, json=request, timeout=self.request_timeout)
|
|
106
|
+
response.raise_for_status()
|
|
104
107
|
except RequestException as error:
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
raise APIError(message=f"HTTP request failed: {error}", code=-32000) from error
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
api_response = response.json()
|
|
112
|
+
except (ValueError, requests.exceptions.JSONDecodeError) as error:
|
|
113
|
+
print(f'API Full response: {response.content}')
|
|
114
|
+
raise APIError(message="Non-JSON response received from API", code=-32700) from error
|
|
107
115
|
if self.debug_output:
|
|
108
116
|
print('API full response:\t', api_response)
|
|
109
117
|
|
|
@@ -150,8 +158,9 @@ class APIClient:
|
|
|
150
158
|
api_response = self.api_request('deauth', {})
|
|
151
159
|
if api_response:
|
|
152
160
|
# The auth header is stripped
|
|
153
|
-
self.session.headers.pop("HPLS-AUTH")
|
|
161
|
+
self.session.headers.pop("HPLS-AUTH", None)
|
|
154
162
|
self.auth_id = None
|
|
163
|
+
self.level = None
|
|
155
164
|
self.session.close()
|
|
156
165
|
return api_response
|
|
157
166
|
|
|
@@ -283,22 +292,25 @@ class APIClient:
|
|
|
283
292
|
"""
|
|
284
293
|
Function to get a specific invoice object for an account
|
|
285
294
|
:param account: the account name
|
|
286
|
-
:param invoice_id: the
|
|
295
|
+
:param invoice_id: the ID of the invoice to request
|
|
287
296
|
:return: the invoice as an Invoice object
|
|
288
297
|
"""
|
|
289
298
|
# Get all invoices for the account
|
|
290
299
|
invoice_list = self.account_invoice_list(account)
|
|
291
300
|
|
|
292
|
-
#
|
|
293
|
-
invoice
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
# Iterate over all invoices and create an object if the ID matches
|
|
302
|
+
for invoice in invoice_list:
|
|
303
|
+
if invoice['invoice_id'] == invoice_id:
|
|
304
|
+
# Initialize the Invoice object
|
|
305
|
+
invoice = Invoice(account, invoice_id)
|
|
306
|
+
# Retrieve the other data for the invoice from the invoice list
|
|
307
|
+
for i in invoice_list:
|
|
308
|
+
if i['invoice_id'] == invoice_id:
|
|
309
|
+
invoice.date = i['date']
|
|
310
|
+
invoice.status = i['status']
|
|
311
|
+
invoice.token = i['token']
|
|
312
|
+
return invoice
|
|
313
|
+
raise ValueError('Invoice not found')
|
|
302
314
|
|
|
303
315
|
def account_invoice_get_list(self, account: str) -> list:
|
|
304
316
|
"""
|
|
@@ -584,7 +596,7 @@ class APIClient:
|
|
|
584
596
|
if 'password' in kwargs and 'password_hash' in kwargs:
|
|
585
597
|
raise KeyError('''Simultaneous usage of 'password' and 'password_hash' not allowed.''')
|
|
586
598
|
|
|
587
|
-
if 'additional_mail_quota' in kwargs or 'additional_cloud_quota' in kwargs and 'plan' not in kwargs:
|
|
599
|
+
if ('additional_mail_quota' in kwargs or 'additional_cloud_quota' in kwargs) and 'plan' not in kwargs:
|
|
588
600
|
raise KeyError('''If setting additional quota, 'plan' must be given.''')
|
|
589
601
|
|
|
590
602
|
# Check for each argument in kwargs if it is a valid function parameter.
|
|
@@ -618,7 +630,8 @@ class APIClient:
|
|
|
618
630
|
:param password: the password to set
|
|
619
631
|
:return: the response for the request
|
|
620
632
|
"""
|
|
621
|
-
return self.api_request('mail.set', {'mail': mail, 'password': password,
|
|
633
|
+
return self.api_request('mail.set', {'mail': mail, 'password': password,
|
|
634
|
+
'require_reset_password': True})
|
|
622
635
|
|
|
623
636
|
def mail_set_plan(self, mail: str, plan: str) -> dict:
|
|
624
637
|
"""
|
|
@@ -922,10 +935,16 @@ class APIClient:
|
|
|
922
935
|
if mail_addresses_to_add is None and mail_addresses_to_remove is None:
|
|
923
936
|
raise ValueError('mail_addresses_to_add or mail_addresses_to_remove are required')
|
|
924
937
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
938
|
+
raw_params = {
|
|
939
|
+
'group_id': group_id,
|
|
940
|
+
'display_name': display_name,
|
|
941
|
+
'mail_addresses_to_add': mail_addresses_to_add,
|
|
942
|
+
'mail_addresses_to_remove': mail_addresses_to_remove,
|
|
943
|
+
'account': account,
|
|
944
|
+
}
|
|
945
|
+
# Filter out any keys whose values are None so they aren't serialized as `null`
|
|
946
|
+
params = {k: v for k, v in raw_params.items() if v is not None}
|
|
947
|
+
|
|
929
948
|
return self.api_request('group.set', params)
|
|
930
949
|
|
|
931
950
|
def mail_passwordreset_listmethods(self, mail: str) -> dict:
|
|
@@ -1014,8 +1033,15 @@ class APIClient:
|
|
|
1014
1033
|
:param adminmail: admin email address of the mailing list (optional).
|
|
1015
1034
|
:return: the mailbox API response for the request - True if the mailing list was changed, error code otherwise.
|
|
1016
1035
|
"""
|
|
1017
|
-
|
|
1018
|
-
|
|
1036
|
+
raw_params = {
|
|
1037
|
+
'mailinglist': mailinglist,
|
|
1038
|
+
'account': account,
|
|
1039
|
+
'password': password,
|
|
1040
|
+
'adminmail': adminmail
|
|
1041
|
+
}
|
|
1042
|
+
# Filter out any keys whose values are None so they aren't serialized as `null`
|
|
1043
|
+
params = {k: v for k, v in raw_params.items() if v is not None}
|
|
1044
|
+
return self.api_request('mailinglist.set', params)
|
|
1019
1045
|
|
|
1020
1046
|
def mailinglist_del(self, mailinglist: str, account: str) -> dict:
|
|
1021
1047
|
"""
|
|
@@ -1066,21 +1092,26 @@ class APIClient:
|
|
|
1066
1092
|
:param spam_folder: name of the spam folder.
|
|
1067
1093
|
:return: the response for the request - True if adding was successful, error code otherwise.
|
|
1068
1094
|
"""
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1095
|
+
raw_params = {
|
|
1096
|
+
'new_account_mail': new_account_mail,
|
|
1097
|
+
'new_account_password': new_account_password,
|
|
1098
|
+
'parent_mail': parent_mail,
|
|
1099
|
+
'primary_address': primary_address,
|
|
1100
|
+
'mail_server': mail_server, 'mail_port': str(mail_port),
|
|
1101
|
+
'transport_server': transport_server,
|
|
1102
|
+
'transport_port': str(transport_port),
|
|
1103
|
+
'mail_secure': mail_secure,
|
|
1104
|
+
'mail_starttls': mail_starttls,
|
|
1105
|
+
'transport_secure': transport_secure,
|
|
1106
|
+
'transport_starttls': transport_starttls,
|
|
1107
|
+
'trash_folder': trash_folder,
|
|
1108
|
+
'sent_folder': sent_folder,
|
|
1109
|
+
'drafts_folder': drafts_folder,
|
|
1110
|
+
'spam_folder': spam_folder
|
|
1111
|
+
}
|
|
1112
|
+
# Filter out any keys whose values are None so they aren't serialized as `null`
|
|
1113
|
+
params = {k: v for k, v in raw_params.items() if v is not None}
|
|
1114
|
+
return self.api_request('additionalmailaccount.add', params)
|
|
1084
1115
|
|
|
1085
1116
|
def additionalmailaccount_delete(self, parent_mail: str, account_mail: str) -> dict:
|
|
1086
1117
|
"""
|
|
@@ -1111,16 +1142,13 @@ class APIClient:
|
|
|
1111
1142
|
{'delete_mail_accounts_and_domains': delete_mail_accounts_and_domains})
|
|
1112
1143
|
|
|
1113
1144
|
|
|
1114
|
-
def validate_params(allowed: dict, actual: dict) -> bool
|
|
1145
|
+
def validate_params(allowed: dict, actual: dict) -> bool:
|
|
1115
1146
|
for arg in actual:
|
|
1116
1147
|
if arg not in allowed:
|
|
1117
1148
|
raise ValueError(f'Parameter {arg} not a valid parameter.')
|
|
1118
|
-
|
|
1119
1149
|
if not isinstance(actual[arg], allowed[arg]):
|
|
1120
1150
|
raise TypeError(f'Attribute {arg} must be of type {str(allowed[arg])}. {str(type(actual[arg]))} given')
|
|
1121
|
-
|
|
1122
|
-
return True
|
|
1123
|
-
return None
|
|
1151
|
+
return True
|
|
1124
1152
|
|
|
1125
1153
|
|
|
1126
1154
|
def bool2str(state: bool) -> str:
|
|
@@ -379,6 +379,9 @@ class TestAPIClient:
|
|
|
379
379
|
api = APIClient.APIClient()
|
|
380
380
|
api.auth(api_test_user, api_test_pass)
|
|
381
381
|
mail = test_id + '@' + domain
|
|
382
|
+
|
|
383
|
+
# Ensure that the plan supports capabilities
|
|
384
|
+
api.mail_set_plan(mail, 'standard')
|
|
382
385
|
for i in capabilities:
|
|
383
386
|
api.mail_capabilities_set(mail, [i])
|
|
384
387
|
# The API returns a list of capabilities
|
|
@@ -406,7 +409,7 @@ class TestAPIClient:
|
|
|
406
409
|
api.auth(api_test_user, api_test_pass)
|
|
407
410
|
mails = api.mail_list(domain)
|
|
408
411
|
mail = mails[0]['mail']
|
|
409
|
-
plans = ['premium', '
|
|
412
|
+
plans = ['premium', 'standard']
|
|
410
413
|
for plan in plans:
|
|
411
414
|
api.mail_set_plan(mail, plan)
|
|
412
415
|
assert str(api.mail_get(mail)['plan']).lower() == plan
|
|
@@ -468,16 +471,17 @@ class TestAPIClient:
|
|
|
468
471
|
mail = test_id + '@' + domain
|
|
469
472
|
additional_mail_quota = 23
|
|
470
473
|
api.mail_set_additional_mail_quota(mail, additional_mail_quota)
|
|
471
|
-
assert
|
|
474
|
+
assert int(api.mail_get(mail)['additional_mail_quota']) == additional_mail_quota
|
|
472
475
|
api.deauth()
|
|
473
476
|
|
|
477
|
+
@pytest.mark.depends(name="test_mail_add")
|
|
474
478
|
def test_mail_set_additional_cloud_quota(self):
|
|
475
479
|
api = APIClient.APIClient()
|
|
476
480
|
api.auth(api_test_user, api_test_pass)
|
|
477
481
|
mail = test_id + '@' + domain
|
|
478
482
|
additional_cloud_quota = 42
|
|
479
483
|
api.mail_set_additional_cloud_quota(mail, additional_cloud_quota)
|
|
480
|
-
assert
|
|
484
|
+
assert int(api.mail_get(mail)['additional_cloud_quota']) == additional_cloud_quota
|
|
481
485
|
api.deauth()
|
|
482
486
|
|
|
483
487
|
@pytest.mark.depends(name="test_mail_add")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|