| from typing import Annotated |
|
|
| from fastapi import Depends, Header, Path |
| from fastapi.security import OAuth2PasswordBearer |
| from sqlalchemy.orm import Session |
|
|
| from src.api.errors import error_response |
| from src.config import get_settings |
| from src.models.auth import OrganizationRole |
| from src.services.auth import AuthService, AuthServiceError |
| from src.services.db import User, get_session |
| from src.services.organizations import OrganizationService |
|
|
| oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login", auto_error=False) |
|
|
| DbSessionDep = Annotated[Session, Depends(get_session)] |
| AccessTokenDep = Annotated[str | None, Depends(oauth2_scheme)] |
|
|
|
|
| def service_error_to_response(exc: AuthServiceError): |
| return error_response(status_code=exc.status_code, code=exc.code, message=exc.message) |
|
|
|
|
| def get_optional_current_user(db: DbSessionDep, token: AccessTokenDep) -> User | None: |
| if not token: |
| return None |
| try: |
| return AuthService(db, get_settings()).authenticate_access_token(token) |
| except AuthServiceError: |
| return None |
|
|
|
|
| def require_current_user(db: DbSessionDep, token: AccessTokenDep) -> User: |
| if not token: |
| raise AuthServiceError(401, "unauthorized", "Authentication required.") |
| return AuthService(db, get_settings()).authenticate_access_token(token) |
|
|
|
|
| CurrentUserDep = Annotated[User, Depends(require_current_user)] |
| OptionalCurrentUserDep = Annotated[User | None, Depends(get_optional_current_user)] |
|
|
|
|
| def require_organization_membership( |
| org_id: Annotated[str, Path()], |
| user: CurrentUserDep, |
| db: DbSessionDep, |
| ): |
| return OrganizationService(db).require_membership(user.id, org_id) |
|
|
|
|
| def require_organization_manager( |
| org_id: Annotated[str, Path()], |
| user: CurrentUserDep, |
| db: DbSessionDep, |
| ): |
| return OrganizationService(db).require_manager(user.id, org_id) |
|
|
|
|
| OrganizationMembershipDep = Annotated[object, Depends(require_organization_membership)] |
| OrganizationManagerDep = Annotated[object, Depends(require_organization_manager)] |
| GuestSessionHeaderDep = Annotated[str | None, Header(alias="X-Guest-Session-Id")] |
|
|
|
|
| def role_allows_organization_management(role: OrganizationRole | str) -> bool: |
| return str(role) == OrganizationRole.OWNER.value |
|
|