Source code for src.module.tenant.domain.services

"""Tenant Context domain services.

Domain services contain business logic that doesn't naturally belong to a single
aggregate. They receive dependencies via parameters (no direct imports from infra).
"""

from __future__ import annotations

from typing import Any


[docs] def provision_tenant( tenant: Any, isolation_backend: Any, event_publisher: Any, ) -> None: """Provision storage for a new tenant and emit TenantCreated event. Args: tenant: The Tenant model instance. isolation_backend: The active TenantIsolationBackend. event_publisher: Callable to publish domain events. """ from src.module.tenant.domain.events import TenantCreated isolation_backend.create_tenant_storage(tenant) event_publisher( TenantCreated( tenant_id=str(tenant.id), tenant_slug=tenant.slug, schema_name=tenant.schema_name, ) )
[docs] def resolve_tenant_from_identifier( identifier: str, tenant_queryset: Any, ) -> Any: """Resolve a tenant by slug or UUID from the given queryset. Args: identifier: Tenant slug or UUID string. tenant_queryset: A queryset-like object with .by_slug() and .by_id() methods. Returns: The resolved Tenant instance. Raises: TenantNotFoundError: If the tenant cannot be found. TenantInactiveError: If the tenant exists but is not active. """ import uuid from src.share_kernel.domain.exceptions import TenantInactiveError, TenantNotFoundError tenant = None # Try UUID first try: tenant_uuid = uuid.UUID(identifier) tenant = tenant_queryset.filter(id=tenant_uuid).first() except (ValueError, AttributeError): pass # Fall back to slug if tenant is None: tenant = tenant_queryset.filter(slug=identifier).first() if tenant is None: raise TenantNotFoundError(f"Tenant not found: {identifier}") if tenant.status != "active": raise TenantInactiveError(f"Tenant '{tenant.slug}' is {tenant.status}") return tenant
[docs] def validate_membership( user_id: str, tenant_id: str, membership_queryset: Any, ) -> Any: """Validate that a user has an active membership in a tenant. Args: user_id: The user's UUID string. tenant_id: The tenant's UUID string. membership_queryset: A queryset for TenantMembership lookups. Returns: The active TenantMembership instance. Raises: MembershipNotFoundError: If no active membership exists. """ from src.share_kernel.domain.exceptions import MembershipNotFoundError membership = membership_queryset.filter( user_id=user_id, tenant_id=tenant_id, status="active", ).first() if membership is None: raise MembershipNotFoundError( f"User {user_id} has no active membership in tenant {tenant_id}" ) return membership