118 lines
4.5 KiB
Python
118 lines
4.5 KiB
Python
from alembic.runtime.migration import MigrationContext
|
|
from alembic.config import Config
|
|
from alembic.script import ScriptDirectory
|
|
from sqlalchemy.ext.asyncio import AsyncEngine
|
|
from sqlalchemy import select, insert
|
|
from app.database.models import Inquilino, RbacUser, RbacPapel, rbac_papeis_usuario
|
|
from app.database.session import sessionmanager
|
|
from app.rbac.auth import get_user_db, get_user_manager
|
|
from app.rbac.schemas import UserCreate
|
|
from fastapi_users.exceptions import UserAlreadyExists
|
|
|
|
|
|
async def check_migrations(engine: AsyncEngine):
|
|
"""
|
|
Verifica se todas as migrações foram aplicadas.
|
|
"""
|
|
alembic_config = Config("alembic.ini")
|
|
script = ScriptDirectory.from_config(alembic_config)
|
|
|
|
async with engine.begin() as conn:
|
|
def sync_check_migrations(sync_conn):
|
|
context = MigrationContext.configure(sync_conn)
|
|
current_revision = context.get_current_revision()
|
|
latest_revision = script.get_current_head()
|
|
|
|
if current_revision != latest_revision:
|
|
raise RuntimeError(
|
|
f"Database is not up-to-date. Current: {current_revision}, Latest: {latest_revision}. "
|
|
"Execute migrations before adding new tenants."
|
|
)
|
|
|
|
await conn.run_sync(sync_check_migrations)
|
|
|
|
|
|
async def create_user(session, fk_inquilino_uuid, email, password, is_superuser=False):
|
|
"""
|
|
Cria um usuário no sistema utilizando o gerenciador de usuários do FastAPI Users.
|
|
"""
|
|
try:
|
|
|
|
user_db = await get_user_db(session).__anext__()
|
|
user_manager = await get_user_manager(user_db).__anext__()
|
|
|
|
try:
|
|
user = await user_manager.create(
|
|
UserCreate(
|
|
email=email,
|
|
password=password,
|
|
is_superuser=is_superuser,
|
|
is_active=True,
|
|
fk_inquilino_uuid=fk_inquilino_uuid,
|
|
|
|
)
|
|
)
|
|
return user.id
|
|
except UserAlreadyExists:
|
|
result_user = await session.execute(select(RbacUser).filter_by(email=email))
|
|
existing_user = result_user.scalars().first()
|
|
raise RuntimeError(f"Usuário '{email}' já existe, seu ID é {existing_user.id}")
|
|
except Exception as e:
|
|
raise RuntimeError(f"Erro ao criar usuário '{email}': {e}")
|
|
|
|
|
|
async def tenant_create(nome: str, email: str, password: str, cpf_cnpj: str):
|
|
"""
|
|
Cria um novo tenant (inquilino) no sistema, configura o schema específico
|
|
e registra um usuário inicial relacionado ao inquilino.
|
|
"""
|
|
async with sessionmanager.session() as db:
|
|
try:
|
|
# Verificar se o tenant já existe
|
|
result = await db.execute(select(Inquilino).filter_by(cpf_cnpj=cpf_cnpj))
|
|
existing_tenant = result.scalars().first()
|
|
|
|
if existing_tenant:
|
|
raise RuntimeError(
|
|
f"Tenant com CPF/CNPJ '{cpf_cnpj}' já existe. Nome: {existing_tenant.nome}, "
|
|
f"UUID: {existing_tenant.uuid}"
|
|
)
|
|
|
|
# Criar o registro do tenant
|
|
tenant = Inquilino(nome=nome, cpf_cnpj=cpf_cnpj)
|
|
db.add(tenant)
|
|
await db.commit()
|
|
await db.refresh(tenant)
|
|
|
|
# Criar o usuário inicial
|
|
user_id = await create_user(
|
|
session=db,
|
|
fk_inquilino_uuid=tenant.uuid,
|
|
email=email,
|
|
password=password,
|
|
is_superuser=True,
|
|
)
|
|
|
|
# Nova sessão para associar o papel ao usuário
|
|
async with sessionmanager.session() as new_db:
|
|
# Buscar o papel "Super Administrador"
|
|
result_papel = await new_db.execute(select(RbacPapel).filter_by(nome="Super Administrador"))
|
|
papel = result_papel.scalars().first()
|
|
if not papel:
|
|
raise RuntimeError("Papel 'Super Administrador' não encontrado.")
|
|
|
|
# Relacionar o papel ao usuário
|
|
await new_db.execute(
|
|
insert(rbac_papeis_usuario).values(
|
|
user_uuid=user_id,
|
|
papel_uuid=papel.uuid,
|
|
)
|
|
)
|
|
await new_db.commit()
|
|
|
|
return tenant.uuid
|
|
except RuntimeError as e:
|
|
raise RuntimeError(f"Erro inesperado durante a criação do cliente: '{nome}': {e}")
|
|
except Exception as e:
|
|
raise RuntimeError(f"Erro inesperado durante a criação do cliente: '{nome}': {e}")
|