fix(priority): keep readable priority sync details
This commit is contained in:
@@ -579,6 +579,16 @@ def import_upstream_keys_as_accounts(
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
with _client(website) as c:
|
with _client(website) as c:
|
||||||
|
target_group_names: dict[str, str] = {}
|
||||||
|
try:
|
||||||
|
grps = c.get_groups(endpoint=website.groups_endpoint) or []
|
||||||
|
for g in grps:
|
||||||
|
g_id = g.get("id")
|
||||||
|
if g_id is not None:
|
||||||
|
target_group_names[str(g_id)] = g.get("name") or str(g_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("failed to fetch groups for website %s at import: %s", wid, e)
|
||||||
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
# 跳过远端已不存在或导入失败的 Key(对账后标记为 orphaned / import_failed)
|
# 跳过远端已不存在或导入失败的 Key(对账后标记为 orphaned / import_failed)
|
||||||
if row.status in ("orphaned", "failed", "import_failed"):
|
if row.status in ("orphaned", "failed", "import_failed"):
|
||||||
@@ -608,9 +618,12 @@ def import_upstream_keys_as_accounts(
|
|||||||
if exists is True:
|
if exists is True:
|
||||||
# 顺手回填 imported_target_group_id(老数据升级后可通过重导自动补齐)
|
# 顺手回填 imported_target_group_id(老数据升级后可通过重导自动补齐)
|
||||||
new_tgid = body.target_group_map.get(row.group_id) or None
|
new_tgid = body.target_group_map.get(row.group_id) or None
|
||||||
if new_tgid and row.imported_target_group_id != new_tgid:
|
if new_tgid:
|
||||||
row.imported_target_group_id = new_tgid
|
tg_name = target_group_names.get(str(new_tgid))
|
||||||
db.commit()
|
if row.imported_target_group_id != new_tgid or row.imported_target_group_name != tg_name:
|
||||||
|
row.imported_target_group_id = new_tgid
|
||||||
|
row.imported_target_group_name = tg_name
|
||||||
|
db.commit()
|
||||||
items.append(ImportAccountItem(
|
items.append(ImportAccountItem(
|
||||||
upstream_key_id=row.id,
|
upstream_key_id=row.id,
|
||||||
source_group_id=row.group_id,
|
source_group_id=row.group_id,
|
||||||
@@ -683,7 +696,7 @@ def import_upstream_keys_as_accounts(
|
|||||||
row.imported_account_id = account_id or None
|
row.imported_account_id = account_id or None
|
||||||
row.imported_at = datetime.now(timezone.utc)
|
row.imported_at = datetime.now(timezone.utc)
|
||||||
row.imported_target_group_id = target_group_id or None
|
row.imported_target_group_id = target_group_id or None
|
||||||
row.imported_target_group_name = None # target_group_map 只存 ID,name 展示用可留 NULL
|
row.imported_target_group_name = target_group_names.get(str(target_group_id)) if target_group_id else None
|
||||||
row.status = "imported"
|
row.status = "imported"
|
||||||
row.error = None
|
row.error = None
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|||||||
@@ -192,6 +192,12 @@ class ReorderPriorityItem(BaseModel):
|
|||||||
new_priority: Optional[int] = None
|
new_priority: Optional[int] = None
|
||||||
status: str
|
status: str
|
||||||
message: str = ""
|
message: str = ""
|
||||||
|
target_group_id: Optional[str] = None
|
||||||
|
target_group_name: Optional[str] = None
|
||||||
|
account_name: Optional[str] = None
|
||||||
|
source_group_id: Optional[str] = None
|
||||||
|
source_group_name: Optional[str] = None
|
||||||
|
source_rate: Optional[float] = None
|
||||||
|
|
||||||
|
|
||||||
class ReorderPriorityResponse(BaseModel):
|
class ReorderPriorityResponse(BaseModel):
|
||||||
|
|||||||
@@ -247,10 +247,11 @@ def _priority_result(
|
|||||||
account_name: str | None = None,
|
account_name: str | None = None,
|
||||||
old_priority: Any = None,
|
old_priority: Any = None,
|
||||||
source_rate: float | None = None,
|
source_rate: float | None = None,
|
||||||
|
target_group_name: str | None = None,
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""构建统一的优先级同步结果 dict,支持丰富的展示和后向兼容性。"""
|
"""构建统一的优先级同步结果 dict,支持丰富的展示和后向兼容性。"""
|
||||||
tg_id = row.imported_target_group_id or row.group_id
|
tg_id = row.imported_target_group_id or row.group_id
|
||||||
tg_name = row.imported_target_group_name or tg_id
|
tg_name = target_group_name or row.imported_target_group_name or tg_id
|
||||||
return {
|
return {
|
||||||
# 兼容旧字段
|
# 兼容旧字段
|
||||||
"account_id": row.imported_account_id,
|
"account_id": row.imported_account_id,
|
||||||
@@ -547,8 +548,9 @@ def sync_account_priorities_for_upstream(
|
|||||||
auth_config=json.loads(website.auth_config_json or "{}"),
|
auth_config=json.loads(website.auth_config_json or "{}"),
|
||||||
timeout=float(website.timeout_seconds),
|
timeout=float(website.timeout_seconds),
|
||||||
) as client:
|
) as client:
|
||||||
# 尽量拉取目标网站账号列表以获取账号名称和旧 priority,失败不阻断
|
# 尽量拉取目标网站账号列表以获取账号名称和旧 priority,并拉取分组以获取分组名称,失败不阻断
|
||||||
account_info_map: dict[str, dict[str, Any]] = {}
|
account_info_map: dict[str, dict[str, Any]] = {}
|
||||||
|
target_group_names: dict[str, str] = {}
|
||||||
try:
|
try:
|
||||||
remote_accounts = client.list_accounts() or []
|
remote_accounts = client.list_accounts() or []
|
||||||
for acc in remote_accounts:
|
for acc in remote_accounts:
|
||||||
@@ -561,6 +563,15 @@ def sync_account_priorities_for_upstream(
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning("failed to fetch remote accounts for website %s: %s", wid, e)
|
logger.warning("failed to fetch remote accounts for website %s: %s", wid, e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
grps = client.get_groups(endpoint=website.groups_endpoint) or []
|
||||||
|
for g in grps:
|
||||||
|
g_id = g.get("id")
|
||||||
|
if g_id is not None:
|
||||||
|
target_group_names[str(g_id)] = g.get("name") or str(g_id)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("failed to fetch groups for website %s at sync: %s", wid, e)
|
||||||
|
|
||||||
for comp_rows in competitive_buckets.values():
|
for comp_rows in competitive_buckets.values():
|
||||||
for row in comp_rows:
|
for row in comp_rows:
|
||||||
account_id = row.imported_account_id
|
account_id = row.imported_account_id
|
||||||
@@ -573,6 +584,12 @@ def sync_account_priorities_for_upstream(
|
|||||||
old_prio = acc_info.get("priority")
|
old_prio = acc_info.get("priority")
|
||||||
src_rate = raw_rate_map.get(f"{row.upstream_id}:{row.group_id}")
|
src_rate = raw_rate_map.get(f"{row.upstream_id}:{row.group_id}")
|
||||||
|
|
||||||
|
tg_id_str = str(row.imported_target_group_id or row.group_id)
|
||||||
|
tg_name = target_group_names.get(tg_id_str)
|
||||||
|
if tg_name and row.imported_target_group_name != tg_name:
|
||||||
|
row.imported_target_group_name = tg_name
|
||||||
|
db.commit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
client.update_account(account_id, {"priority": new_priority})
|
client.update_account(account_id, {"priority": new_priority})
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -590,6 +607,7 @@ def sync_account_priorities_for_upstream(
|
|||||||
account_name=acc_name,
|
account_name=acc_name,
|
||||||
old_priority=old_prio,
|
old_priority=old_prio,
|
||||||
source_rate=src_rate,
|
source_rate=src_rate,
|
||||||
|
target_group_name=tg_name or row.imported_target_group_name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@@ -606,6 +624,7 @@ def sync_account_priorities_for_upstream(
|
|||||||
account_name=acc_name,
|
account_name=acc_name,
|
||||||
old_priority=old_prio,
|
old_priority=old_prio,
|
||||||
source_rate=src_rate,
|
source_rate=src_rate,
|
||||||
|
target_group_name=tg_name or row.imported_target_group_name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|||||||
@@ -619,6 +619,10 @@ def test_priority_sync_fetches_remote_accounts_and_backfills_info(db_session, mo
|
|||||||
{"id": "A1", "name": "SmartUp-A1-Name", "priority": 15},
|
{"id": "A1", "name": "SmartUp-A1-Name", "priority": 15},
|
||||||
{"id": "A2", "name": "SmartUp-A2-Name", "priority": 25},
|
{"id": "A2", "name": "SmartUp-A2-Name", "priority": 25},
|
||||||
]
|
]
|
||||||
|
def get_groups(self, *args, **kwargs):
|
||||||
|
return [
|
||||||
|
{"id": "TG1", "name": "TG1-Readable-Group-Name"}
|
||||||
|
]
|
||||||
def update_account(self, account_id, data):
|
def update_account(self, account_id, data):
|
||||||
update_calls.append((account_id, data))
|
update_calls.append((account_id, data))
|
||||||
|
|
||||||
@@ -634,7 +638,7 @@ def test_priority_sync_fetches_remote_accounts_and_backfills_info(db_session, mo
|
|||||||
assert res_a1["new_priority"] == 1
|
assert res_a1["new_priority"] == 1
|
||||||
assert res_a1["source_rate"] == 1.0
|
assert res_a1["source_rate"] == 1.0
|
||||||
assert res_a1["target_group_id"] == "TG1"
|
assert res_a1["target_group_id"] == "TG1"
|
||||||
assert res_a1["target_group_name"] == "TG1" # fallback to tg_id since target_group_name is not set
|
assert res_a1["target_group_name"] == "TG1-Readable-Group-Name"
|
||||||
|
|
||||||
res_a2 = next(r for r in results if r["account_id"] == "A2")
|
res_a2 = next(r for r in results if r["account_id"] == "A2")
|
||||||
assert res_a2["account_name"] == "SmartUp-A2-Name"
|
assert res_a2["account_name"] == "SmartUp-A2-Name"
|
||||||
@@ -642,6 +646,10 @@ def test_priority_sync_fetches_remote_accounts_and_backfills_info(db_session, mo
|
|||||||
assert res_a2["new_priority"] == 11
|
assert res_a2["new_priority"] == 11
|
||||||
assert res_a2["source_rate"] == 2.0
|
assert res_a2["source_rate"] == 2.0
|
||||||
|
|
||||||
|
# 验证本地 DB 中行的 imported_target_group_name 被正确更新写入
|
||||||
|
row1 = db_session.query(UpstreamGeneratedKey).filter_by(imported_account_id="A1").first()
|
||||||
|
assert row1.imported_target_group_name == "TG1-Readable-Group-Name"
|
||||||
|
|
||||||
|
|
||||||
def test_priority_sync_graceful_on_remote_list_failure(db_session, monkeypatch):
|
def test_priority_sync_graceful_on_remote_list_failure(db_session, monkeypatch):
|
||||||
"""验证 list_accounts 抛异常时,优先级同步依然成功更新,且各项降级为账号 ID 和未知。"""
|
"""验证 list_accounts 抛异常时,优先级同步依然成功更新,且各项降级为账号 ID 和未知。"""
|
||||||
@@ -677,4 +685,3 @@ def test_priority_sync_graceful_on_remote_list_failure(db_session, monkeypatch):
|
|||||||
assert res_a1["old_priority"] is None
|
assert res_a1["old_priority"] is None
|
||||||
assert res_a1["new_priority"] == 1
|
assert res_a1["new_priority"] == 1
|
||||||
assert res_a1["status"] == "success"
|
assert res_a1["status"] == "success"
|
||||||
|
|
||||||
|
|||||||
@@ -299,6 +299,12 @@ export interface ReorderPriorityItem {
|
|||||||
new_priority: number | null
|
new_priority: number | null
|
||||||
status: string
|
status: string
|
||||||
message: string
|
message: string
|
||||||
|
target_group_id?: string | null
|
||||||
|
target_group_name?: string | null
|
||||||
|
account_name?: string | null
|
||||||
|
source_group_id?: string | null
|
||||||
|
source_group_name?: string | null
|
||||||
|
source_rate?: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WebsiteBatchSyncResponse {
|
export interface WebsiteBatchSyncResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user