cc3m / routers /zones.py
kokokoasd's picture
Upload 21 files
36ce73b verified
"""
Zone CRUD API.
Single Responsibility: only handles zone create/list/delete.
File management is in files.py, port management in ports.py.
"""
import shutil
from datetime import datetime
import httpx
from fastapi import APIRouter, Depends, Form, HTTPException
from auth import AuthUser, get_current_user
from config import DATA_DIR, ADMIN_API_URL
from storage import load_meta, save_meta, validate_zone_name, check_zone_owner
from routers.terminal import kill_terminal
router = APIRouter(prefix="/api/zones", tags=["zones"])
def _get_max_zones() -> int:
"""Fetch zone limit from Admin Worker config."""
if not ADMIN_API_URL:
return 0
try:
resp = httpx.get(f"{ADMIN_API_URL}/config", timeout=5)
if resp.status_code == 200:
return resp.json().get("max_zones", 0)
except Exception:
pass
return 0
@router.get("")
def list_zones(user: AuthUser = Depends(get_current_user)):
meta = load_meta()
return [
{
"name": name,
"created": info.get("created", ""),
"description": info.get("description", ""),
"exists": (DATA_DIR / name).is_dir(),
}
for name, info in meta.items()
if user.role == "admin" or info.get("owner_id") == user.sub
]
@router.post("")
def create_zone(name: str = Form(...), description: str = Form(""), user: AuthUser = Depends(get_current_user)):
try:
validate_zone_name(name)
zone_path = DATA_DIR / name
if zone_path.exists():
raise ValueError(f"Zone '{name}' đã tồn tại")
# Check zone limit (per-user for non-admin)
max_zones = _get_max_zones()
if max_zones > 0:
meta = load_meta()
user_zones = [n for n, info in meta.items() if info.get("owner_id") == user.sub]
if len(user_zones) >= max_zones:
raise ValueError(f"Đã đạt giới hạn {max_zones} zones")
zone_path.mkdir(parents=True)
(zone_path / "README.md").write_text(
f"# {name}\n\nZone được tạo lúc {datetime.now().isoformat()}\n"
)
meta = load_meta()
meta[name] = {
"created": datetime.now().isoformat(),
"description": description,
"owner_id": user.sub,
"owner_name": user.username,
}
save_meta(meta)
return {"name": name, "path": str(zone_path)}
except ValueError as e:
raise HTTPException(400, str(e))
@router.delete("/{zone_name}")
def delete_zone(zone_name: str, user: AuthUser = Depends(get_current_user)):
try:
validate_zone_name(zone_name)
check_zone_owner(zone_name, user.sub, user.role)
zone_path = DATA_DIR / zone_name
if not zone_path.exists():
raise ValueError(f"Zone '{zone_name}' không tồn tại")
kill_terminal(zone_name)
shutil.rmtree(zone_path)
meta = load_meta()
meta.pop(zone_name, None)
save_meta(meta)
return {"ok": True}
except ValueError as e:
raise HTTPException(400, str(e))