rebase
This commit is contained in:
44
app/main.py
44
app/main.py
@@ -27,6 +27,25 @@ from app.models import Setting, User
|
||||
_logger = get_logger(__name__)
|
||||
|
||||
|
||||
async def _apply_schema_fixups(engine) -> None:
|
||||
"""Apply idempotent ALTER statements for schema fixes that create_all
|
||||
cannot handle (e.g. changing NOT NULL → NULL on existing tables).
|
||||
|
||||
These run on every startup. Each statement is wrapped in try/except so
|
||||
it silently succeeds if the fix was already applied.
|
||||
"""
|
||||
fixups = [
|
||||
# world_presets.owner_id: was NOT NULL, now nullable (for system presets)
|
||||
"ALTER TABLE world_presets ALTER COLUMN owner_id DROP NOT NULL",
|
||||
]
|
||||
async with engine.begin() as conn:
|
||||
for sql in fixups:
|
||||
try:
|
||||
await conn.execute(text(sql))
|
||||
except Exception: # noqa: BLE001
|
||||
pass # already applied, or table doesn't exist yet
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
"""Application startup / shutdown lifecycle."""
|
||||
@@ -44,10 +63,10 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
try:
|
||||
engine = get_engine()
|
||||
await create_all_tables(engine)
|
||||
await _apply_schema_fixups(engine)
|
||||
_logger.info("db_tables_ready")
|
||||
except Exception as e: # noqa: BLE001
|
||||
_logger.error("db_tables_create_failed", error=str(e))
|
||||
# Continue anyway — /api/health will reflect the broken state
|
||||
|
||||
sm = get_sessionmaker()
|
||||
try:
|
||||
@@ -56,7 +75,9 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
await seed_default_settings(session)
|
||||
# 2) ensure admin setup token
|
||||
token = await get_admin_setup_token(session)
|
||||
# 3) check if any admin exists
|
||||
# 3) check if any admin exists — ALWAYS print the setup URL
|
||||
# (user requested: even if admin exists, show the token for
|
||||
# reference / debugging)
|
||||
from sqlalchemy import func
|
||||
|
||||
admins_count = (
|
||||
@@ -65,16 +86,18 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
)
|
||||
).scalar_one()
|
||||
if admins_count == 0:
|
||||
_logger.warning(
|
||||
"no_admin_yet",
|
||||
setup_url=f"/register/admin?token={token}",
|
||||
)
|
||||
print(f"\n=== AI-RPG Admin Setup ===")
|
||||
print(f"No admin user yet. Open this URL in your browser:")
|
||||
print(f" /register/admin?token={token}")
|
||||
print(f"===========================\n")
|
||||
_logger.warning("no_admin_yet", setup_url=f"/register/admin?token={token}")
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f" AI-RPG — No admin user yet.")
|
||||
print(f" Open this URL to create the first admin:")
|
||||
print(f" http://localhost:8080/register/admin?token={token}")
|
||||
print(f"{'=' * 60}\n")
|
||||
else:
|
||||
_logger.info("admins_present", count=admins_count)
|
||||
# Still print the token URL for reference
|
||||
print(f"\n Admin already exists. Admin register URL (for reference):")
|
||||
print(f" /register/admin?token={token}")
|
||||
print(f" (This URL is blocked since an admin already exists.)\n")
|
||||
# 4) seed builtin presets (idempotent)
|
||||
from app.migrations.seed import seed_builtin_presets
|
||||
|
||||
@@ -94,7 +117,6 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
_logger.warning("qdrant_init_failed", error=str(e))
|
||||
except Exception as e: # noqa: BLE001
|
||||
_logger.error("startup_failed", error=str(e))
|
||||
# Don't crash — let /api/health reflect the broken state
|
||||
pass
|
||||
|
||||
yield
|
||||
|
||||
Reference in New Issue
Block a user