Files
orion/app/exceptions/team.py
Samir Boulahtit 238c1ec9b8 refactor: modernize code quality tooling with Ruff
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter)
- Add comprehensive pyproject.toml configuration
- Simplify Makefile code quality targets
- Configure exclusions for venv/.venv in pyproject.toml
- Auto-fix 1,359 linting issues across codebase

Benefits:
- Much faster builds (Ruff is written in Rust)
- Single tool replaces multiple tools
- More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q)
- All configuration centralized in pyproject.toml
- Better import sorting and formatting consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 19:37:38 +01:00

274 lines
8.1 KiB
Python

# app/exceptions/team.py
"""
Team management specific exceptions.
"""
from typing import Any
from .base import (
AuthorizationException,
BusinessLogicException,
ConflictException,
ResourceNotFoundException,
ValidationException,
)
class TeamMemberNotFoundException(ResourceNotFoundException):
"""Raised when a team member is not found."""
def __init__(self, user_id: int, vendor_id: int | None = None):
details = {"user_id": user_id}
if vendor_id:
details["vendor_id"] = vendor_id
message = (
f"Team member with user ID '{user_id}' not found in vendor {vendor_id}"
)
else:
message = f"Team member with user ID '{user_id}' not found"
super().__init__(
resource_type="TeamMember",
identifier=str(user_id),
message=message,
error_code="TEAM_MEMBER_NOT_FOUND",
details=details,
)
class TeamMemberAlreadyExistsException(ConflictException):
"""Raised when trying to add a user who is already a team member."""
def __init__(self, user_id: int, vendor_id: int):
super().__init__(
message=f"User {user_id} is already a team member of vendor {vendor_id}",
error_code="TEAM_MEMBER_ALREADY_EXISTS",
details={
"user_id": user_id,
"vendor_id": vendor_id,
},
)
class TeamInvitationNotFoundException(ResourceNotFoundException):
"""Raised when a team invitation is not found."""
def __init__(self, invitation_token: str):
super().__init__(
resource_type="TeamInvitation",
identifier=invitation_token,
message=f"Team invitation with token '{invitation_token}' not found or expired",
error_code="TEAM_INVITATION_NOT_FOUND",
)
class TeamInvitationExpiredException(BusinessLogicException):
"""Raised when trying to accept an expired invitation."""
def __init__(self, invitation_token: str):
super().__init__(
message="Team invitation has expired",
error_code="TEAM_INVITATION_EXPIRED",
details={"invitation_token": invitation_token},
)
class TeamInvitationAlreadyAcceptedException(ConflictException):
"""Raised when trying to accept an already accepted invitation."""
def __init__(self, invitation_token: str):
super().__init__(
message="Team invitation has already been accepted",
error_code="TEAM_INVITATION_ALREADY_ACCEPTED",
details={"invitation_token": invitation_token},
)
class UnauthorizedTeamActionException(AuthorizationException):
"""Raised when user tries to perform team action without permission."""
def __init__(
self,
action: str,
user_id: int | None = None,
required_permission: str | None = None,
):
details = {"action": action}
if user_id:
details["user_id"] = user_id
if required_permission:
details["required_permission"] = required_permission
super().__init__(
message=f"Unauthorized to perform action: {action}",
error_code="UNAUTHORIZED_TEAM_ACTION",
details=details,
)
class CannotRemoveOwnerException(BusinessLogicException):
"""Raised when trying to remove the vendor owner from team."""
def __init__(self, user_id: int, vendor_id: int):
super().__init__(
message="Cannot remove vendor owner from team",
error_code="CANNOT_REMOVE_OWNER",
details={
"user_id": user_id,
"vendor_id": vendor_id,
},
)
class CannotModifyOwnRoleException(BusinessLogicException):
"""Raised when user tries to modify their own role."""
def __init__(self, user_id: int):
super().__init__(
message="Cannot modify your own role",
error_code="CANNOT_MODIFY_OWN_ROLE",
details={"user_id": user_id},
)
class RoleNotFoundException(ResourceNotFoundException):
"""Raised when a role is not found."""
def __init__(self, role_id: int, vendor_id: int | None = None):
details = {"role_id": role_id}
if vendor_id:
details["vendor_id"] = vendor_id
message = f"Role with ID '{role_id}' not found in vendor {vendor_id}"
else:
message = f"Role with ID '{role_id}' not found"
super().__init__(
resource_type="Role",
identifier=str(role_id),
message=message,
error_code="ROLE_NOT_FOUND",
details=details,
)
class InvalidRoleException(ValidationException):
"""Raised when role data is invalid."""
def __init__(
self,
message: str = "Invalid role data",
field: str | None = None,
details: dict[str, Any] | None = None,
):
super().__init__(
message=message,
field=field,
details=details,
)
self.error_code = "INVALID_ROLE_DATA"
class InsufficientTeamPermissionsException(AuthorizationException):
"""Raised when user lacks required team permissions for an action."""
def __init__(
self,
required_permission: str,
user_id: int | None = None,
action: str | None = None,
):
details = {"required_permission": required_permission}
if user_id:
details["user_id"] = user_id
if action:
details["action"] = action
message = f"Insufficient team permissions. Required: {required_permission}"
super().__init__(
message=message,
error_code="INSUFFICIENT_TEAM_PERMISSIONS",
details=details,
)
class MaxTeamMembersReachedException(BusinessLogicException):
"""Raised when vendor has reached maximum team members limit."""
def __init__(self, max_members: int, vendor_id: int):
super().__init__(
message=f"Maximum number of team members reached ({max_members})",
error_code="MAX_TEAM_MEMBERS_REACHED",
details={
"max_members": max_members,
"vendor_id": vendor_id,
},
)
class TeamValidationException(ValidationException):
"""Raised when team operation validation fails."""
def __init__(
self,
message: str = "Team operation validation failed",
field: str | None = None,
validation_errors: dict[str, str] | None = None,
):
details = {}
if validation_errors:
details["validation_errors"] = validation_errors
super().__init__(
message=message,
field=field,
details=details,
)
self.error_code = "TEAM_VALIDATION_FAILED"
class InvalidInvitationDataException(ValidationException):
"""Raised when team invitation data is invalid."""
def __init__(
self,
message: str = "Invalid invitation data",
field: str | None = None,
details: dict[str, Any] | None = None,
):
super().__init__(
message=message,
field=field,
details=details,
)
self.error_code = "INVALID_INVITATION_DATA"
# ============================================================================
# NEW: Add InvalidInvitationTokenException
# ============================================================================
class InvalidInvitationTokenException(ValidationException):
"""Raised when invitation token is invalid, expired, or already used.
This is a general exception for any invitation token validation failure.
Use this when checking invitation tokens during the acceptance flow.
"""
def __init__(
self,
message: str = "Invalid or expired invitation token",
invitation_token: str | None = None,
):
details = {}
if invitation_token:
details["invitation_token"] = invitation_token
super().__init__(
message=message,
field="invitation_token",
details=details,
)
self.error_code = "INVALID_INVITATION_TOKEN"