Release v0.1.5
This commit is contained in:
82
src/govoplan_access/backend/tenancy/provisioning.py
Normal file
82
src/govoplan_access/backend/tenancy/provisioning.py
Normal file
@@ -0,0 +1,82 @@
|
||||
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
|
||||
Reference in New Issue
Block a user