Fix: register plugin routes in create_app() not lifespan(); add status column to contacts migration 0039; add updated_at to user_tenants migration 0037
This commit is contained in:
@@ -80,6 +80,11 @@ def upgrade() -> None:
|
||||
if status_col_result is None:
|
||||
op.add_column("user_tenants", sa.Column("status", sa.String(20), nullable=False, server_default="active"))
|
||||
|
||||
# ── 4b. Add updated_at column to user_tenants ──────────────────────────
|
||||
updated_col_result = conn.execute(sa.text(_column_exists("user_tenants", "updated_at"))).fetchone()
|
||||
if updated_col_result is None:
|
||||
op.add_column("user_tenants", sa.Column("updated_at", sa.DateTime(timezone=True), nullable=True, server_default=sa.func.now()))
|
||||
|
||||
# ── 5. Data migration: copy tenant_id, role, role_id from users to user_tenants ─
|
||||
# Only create UserTenant rows that don't already exist
|
||||
conn.execute(sa.text("""
|
||||
|
||||
@@ -54,6 +54,11 @@ def _constraint_exists(table: str, constraint: str) -> str:
|
||||
def upgrade() -> None:
|
||||
conn = op.get_bind()
|
||||
|
||||
# ── 0. Add status column to contacts (for state machine) ──
|
||||
status_col = conn.execute(sa.text(_column_exists("contacts", "status"))).fetchone()
|
||||
if not status_col:
|
||||
op.add_column("contacts", sa.Column("status", sa.String(20), nullable=False, server_default="lead"))
|
||||
|
||||
# ── 1a. Rename surfix → suffix ──
|
||||
result = conn.execute(sa.text(_column_exists("contacts", "surfix"))).fetchone()
|
||||
if result:
|
||||
|
||||
+20
-9
@@ -139,12 +139,14 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
if plugin_record is None:
|
||||
# Create DB record for this builtin plugin — inactive by default (except core)
|
||||
# Only core plugins auto-activate on first install
|
||||
# Existing plugins that are marked active in DB will be activated below
|
||||
plugin_record = PluginModel(
|
||||
name=name,
|
||||
display_name=plugin.manifest.display_name,
|
||||
version=plugin.manifest.version,
|
||||
status="installed",
|
||||
active=plugin.manifest.is_core, # Only core plugins auto-activate
|
||||
active=plugin.manifest.is_core,
|
||||
is_core=plugin.manifest.is_core,
|
||||
)
|
||||
db.add(plugin_record)
|
||||
@@ -170,16 +172,12 @@ async def lifespan(app: FastAPI):
|
||||
logger.info(f"Plugin {name} is inactive — skipping activation")
|
||||
continue
|
||||
|
||||
# Activate plugin and register routes
|
||||
# Activate plugin (routes are already registered in create_app)
|
||||
try:
|
||||
await plugin.on_activate(db, container, event_bus)
|
||||
for route_def in plugin.manifest.routes:
|
||||
router_module = importlib.import_module(route_def.module)
|
||||
router = getattr(router_module, route_def.router_attr)
|
||||
app.include_router(router)
|
||||
plugin_record.status = "active"
|
||||
print(f"[STARTUP] Activated plugin: {name} ({len(plugin.manifest.routes)} routes)", flush=True)
|
||||
logger.info(f"Activated plugin: {name} ({len(plugin.manifest.routes)} routes)")
|
||||
print(f"[STARTUP] Activated plugin: {name}", flush=True)
|
||||
logger.info(f"Activated plugin: {name}")
|
||||
except Exception as exc:
|
||||
print(f"[STARTUP] Failed to activate plugin {name}: {exc}", flush=True)
|
||||
logger.error(f"Failed to activate plugin {name}: {exc}")
|
||||
@@ -335,7 +333,20 @@ def create_app() -> FastAPI:
|
||||
app.include_router(custom_fields.router)
|
||||
app.include_router(saved_filters.router)
|
||||
|
||||
# ── Plugin routes are registered in lifespan() after activation status is loaded ──
|
||||
# ── Register plugin routes for all built-in plugins ──
|
||||
# Routes are registered here (before app start); activation status
|
||||
# is enforced at runtime via require_permission and plugin checks.
|
||||
import importlib
|
||||
from app.plugins.builtins.contracts import BUILTIN_PLUGINS
|
||||
for name, plugin in BUILTIN_PLUGINS.items():
|
||||
try:
|
||||
for route_def in plugin.manifest.routes:
|
||||
router_module = importlib.import_module(route_def.module)
|
||||
router = getattr(router_module, route_def.router_attr)
|
||||
app.include_router(router)
|
||||
logger.info(f"Registered plugin routes: {name} ({len(plugin.manifest.routes)} routes)")
|
||||
except Exception as exc:
|
||||
logger.error(f"Failed to register plugin routes for {name}: {exc}")
|
||||
# Do NOT register plugin routes here — lifespan() handles it for active plugins only
|
||||
|
||||
# ── Serve frontend static files (SPA) ──────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user