140 lines
5.1 KiB
Python
140 lines
5.1 KiB
Python
"""
|
|
Configuration management and server CRUD API endpoints.
|
|
"""
|
|
|
|
import logging
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.config import settings
|
|
from app.database import get_db
|
|
from app.models import DeployServer, GitServer
|
|
from app.schemas import (
|
|
ConfigResponse, ConfigUpdate,
|
|
DeployServerCreate, DeployServerResponse,
|
|
GitServerCreate, GitServerResponse,
|
|
)
|
|
|
|
log = logging.getLogger("foxy.api.config")
|
|
router = APIRouter(prefix="/api/config", tags=["config"])
|
|
|
|
|
|
# ─── App Configuration ────────────────────────────────────────────────────────
|
|
|
|
|
|
@router.get("", response_model=ConfigResponse)
|
|
async def get_config():
|
|
"""Get current configuration (secrets masked)."""
|
|
return ConfigResponse(
|
|
OPENCLAW_WORKSPACE=settings.OPENCLAW_WORKSPACE,
|
|
GITEA_SERVER=settings.GITEA_SERVER,
|
|
DEPLOYMENT_SERVER=settings.DEPLOYMENT_SERVER,
|
|
DEPLOYMENT_USER=settings.DEPLOYMENT_USER,
|
|
TELEGRAM_CHAT_ID=settings.TELEGRAM_CHAT_ID,
|
|
LOG_LEVEL=settings.LOG_LEVEL,
|
|
GITEA_OPENCLAW_TOKEN="***" if settings.GITEA_OPENCLAW_TOKEN else "",
|
|
DEPLOYMENT_PWD="***" if settings.DEPLOYMENT_PWD else "",
|
|
TELEGRAM_BOT_TOKEN="***" if settings.TELEGRAM_BOT_TOKEN else "",
|
|
)
|
|
|
|
|
|
@router.put("")
|
|
async def update_config(body: ConfigUpdate):
|
|
"""
|
|
Update non-sensitive configuration values.
|
|
Note: In production, this would persist to .env file or a config store.
|
|
For now, it updates the in-memory settings.
|
|
"""
|
|
updated = {}
|
|
for field, value in body.model_dump(exclude_unset=True).items():
|
|
if value is not None:
|
|
setattr(settings, field, value)
|
|
updated[field] = value
|
|
|
|
log.info(f"Config updated: {list(updated.keys())}")
|
|
return {"message": "Configuration updated", "updated_fields": list(updated.keys())}
|
|
|
|
|
|
# ─── Deploy Servers ────────────────────────────────────────────────────────────
|
|
|
|
|
|
@router.get("/deploy-servers", response_model=list[DeployServerResponse])
|
|
async def list_deploy_servers(db: AsyncSession = Depends(get_db)):
|
|
"""List all deployment servers."""
|
|
result = await db.execute(select(DeployServer).order_by(DeployServer.name))
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.post("/deploy-servers", response_model=DeployServerResponse, status_code=201)
|
|
async def create_deploy_server(body: DeployServerCreate, db: AsyncSession = Depends(get_db)):
|
|
"""Add a new deployment server."""
|
|
server = DeployServer(
|
|
name=body.name,
|
|
host=body.host,
|
|
user=body.user,
|
|
password=body.password,
|
|
ssh_port=body.ssh_port,
|
|
description=body.description,
|
|
)
|
|
db.add(server)
|
|
await db.flush()
|
|
await db.refresh(server)
|
|
log.info(f"Deploy server created: {body.name} ({body.host})")
|
|
return server
|
|
|
|
|
|
@router.delete("/deploy-servers/{server_id}")
|
|
async def delete_deploy_server(server_id: int, db: AsyncSession = Depends(get_db)):
|
|
"""Remove a deployment server."""
|
|
result = await db.execute(select(DeployServer).where(DeployServer.id == server_id))
|
|
server = result.scalar_one_or_none()
|
|
if not server:
|
|
raise HTTPException(status_code=404, detail="Deploy server not found")
|
|
name = server.name
|
|
await db.delete(server)
|
|
await db.flush()
|
|
log.info(f"Deploy server deleted: {name}")
|
|
return {"message": f"Deploy server '{name}' deleted"}
|
|
|
|
|
|
# ─── Git Servers ───────────────────────────────────────────────────────────────
|
|
|
|
|
|
@router.get("/git-servers", response_model=list[GitServerResponse])
|
|
async def list_git_servers(db: AsyncSession = Depends(get_db)):
|
|
"""List all Git servers."""
|
|
result = await db.execute(select(GitServer).order_by(GitServer.name))
|
|
return result.scalars().all()
|
|
|
|
|
|
@router.post("/git-servers", response_model=GitServerResponse, status_code=201)
|
|
async def create_git_server(body: GitServerCreate, db: AsyncSession = Depends(get_db)):
|
|
"""Add a new Git server."""
|
|
server = GitServer(
|
|
name=body.name,
|
|
url=body.url,
|
|
token=body.token,
|
|
org=body.org,
|
|
description=body.description,
|
|
)
|
|
db.add(server)
|
|
await db.flush()
|
|
await db.refresh(server)
|
|
log.info(f"Git server created: {body.name} ({body.url})")
|
|
return server
|
|
|
|
|
|
@router.delete("/git-servers/{server_id}")
|
|
async def delete_git_server(server_id: int, db: AsyncSession = Depends(get_db)):
|
|
"""Remove a Git server."""
|
|
result = await db.execute(select(GitServer).where(GitServer.id == server_id))
|
|
server = result.scalar_one_or_none()
|
|
if not server:
|
|
raise HTTPException(status_code=404, detail="Git server not found")
|
|
name = server.name
|
|
await db.delete(server)
|
|
await db.flush()
|
|
log.info(f"Git server deleted: {name}")
|
|
return {"message": f"Git server '{name}' deleted"}
|