From 679e4fd05410e73419dcb5c8092e72c93c11b01b Mon Sep 17 00:00:00 2001 From: Baiheng Xie <874256269@qq.com> Date: Mon, 2 Feb 2026 17:36:21 +0800 Subject: [PATCH 1/3] refactor: relocate domain specific exceptions --- src/auth/exceptions.py | 31 +++++++++++++++++++++++++++++++ src/auth/rbac.py | 5 ++++- src/exceptions.py | 29 ----------------------------- tests/test_exceptions.py | 4 ++-- 4 files changed, 37 insertions(+), 32 deletions(-) create mode 100644 src/auth/exceptions.py diff --git a/src/auth/exceptions.py b/src/auth/exceptions.py new file mode 100644 index 0000000..0b9502e --- /dev/null +++ b/src/auth/exceptions.py @@ -0,0 +1,31 @@ +from collections.abc import Sequence + +from src.exceptions import BusinessException +from src.shared.errors import ErrorCode + + +class InvalidPasswordException(BusinessException): + def __init__(self, remaining_attempts: int): + super().__init__( + code=ErrorCode.AUTH_INVALID_PASSWORD, + msg=f"Invalid password, {remaining_attempts} attempts remaining", + data={"remaining_attempts": remaining_attempts}, + ) + + +class InsufficientPermissionException(BusinessException): + def __init__(self, required: Sequence[str]): + super().__init__( + code=ErrorCode.PERM_INSUFFICIENT, + msg="Insufficient permissions", + data={"required": list(required)}, + ) + + +class InsufficientRoleException(BusinessException): + def __init__(self, required: Sequence[str]): + super().__init__( + code=ErrorCode.ROLE_INSUFFICIENT, + msg="Insufficient roles", + data={"required": list(required)}, + ) diff --git a/src/auth/rbac.py b/src/auth/rbac.py index 50a790c..0698574 100644 --- a/src/auth/rbac.py +++ b/src/auth/rbac.py @@ -9,7 +9,10 @@ from src.audit.schemas import AuditAction, AuditResult from src.audit.service import extract_client_info from src.auth.models import Permission, Role, RolePermission, User, UserRole -from src.exceptions import InsufficientPermissionException, InsufficientRoleException +from src.auth.exceptions import ( + InsufficientPermissionException, + InsufficientRoleException, +) from src.session import get_session from . import current_user diff --git a/src/exceptions.py b/src/exceptions.py index c87db4a..0dc63d5 100644 --- a/src/exceptions.py +++ b/src/exceptions.py @@ -1,5 +1,3 @@ -from collections.abc import Sequence - from src.shared.errors import ErrorCode @@ -12,30 +10,3 @@ def __init__(self, code: ErrorCode, msg: str, data: dict | None = None): def __str__(self) -> str: return f"[{self.code}] {self.msg}" - - -class InvalidPasswordException(BusinessException): - def __init__(self, remaining_attempts: int): - super().__init__( - code=ErrorCode.AUTH_INVALID_PASSWORD, - msg=f"Invalid password, {remaining_attempts} attempts remaining", - data={"remaining_attempts": remaining_attempts}, - ) - - -class InsufficientPermissionException(BusinessException): - def __init__(self, required: Sequence[str]): - super().__init__( - code=ErrorCode.PERM_INSUFFICIENT, - msg="Insufficient permissions", - data={"required": list(required)}, - ) - - -class InsufficientRoleException(BusinessException): - def __init__(self, required: Sequence[str]): - super().__init__( - code=ErrorCode.ROLE_INSUFFICIENT, - msg="Insufficient roles", - data={"required": list(required)}, - ) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index e9f13e1..08fc359 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -1,12 +1,12 @@ import pytest from src.shared.errors import ErrorCode -from src.exceptions import ( - BusinessException, +from src.auth.exceptions import ( InsufficientPermissionException, InsufficientRoleException, InvalidPasswordException, ) +from src.exceptions import BusinessException @pytest.mark.parametrize( From 27220774d4e96e16e65194274f1496244593662d Mon Sep 17 00:00:00 2001 From: Baiheng Xie <874256269@qq.com> Date: Mon, 2 Feb 2026 17:52:37 +0800 Subject: [PATCH 2/3] refactor!: removed unused InvalidPasswordException --- src/auth/exceptions.py | 9 --------- src/shared/errors.py | 2 -- 2 files changed, 11 deletions(-) diff --git a/src/auth/exceptions.py b/src/auth/exceptions.py index 0b9502e..f892bf8 100644 --- a/src/auth/exceptions.py +++ b/src/auth/exceptions.py @@ -4,15 +4,6 @@ from src.shared.errors import ErrorCode -class InvalidPasswordException(BusinessException): - def __init__(self, remaining_attempts: int): - super().__init__( - code=ErrorCode.AUTH_INVALID_PASSWORD, - msg=f"Invalid password, {remaining_attempts} attempts remaining", - data={"remaining_attempts": remaining_attempts}, - ) - - class InsufficientPermissionException(BusinessException): def __init__(self, required: Sequence[str]): super().__init__( diff --git a/src/shared/errors.py b/src/shared/errors.py index fd160b8..81bc616 100644 --- a/src/shared/errors.py +++ b/src/shared/errors.py @@ -3,7 +3,6 @@ class ErrorCode(IntEnum): AUTH_INVALID_CREDENTIALS = 10001 - AUTH_INVALID_PASSWORD = 10002 AUTH_TOKEN_INVALID = 10004 AUTH_ACCOUNT_LOCKED = 10005 @@ -23,7 +22,6 @@ class ErrorCode(IntEnum): ERROR_CODE_TO_HTTP = { ErrorCode.AUTH_INVALID_CREDENTIALS: 401, - ErrorCode.AUTH_INVALID_PASSWORD: 401, ErrorCode.AUTH_TOKEN_INVALID: 401, ErrorCode.AUTH_ACCOUNT_LOCKED: 403, ErrorCode.USER_NOT_FOUND: 404, From b73b257972354b6ad06e309c5cd4a3cc70a3b02f Mon Sep 17 00:00:00 2001 From: Baiheng Xie <874256269@qq.com> Date: Mon, 2 Feb 2026 17:55:35 +0800 Subject: [PATCH 3/3] fix: remove import --- tests/test_exceptions.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py index 08fc359..0c480a1 100644 --- a/tests/test_exceptions.py +++ b/tests/test_exceptions.py @@ -4,7 +4,6 @@ from src.auth.exceptions import ( InsufficientPermissionException, InsufficientRoleException, - InvalidPasswordException, ) from src.exceptions import BusinessException @@ -55,15 +54,6 @@ def test_business_exception_exposes_code_message_data_and_string( assert str(exc) == expected_str -def test_domain_exception_includes_remaining_attempts_in_message_and_data(): - exc = InvalidPasswordException(remaining_attempts=3) - - assert exc.code == ErrorCode.AUTH_INVALID_PASSWORD - assert exc.msg == "Invalid password, 3 attempts remaining" - assert exc.data == {"remaining_attempts": 3} - assert str(exc) == "[10002] Invalid password, 3 attempts remaining" - - def test_insufficient_permission_exception_includes_required_and_user_perms(): exc = InsufficientPermissionException(required=["admin:delete", "admin:create"])