feat: add one-click sync for website group bindings

This commit is contained in:
liumangmang
2026-06-01 09:06:01 +08:00
parent 890432e1a5
commit 518e3e8efc
6 changed files with 329 additions and 11 deletions
+65
View File
@@ -30,7 +30,9 @@ from app.schemas.website import (
WebsiteResponse,
WebsiteSyncLogResponse,
WebsiteUpdate,
WebsiteBatchSyncResponse,
)
from app.services.website_client import Sub2ApiWebsiteClient
from app.services.website_sync import binding_sources, sync_binding, build_rate_priority_map
from app.utils.auth import get_current_user
@@ -669,6 +671,69 @@ def list_bindings(db: Session = Depends(get_db), _=Depends(get_current_user)):
return [_binding_response(db, row) for row in rows]
@router.post("/api/websites/{wid}/group-bindings/sync-now", response_model=WebsiteBatchSyncResponse)
def sync_website_group_bindings(
wid: int,
db: Session = Depends(get_db),
_=Depends(get_current_user),
):
"""一键同步网站下所有分组绑定。"""
website = db.query(Website).filter(Website.id == wid).first()
if not website:
raise HTTPException(404, "website not found")
bindings = db.query(WebsiteGroupBinding).filter(WebsiteGroupBinding.website_id == wid).order_by(WebsiteGroupBinding.id.asc()).all()
if not bindings:
return WebsiteBatchSyncResponse(
total=0, success=0, failed=0, skipped=0,
message="暂无绑定可同步",
logs=[],
)
results: list[WebsiteSyncLog] = []
for binding in bindings:
try:
log = sync_binding(db, binding, write=True)
results.append(log)
except Exception as exc:
logger.exception("batch sync failed for binding %s", binding.id)
# Create and persist a synthetic failed log if sync_binding crashed before creating one
synthetic_log = WebsiteSyncLog(
website_id=wid,
binding_id=binding.id,
target_group_id=binding.target_group_id,
target_group_name=binding.target_group_name,
algorithm=binding.algorithm,
percent=binding.percent,
source_rates_json="[]",
status="failed",
message=str(exc),
created_at=datetime.now(timezone.utc),
)
db.add(synthetic_log)
db.commit()
db.refresh(synthetic_log)
results.append(synthetic_log)
success_count = sum(1 for r in results if r.status == "success")
failed_count = sum(1 for r in results if r.status == "failed")
skipped_count = sum(1 for r in results if r.status == "skipped")
msg_parts = []
if success_count: msg_parts.append(f"成功 {success_count}")
if failed_count: msg_parts.append(f"失败 {failed_count}")
if skipped_count: msg_parts.append(f"跳过 {skipped_count}")
return WebsiteBatchSyncResponse(
total=len(bindings),
success=success_count,
failed=failed_count,
skipped=skipped_count,
message=f"同步完成:{''.join(msg_parts)}" if msg_parts else "同步完成",
logs=[_log_response(r) for r in results],
)
@router.post("/api/group-bindings", response_model=BindingResponse, status_code=201)
def create_binding(body: BindingCreate, db: Session = Depends(get_db), _=Depends(get_current_user)):
website = db.query(Website).filter(Website.id == body.website_id).first()
+9
View File
@@ -178,3 +178,12 @@ class ImportAccountsResponse(BaseModel):
success: bool
message: str
items: list[ImportAccountItem]
class WebsiteBatchSyncResponse(BaseModel):
total: int
success: int
failed: int
skipped: int
message: str
logs: list[WebsiteSyncLogResponse]