Compare commits
1 Commits
3cf2b1bc49
...
4b20444a5e
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b20444a5e |
107
app/init_wizard.py
Normal file
107
app/init_wizard.py
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
"""
|
||||||
|
HarborForge initialization via AbstractWizard.
|
||||||
|
|
||||||
|
On startup, reads config from AbstractWizard and creates:
|
||||||
|
- Admin user (if not exists)
|
||||||
|
- Default project (if configured)
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
import httpx
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.models import models
|
||||||
|
from app.api.deps import get_password_hash
|
||||||
|
|
||||||
|
logger = logging.getLogger("harborforge.init")
|
||||||
|
|
||||||
|
WIZARD_URL = os.getenv("WIZARD_URL", "http://wizard:8080")
|
||||||
|
WIZARD_CONFIG = os.getenv("WIZARD_CONFIG", "harborforge.json")
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_wizard_config() -> dict | None:
|
||||||
|
"""Fetch initialization config from AbstractWizard."""
|
||||||
|
url = f"{WIZARD_URL}/api/v1/config/{WIZARD_CONFIG}"
|
||||||
|
try:
|
||||||
|
resp = httpx.get(url, timeout=10)
|
||||||
|
if resp.status_code == 200:
|
||||||
|
data = resp.json()
|
||||||
|
# AbstractWizard wraps in {"data": ...}
|
||||||
|
return data.get("data", data)
|
||||||
|
elif resp.status_code == 404:
|
||||||
|
logger.info("No wizard config found at %s, skipping initialization", url)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
logger.warning("Wizard returned %d: %s", resp.status_code, resp.text)
|
||||||
|
return None
|
||||||
|
except httpx.ConnectError:
|
||||||
|
logger.info("AbstractWizard not available at %s, skipping", WIZARD_URL)
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Failed to fetch wizard config: %s", e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def init_admin_user(db: Session, admin_cfg: dict) -> None:
|
||||||
|
"""Create admin user if not exists."""
|
||||||
|
username = admin_cfg.get("username", "admin")
|
||||||
|
existing = db.query(models.User).filter(models.User.username == username).first()
|
||||||
|
if existing:
|
||||||
|
logger.info("Admin user '%s' already exists (id=%d), skipping", username, existing.id)
|
||||||
|
return
|
||||||
|
|
||||||
|
password = admin_cfg.get("password", "changeme")
|
||||||
|
user = models.User(
|
||||||
|
username=username,
|
||||||
|
email=admin_cfg.get("email", f"{username}@harborforge.local"),
|
||||||
|
full_name=admin_cfg.get("full_name", "Admin"),
|
||||||
|
hashed_password=get_password_hash(password),
|
||||||
|
is_admin=True,
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
db.add(user)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(user)
|
||||||
|
logger.info("Created admin user '%s' (id=%d)", username, user.id)
|
||||||
|
|
||||||
|
|
||||||
|
def init_default_project(db: Session, project_cfg: dict, admin_user_id: int) -> None:
|
||||||
|
"""Create default project if configured and not exists."""
|
||||||
|
name = project_cfg.get("name", "Default")
|
||||||
|
existing = db.query(models.Project).filter(models.Project.name == name).first()
|
||||||
|
if existing:
|
||||||
|
logger.info("Project '%s' already exists (id=%d), skipping", name, existing.id)
|
||||||
|
return
|
||||||
|
|
||||||
|
project = models.Project(
|
||||||
|
name=name,
|
||||||
|
description=project_cfg.get("description", ""),
|
||||||
|
owner_id=admin_user_id,
|
||||||
|
)
|
||||||
|
db.add(project)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(project)
|
||||||
|
logger.info("Created default project '%s' (id=%d)", name, project.id)
|
||||||
|
|
||||||
|
|
||||||
|
def run_init(db: Session) -> None:
|
||||||
|
"""Main initialization entry point."""
|
||||||
|
config = fetch_wizard_config()
|
||||||
|
if not config:
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("Running HarborForge initialization from AbstractWizard")
|
||||||
|
|
||||||
|
# Admin user
|
||||||
|
admin_cfg = config.get("admin")
|
||||||
|
if admin_cfg:
|
||||||
|
init_admin_user(db, admin_cfg)
|
||||||
|
|
||||||
|
# Default project
|
||||||
|
project_cfg = config.get("default_project")
|
||||||
|
if project_cfg:
|
||||||
|
admin = db.query(models.User).filter(models.User.is_admin == True).first()
|
||||||
|
if admin:
|
||||||
|
init_default_project(db, project_cfg, admin.id)
|
||||||
|
|
||||||
|
logger.info("Initialization complete")
|
||||||
10
app/main.py
10
app/main.py
@@ -46,6 +46,14 @@ app.include_router(misc_router)
|
|||||||
# Run database migration on startup
|
# Run database migration on startup
|
||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
def startup():
|
def startup():
|
||||||
from app.core.config import Base, engine
|
from app.core.config import Base, engine, SessionLocal
|
||||||
from app.models import webhook, apikey, activity, milestone, notification, worklog
|
from app.models import webhook, apikey, activity, milestone, notification, worklog
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
|
|
||||||
|
# Initialize from AbstractWizard (admin user, default project, etc.)
|
||||||
|
from app.init_wizard import run_init
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
run_init(db)
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user