from __future__ import annotations from collections.abc import Mapping from sqlalchemy.orm import Session from govoplan_access.backend.admin.service import ensure_default_roles from govoplan_access.backend.db.models import Account, User, UserRoleAssignment from govoplan_core.admin.common import AdminValidationError from govoplan_core.core.access import TenantAccessProvisioner, TenantOwnerCandidateRef class LegacyTenantAccessProvisioner(TenantAccessProvisioner): def ensure_default_roles(self, session: object, tenant: object | None = None) -> Mapping[str, object]: return ensure_default_roles(session, tenant) # type: ignore[arg-type] def tenant_owner_candidates(self, session: object) -> tuple[TenantOwnerCandidateRef, ...]: db = _session(session) accounts = db.query(Account).filter(Account.is_active.is_(True)).order_by(Account.email.asc()).all() return tuple( TenantOwnerCandidateRef(account_id=account.id, email=account.email, display_name=account.display_name) for account in accounts ) def ensure_tenant_owner_membership( self, session: object, *, tenant: object, owner_account_id: str, ) -> str: db = _session(session) tenant_id = getattr(tenant, "id", None) if not tenant_id: raise AdminValidationError("Tenant owner membership requires a persisted tenant.") roles = ensure_default_roles(db, tenant) # type: ignore[arg-type] owner_role = roles.get("owner") if owner_role is None: raise AdminValidationError("Tenant owner role is not available.") owner_account = db.get(Account, owner_account_id) if owner_account is None or not owner_account.is_active: raise AdminValidationError("The selected tenant owner account is missing or inactive.") membership = ( db.query(User) .filter(User.tenant_id == tenant_id, User.account_id == owner_account.id) .one_or_none() ) if membership is None: membership = User( tenant_id=tenant_id, account_id=owner_account.id, email=owner_account.email, display_name=owner_account.display_name, is_active=True, auth_provider=owner_account.auth_provider, password_hash=owner_account.password_hash, ) db.add(membership) db.flush() existing_assignment = ( db.query(UserRoleAssignment) .filter( UserRoleAssignment.tenant_id == tenant_id, UserRoleAssignment.user_id == membership.id, UserRoleAssignment.role_id == owner_role.id, ) .one_or_none() ) if existing_assignment is None: db.add(UserRoleAssignment(tenant_id=tenant_id, user_id=membership.id, role_id=owner_role.id)) db.flush() return membership.id def _session(session: object) -> Session: if not isinstance(session, Session): raise TypeError("Tenant access provisioner requires a SQLAlchemy Session") return session