feat: add one-click sync for website group bindings
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user