from fastapi import APIRouter, Depends, Form, Request from fastapi.responses import HTMLResponse, RedirectResponse from sqlalchemy.orm import Session from app.database import get_db from app.models import Product, Contract, DailyBar from app.collector import sync_active_contracts, sync_one_contract router = APIRouter(prefix="/admin", tags=["admin"]) EXCHANGES = ["CZCE", "DCE", "SHFE", "CFFEX", "INE"] @router.get("/", response_class=HTMLResponse) def admin_page(request: Request, db: Session = Depends(get_db)): products = db.query(Product).order_by(Product.code).all() product_data = [] for p in products: contracts = ( db.query(Contract) .filter(Contract.product_id == p.id) .order_by(Contract.code) .all() ) contract_list = [] for c in contracts: bar_count = ( db.query(DailyBar) .filter(DailyBar.contract == c.code) .count() ) contract_list.append({ "id": c.id, "code": c.code, "name": c.name, "is_active": c.is_active, "bar_count": bar_count, }) product_data.append({ "id": p.id, "code": p.code, "name": p.name, "exchange": p.exchange, "contracts": contract_list, }) total_contracts = sum(len(pd["contracts"]) for pd in product_data) template = request.app.state.templates.get_template("admin.html") return HTMLResponse( template.render( request=request, active_nav="admin", products=product_data, total_contracts=total_contracts, exchanges=EXCHANGES, ) ) @router.post("/product") def create_product( request: Request, code: str = Form(...), name: str = Form(...), exchange: str = Form(...), db: Session = Depends(get_db), ): existing = db.query(Product).filter(Product.code == code.upper()).first() if not existing: p = Product(code=code.upper(), name=name, exchange=exchange) db.add(p) db.commit() return RedirectResponse("/admin/?tab=product", status_code=303) @router.post("/contract") def create_contract( request: Request, product_id: int = Form(...), code: str = Form(...), name: str = Form(...), db: Session = Depends(get_db), ): existing = db.query(Contract).filter(Contract.code == code.upper()).first() if not existing: c = Contract( product_id=product_id, code=code.upper(), name=name, is_active=True, ) db.add(c) db.commit() return RedirectResponse("/admin/?tab=contract", status_code=303) @router.post("/contract/{contract_id}/toggle") def toggle_contract(contract_id: int, db: Session = Depends(get_db)): c = db.query(Contract).filter(Contract.id == contract_id).first() if c: c.is_active = not c.is_active db.commit() return RedirectResponse("/admin/?tab=contract", status_code=303) @router.post("/contract/{contract_id}/delete") def delete_contract(contract_id: int, db: Session = Depends(get_db)): c = db.query(Contract).filter(Contract.id == contract_id).first() if c: db.delete(c) db.commit() return RedirectResponse("/admin/?tab=contract", status_code=303) @router.post("/product/{product_id}/delete") def delete_product(product_id: int, db: Session = Depends(get_db)): p = db.query(Product).filter(Product.id == product_id).first() if p: db.delete(p) db.commit() return RedirectResponse("/admin/?tab=product", status_code=303) @router.post("/sync") def sync_all(request: Request): results = sync_active_contracts() total = sum(results.values()) print(f"[sync] Synced {total} bars across {len(results)} contracts: {results}") return RedirectResponse(f"/admin/?tab=sync&synced={total}", status_code=303) @router.post("/sync/{contract_code}") def sync_single(contract_code: str): count = sync_one_contract(contract_code.upper()) return RedirectResponse(f"/admin/?tab=sync&synced={count}", status_code=303) @router.post("/sync/product/{product_id}") def sync_product(product_id: int, request: Request, db: Session = Depends(get_db)): contracts = db.query(Contract).filter( Contract.product_id == product_id, Contract.is_active == True ).all() total = 0 for c in contracts: total += sync_one_contract(c.code) return RedirectResponse(f"/admin/?tab=sync&synced={total}", status_code=303)