Add ftl_id to RelayAPIException

Instead of deriving the FTL ID from the default_code, add it explictly
to the RelayAPIException or derived class. This makes it easier to
cross-reference misc.ftl with the exceptions, and verify that a
translation is in use.
This commit is contained in:
John Whitlock 2024-09-05 14:40:28 -05:00
Родитель eb5b4e6a8b
Коммит 7002dc6f4a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 082C735D154FB750
2 изменённых файлов: 28 добавлений и 16 удалений

Просмотреть файл

@ -36,10 +36,11 @@ class RelayAPIException(APIException):
Base class for exceptions that may be returned through the API.
Derived classes should set `default_code` to a unique string identifying the
exception. There should be a matching Fluent string with an `api-error-`
prefix. For example, the Fluent string "api-error-free-tier-limit" matches
the exception class with the default_code "free-tier-limit". These Fluent
strings are in misc.ftl.
exception. The `ftl_id` should be a matching Fluent string with an `api-error-`
prefix. For example, the `ftl_id` "api-error-free-tier-limit" matches
the exception class with the `default_code` "free-tier-limit". These Fluent
strings are in misc.ftl. While the `ftl_id` _could_ be constructed from the
`default_code`, it is included as a cross-referencing aid.
Derived classes can set `default_detail` to a human-readable string, or they
can set `default_detail_template` to dynamically create the string from extra
@ -53,6 +54,7 @@ class RelayAPIException(APIException):
default_code: str
default_detail: str
status_code: int
ftl_id: str
def __init__(
self, detail: _APIExceptionInput = None, code: str | None = None
@ -69,8 +71,20 @@ class RelayAPIException(APIException):
self.default_detail = self.default_detail_template.format(**context)
if not isinstance(self.default_detail, str):
raise TypeError("self.default_detail must be type str")
if not isinstance(self.ftl_id, str):
raise TypeError("self.ftl_id must be type str")
super().__init__(detail, code)
# Validated the Fluent error ID ftl_id
error_code = self.get_codes()
if not isinstance(error_code, str):
raise TypeError("error_code must be type str")
ftl_id_sub = "api-error-"
ftl_id_error = error_code.replace("_", "-")
expected_ftl_id = ftl_id_sub + ftl_id_error
if expected_ftl_id != self.ftl_id:
raise ValueError(f'ftl_id is "{self.ftl_id}", expected "{expected_ftl_id}"')
def error_context(self) -> ErrorContextType:
"""Return context variables for client-side translation."""
return {}
@ -78,21 +92,11 @@ class RelayAPIException(APIException):
def error_data(self) -> ErrorData:
"""Return extra data for API error responses."""
# For RelayAPIException classes, this is the default_code and is a string
error_code = self.get_codes()
if not isinstance(error_code, str):
raise TypeError("error_code must be type str")
# Build the Fluent error ID
ftl_id_sub = "api-error-"
ftl_id_error = error_code.replace("_", "-")
ftl_id = ftl_id_sub + ftl_id_error
# Replace the default message with the translated Fluent string
error_context = self.error_context()
translated_detail = ftl_bundle.format(ftl_id, error_context)
translated_detail = ftl_bundle.format(self.ftl_id, error_context)
error_data = ErrorData(detail=translated_detail, error_code=error_code)
error_data = ErrorData(detail=translated_detail, error_code=self.get_codes())
if error_context:
error_data["error_context"] = error_context
return error_data

Просмотреть файл

@ -12,12 +12,14 @@ class CannotMakeAddressException(RelayAPIException):
class AccountIsPausedException(CannotMakeAddressException):
default_code = "account_is_paused"
default_detail = "Your account is on pause."
ftl_id = "api-error-account-is-paused"
status_code = 403
class AccountIsInactiveException(CannotMakeAddressException):
default_code = "account_is_inactive"
default_detail = "Your account is not active."
ftl_id = "api-error-account-is-inactive"
status_code = 403
@ -28,6 +30,7 @@ class RelayAddrFreeTierLimitException(CannotMakeAddressException):
" You can reuse an existing mask, but using a unique mask for each account is"
" the most secure option."
)
ftl_id = "api-error-free-tier-limit"
status_code = 403
def __init__(self, free_tier_limit: int | None = None):
@ -44,12 +47,14 @@ class DomainAddrFreeTierException(CannotMakeAddressException):
"Your free account does not include custom subdomains for masks."
" To create custom masks, upgrade to Relay Premium."
)
ftl_id = "api-error-free-tier-no-subdomain-masks"
status_code = 403
class DomainAddrNeedSubdomainException(CannotMakeAddressException):
default_code = "need_subdomain"
default_detail = "Please select a subdomain before creating a custom email address."
ftl_id = "api-error-need-subdomain"
status_code = 400
@ -58,6 +63,7 @@ class DomainAddrUpdateException(CannotMakeAddressException):
default_code = "address_not_editable"
default_detail = "You cannot edit an existing domain address field."
ftl_id = "api-error-address-not-editable"
status_code = 400
@ -67,6 +73,7 @@ class DomainAddrUnavailableException(CannotMakeAddressException):
"{unavailable_address}” could not be created."
" Please try again with a different mask name."
)
ftl_id = "api-error-address-unavailable"
status_code = 400
def __init__(self, unavailable_address: str):
@ -83,6 +90,7 @@ class DomainAddrDuplicateException(CannotMakeAddressException):
"{duplicate_address}” already exists."
" Please try again with a different mask name."
)
ftl_id = "api-error-duplicate-address"
status_code = 409
def __init__(self, duplicate_address: str):