from __future__ import annotations import re from typing import Protocol from v1.auth.schemas import ( PasswordResetConfirmRequest, PasswordResetRequest, SessionCreateRequest, SessionRefreshRequest, SessionResponse, VerificationCreateRequest, VerificationCreateResponse, VerificationResendRequest, VerificationVerifyRequest, ) class AuthServiceGateway(Protocol): async def create_verification( self, request: VerificationCreateRequest ) -> VerificationCreateResponse: raise NotImplementedError async def verify_verification( self, request: VerificationVerifyRequest ) -> SessionResponse: raise NotImplementedError async def resend_verification(self, request: VerificationResendRequest) -> None: raise NotImplementedError async def create_session(self, request: SessionCreateRequest) -> SessionResponse: raise NotImplementedError async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse: raise NotImplementedError async def delete_session(self, refresh_token: str | None) -> None: raise NotImplementedError async def request_password_reset(self, request: PasswordResetRequest) -> None: raise NotImplementedError async def confirm_password_reset( self, request: PasswordResetConfirmRequest ) -> None: raise NotImplementedError class AuthService: _gateway: AuthServiceGateway def __init__(self, gateway: AuthServiceGateway) -> None: self._gateway = gateway async def create_verification( self, request: VerificationCreateRequest ) -> VerificationCreateResponse: normalized_invite_code = _normalize_invite_code(request.invite_code) normalized_request = request.model_copy( update={"invite_code": normalized_invite_code} ) return await self._gateway.create_verification(normalized_request) async def verify_verification( self, request: VerificationVerifyRequest ) -> SessionResponse: return await self._gateway.verify_verification(request) async def resend_verification(self, request: VerificationResendRequest) -> None: await self._gateway.resend_verification(request) async def create_session(self, request: SessionCreateRequest) -> SessionResponse: return await self._gateway.create_session(request) async def refresh_session(self, request: SessionRefreshRequest) -> SessionResponse: return await self._gateway.refresh_session(request) async def delete_session(self, refresh_token: str | None) -> None: await self._gateway.delete_session(refresh_token) async def request_password_reset(self, request: PasswordResetRequest) -> None: await self._gateway.request_password_reset(request) async def confirm_password_reset( self, request: PasswordResetConfirmRequest ) -> None: await self._gateway.confirm_password_reset(request) _INVITE_CODE_PATTERN = re.compile(r"^[ABCDEFGHJKMNPQRSTUVWXYZ23456789]{4}$") def _normalize_invite_code(value: str | None) -> str | None: if value is None: return None normalized = value.strip().upper() if not normalized: return None return normalized if _INVITE_CODE_PATTERN.fullmatch(normalized) else None