Skip to content

Commit 6943f44

Browse files
committed
refactor: centralize error handling with dedicated exception functions
1 parent a0e3da3 commit 6943f44

2 files changed

Lines changed: 121 additions & 102 deletions

File tree

app/bss/adapters/portaswitch/adapter.py

Lines changed: 49 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@
3838
from report_error import WebTritErrorException
3939
from .api import AccountAPI, AdminAPI
4040
from .config import Settings
41+
from .exceptions import (
42+
method_not_found_error,
43+
external_api_issue_error,
44+
not_found_user_error,
45+
not_found_otp_code_error,
46+
not_found_contact_error,
47+
not_found_recording_error,
48+
incorrect_credentials_error,
49+
user_authentication_error,
50+
delivery_channel_unspecified_error,
51+
password_change_required_error,
52+
access_token_expired_error,
53+
access_token_invalid_error,
54+
unsupported_file_format_error,
55+
missing_tokens_error,
56+
session_close_error,
57+
refresh_token_invalid_error,
58+
addon_required_error,
59+
)
4160
from .serializer import Serializer
4261
from .types import (
4362
PortaSwitchSignInCredentialsType,
@@ -132,7 +151,7 @@ def authenticate(self, user: UserInfo, password: str = None) -> SessionInfo:
132151
account_info = self._admin_api.get_account_info(i_account=master_id).get("account_info")
133152

134153
if not account_info or account_info[password_attr] != password:
135-
raise WebTritErrorException(401, "User authentication error", code="incorrect_credentials")
154+
raise incorrect_credentials_error()
136155

137156
if self._portaswitch_settings.ALLOWED_ADDONS:
138157
self._check_allowed_addons(account_info)
@@ -153,10 +172,7 @@ def authenticate(self, user: UserInfo, password: str = None) -> SessionInfo:
153172
"Server.Session.cannot_login_brute_force_activity",
154173
"Client.Session.check_auth.failed_to_process_access_token",
155174
):
156-
raise WebTritErrorException(
157-
status_code=401,
158-
error_message="User authentication error",
159-
)
175+
raise user_authentication_error()
160176

161177
raise error
162178

@@ -177,15 +193,15 @@ def generate_otp(self, user: UserInfo) -> OTPCreateResponse:
177193
try:
178194
account_info = self._admin_api.get_account_info(id=user.user_id).get("account_info")
179195
if not account_info:
180-
raise WebTritErrorException(404, f"There is no an account with such id: {user.user_id}")
196+
raise not_found_user_error(user.user_id)
181197

182198
if self._portaswitch_settings.ALLOWED_ADDONS:
183199
self._check_allowed_addons(account_info)
184200

185201
i_account = account_info.get("i_master_account", account_info["i_account"])
186202
success: int = self._admin_api.create_otp(i_account, self.OTP_DELIVERY_CHANNEL)["success"]
187203
if not success:
188-
raise WebTritErrorException(500, "Unknown error", code="external_api_issue")
204+
raise external_api_issue_error()
189205

190206
otp_id: str = generate_otp_id()
191207
self._cached_otp_ids[otp_id] = i_account, user.user_id
@@ -199,7 +215,7 @@ def generate_otp(self, user: UserInfo) -> OTPCreateResponse:
199215
except WebTritErrorException as error:
200216
fault_code = extract_fault_code(error)
201217
if fault_code in ("Server.AccessControl.empty_rec_and_bcc",):
202-
raise WebTritErrorException(422, "Delivery channel unspecified", code="delivery_channel_unspecified")
218+
raise delivery_channel_unspecified_error()
203219

204220
raise error
205221

@@ -222,11 +238,11 @@ def validate_otp(self, otp: OTPVerifyRequest) -> SessionInfo:
222238

223239
(i_account, user_ref) = self._cached_otp_ids.get(otp_id, (None, None))
224240
if not i_account:
225-
raise WebTritErrorException(status_code=404, error_message=f"Incorrect OTP code: {otp.code}")
241+
raise not_found_otp_code_error(otp.code)
226242

227243
data: dict = self._admin_api.verify_otp(otp_token=otp.code)
228244
if user_ref not in self._otp_settings.IGNORE_ACCOUNTS and not data["success"]:
229-
raise WebTritErrorException(status_code=404, error_message=f"Incorrect OTP code: {otp.code}")
245+
raise not_found_otp_code_error(otp.code)
230246

231247
self._cached_otp_ids.pop(otp_id)
232248

@@ -244,12 +260,7 @@ def validate_otp(self, otp: OTPVerifyRequest) -> SessionInfo:
244260
except WebTritErrorException as error:
245261
fault_code = extract_fault_code(error)
246262
if fault_code in ("Server.Session.alert_You_must_change_password",):
247-
raise WebTritErrorException(
248-
status_code=422,
249-
# code = OTPUserDataErrorCode.validation_error,
250-
error_message="Failed to perform authentication using this account."
251-
"Try changing this account web-password.",
252-
)
263+
raise password_change_required_error()
253264

254265
raise error
255266

@@ -271,17 +282,9 @@ def validate_session(self, access_token: str) -> SessionInfo:
271282

272283
return SessionInfo(user_id=UserId(user_id), access_token=AccessToken(access_token))
273284
except ExpiredSignatureError:
274-
raise WebTritErrorException(
275-
status_code=401,
276-
error_message=f"Access token expired",
277-
code="access_token_expired",
278-
)
285+
raise access_token_expired_error()
279286
except JWTError:
280-
raise WebTritErrorException(
281-
status_code=401,
282-
error_message="Access token invalid",
283-
code="access_token_invalid",
284-
)
287+
raise access_token_invalid_error()
285288

286289
def refresh_session(self, refresh_token: str) -> SessionInfo:
287290
"""Refreshes the PortaSwitch account session.
@@ -311,11 +314,7 @@ def refresh_session(self, refresh_token: str) -> SessionInfo:
311314
"Server.Session.refresh_access_token.refresh_failed",
312315
"Client.Session.check_auth.failed_to_process_access_token",
313316
):
314-
raise WebTritErrorException(
315-
status_code=422,
316-
code="refresh_token_invalid",
317-
error_message=f"Invalid refresh token",
318-
)
317+
raise refresh_token_invalid_error()
319318

320319
raise error
321320

@@ -337,10 +336,7 @@ def close_session(self, access_token: str) -> bool:
337336
except WebTritErrorException as error:
338337
fault_code = extract_fault_code(error)
339338
if fault_code in ("Client.Session.logout.failed_to_process_access_token",):
340-
raise WebTritErrorException(
341-
status_code=422,
342-
error_message=f"Error closing the session",
343-
)
339+
raise session_close_error()
344340

345341
raise error
346342

@@ -378,11 +374,7 @@ def retrieve_user(self, session: SessionInfo, user: UserInfo) -> EndUser:
378374
except WebTritErrorException as error:
379375
fault_code = extract_fault_code(error)
380376
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
381-
raise WebTritErrorException(
382-
status_code=401,
383-
error_message="Access token expired",
384-
code="access_token_expired",
385-
)
377+
raise access_token_expired_error()
386378

387379
raise error
388380

@@ -525,11 +517,7 @@ def retrieve_contacts(self, session: SessionInfo, user: UserInfo) -> list[Contac
525517
except WebTritErrorException as error:
526518
fault_code = extract_fault_code(error)
527519
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
528-
raise WebTritErrorException(
529-
status_code=401,
530-
error_message="Access token expired",
531-
code="access_token_expired",
532-
)
520+
raise access_token_expired_error()
533521

534522
raise error
535523

@@ -908,11 +896,7 @@ def retrieve_contacts_v2(
908896
except WebTritErrorException as error:
909897
fault_code = extract_fault_code(error)
910898
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
911-
raise WebTritErrorException(
912-
status_code=401,
913-
error_message="Access token expired",
914-
code="access_token_expired",
915-
)
899+
raise access_token_expired_error()
916900

917901
raise error
918902

@@ -932,8 +916,7 @@ def retrieve_contact_by_user_id(self, session: SessionInfo, user: UserInfo, user
932916
"""
933917
account_info = self._admin_api.get_account_info(i_account=int(user_id)).get("account_info")
934918
if not account_info:
935-
raise WebTritErrorException(404, f"There is no an account with such id: {user_id}",
936-
code="contact_not_found")
919+
raise not_found_contact_error(user_id)
937920

938921
return Serializer.get_contact_info_by_account(account_info, int(user.user_id))
939922

@@ -980,11 +963,7 @@ def retrieve_calls(
980963
except WebTritErrorException as error:
981964
fault_code = extract_fault_code(error)
982965
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
983-
raise WebTritErrorException(
984-
status_code=401,
985-
error_message="Access token expired",
986-
code="access_token_expired",
987-
)
966+
raise access_token_expired_error()
988967

989968
raise error
990969

@@ -1002,20 +981,16 @@ def retrieve_call_recording(self, session: SessionInfo, call_recording: CallReco
1002981
Raises:
1003982
WebTritErrorException: If the recording is not found or the ID is invalid.
1004983
"""
984+
recording_id = safely_extract_scalar_value(call_recording)
1005985
try:
1006-
recording_id = safely_extract_scalar_value(call_recording)
1007-
1008986
return self._account_api.get_call_recording(
1009987
access_token=safely_extract_scalar_value(session.access_token), recording_id=recording_id
1010988
)
1011989

1012990
except WebTritErrorException as error:
1013991
fault_code = extract_fault_code(error)
1014992
if fault_code in ("Server.CDR.xdr_not_found", "Server.CDR.invalid_call_recording_id",):
1015-
raise WebTritErrorException(
1016-
status_code=404,
1017-
error_message="The recording with such a recording_id is not found.",
1018-
)
993+
raise not_found_recording_error(recording_id)
1019994

1020995
raise error
1021996

@@ -1045,11 +1020,7 @@ def retrieve_voicemails(self, session: SessionInfo, user: UserInfo) -> UserVoice
10451020
except WebTritErrorException as error:
10461021
fault_code = extract_fault_code(error)
10471022
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
1048-
raise WebTritErrorException(
1049-
status_code=401,
1050-
error_message="Access token expired",
1051-
code="access_token_expired",
1052-
)
1023+
raise access_token_expired_error()
10531024

10541025
raise error
10551026

@@ -1079,11 +1050,7 @@ def retrieve_voicemail_message_details(
10791050
except WebTritErrorException as error:
10801051
fault_code = extract_fault_code(error)
10811052
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
1082-
raise WebTritErrorException(
1083-
status_code=401,
1084-
error_message="Access token expired",
1085-
code="access_token_expired",
1086-
)
1053+
raise access_token_expired_error()
10871054

10881055
raise error
10891056

@@ -1104,7 +1071,7 @@ def retrieve_voicemail_message_attachment(
11041071

11051072
file_format = file_format and file_format.lower()
11061073
if file_format and not PortaSwitchMailboxMessageAttachmentFormat.has_value(file_format):
1107-
raise WebTritErrorException(422, "Not supported file format", code="unsupported_file_format")
1074+
raise unsupported_file_format_error()
11081075

11091076
try:
11101077
return self._account_api.get_mailbox_message_attachment(
@@ -1116,11 +1083,7 @@ def retrieve_voicemail_message_attachment(
11161083
except WebTritErrorException as error:
11171084
fault_code = extract_fault_code(error)
11181085
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
1119-
raise WebTritErrorException(
1120-
401,
1121-
error_message="Access token expired",
1122-
code="access_token_expired",
1123-
)
1086+
raise access_token_expired_error()
11241087

11251088
raise error
11261089

@@ -1155,11 +1118,7 @@ def patch_voicemail_message(
11551118
except WebTritErrorException as error:
11561119
fault_code = extract_fault_code(error)
11571120
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
1158-
raise WebTritErrorException(
1159-
401,
1160-
error_message="Access token expired",
1161-
code="access_token_expired",
1162-
)
1121+
raise access_token_expired_error()
11631122

11641123
raise error
11651124

@@ -1179,11 +1138,7 @@ def delete_voicemail_message(self, session: SessionInfo, message_id: str) -> Non
11791138
except WebTritErrorException as error:
11801139
fault_code = extract_fault_code(error)
11811140
if fault_code in ("Client.Session.check_auth.failed_to_process_access_token",):
1182-
raise WebTritErrorException(
1183-
401,
1184-
error_message="Access token expired",
1185-
code="access_token_expired",
1186-
)
1141+
raise access_token_expired_error()
11871142

11881143
raise error
11891144

@@ -1233,7 +1188,7 @@ def signup(self, user_data, tenant_id: str = None) -> SessionResponse:
12331188
refresh_token = user_data.get("refresh_token")
12341189

12351190
if not access_token or not refresh_token:
1236-
raise WebTritErrorException(422, "Missing required access or refresh token parameters")
1191+
raise missing_tokens_error()
12371192

12381193
try:
12391194
account_info = self._account_api.get_account_info(access_token=access_token)["account_info"]
@@ -1245,11 +1200,7 @@ def signup(self, user_data, tenant_id: str = None) -> SessionResponse:
12451200
)
12461201
except WebTritErrorException as error:
12471202
if extract_fault_code(error) == "Client.Session.check_auth.failed_to_process_access_token":
1248-
raise WebTritErrorException(
1249-
401,
1250-
error_message="Access token expired",
1251-
code="access_token_expired",
1252-
)
1203+
raise access_token_expired_error()
12531204

12541205
raise error
12551206

@@ -1267,9 +1218,7 @@ def custom_method_public(
12671218

12681219
return method(data=data, lang=lang)
12691220
else:
1270-
raise WebTritErrorException(
1271-
status_code=404, error_message=f"Method '{method_name}' not found", code="method_not_found"
1272-
)
1221+
raise method_not_found_error(method_name)
12731222

12741223
def custom_method_private(
12751224
self,
@@ -1287,9 +1236,7 @@ def custom_method_private(
12871236

12881237
return method(user_id=user_id, data=data, lang=lang)
12891238
else:
1290-
raise WebTritErrorException(
1291-
status_code=404, error_message=f"Method '{method_name}' not found", code="method_not_found"
1292-
)
1239+
raise method_not_found_error(method_name)
12931240

12941241
# region custom methods handlers
12951242

@@ -1345,7 +1292,7 @@ def _check_allowed_addons(self, account_info: dict):
13451292
logging.info(f"Check add-ons {assigned_addon_names} for access. Allowed add-ons: {allowed_addons}")
13461293

13471294
if not allowed_addons.intersection(assigned_addon_names):
1348-
raise WebTritErrorException(403, "Access denied: required add-on not assigned", code="addon_required")
1295+
raise addon_required_error()
13491296

13501297
def _get_number_to_customer_accounts_map_for_numbers(self, target_numbers: set[str]) -> dict[str, dict]:
13511298
"""Return a mapping of phone numbers to customer accounts, optimized for specific numbers.

0 commit comments

Comments
 (0)