feat: resolve account platforms prioritizing structural snapshot values and correction on existing accounts
This commit is contained in:
@@ -462,6 +462,17 @@ def import_groups_from_upstream(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SUPPORTED_PLATFORMS = {"openai", "anthropic", "gemini", "antigravity"}
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_platform(text: str, group_snapshot: dict | None, fallback: str = "openai") -> str:
|
||||||
|
if group_snapshot and isinstance(group_snapshot, dict):
|
||||||
|
platform = group_snapshot.get("platform")
|
||||||
|
if platform and str(platform).lower() in SUPPORTED_PLATFORMS:
|
||||||
|
return str(platform).lower()
|
||||||
|
return _detect_platform(text, fallback)
|
||||||
|
|
||||||
|
|
||||||
def _detect_platform(text: str, fallback: str = "openai") -> str:
|
def _detect_platform(text: str, fallback: str = "openai") -> str:
|
||||||
"""根据 Key 名或分组名关键词判断平台类型。"""
|
"""根据 Key 名或分组名关键词判断平台类型。"""
|
||||||
lower = text.lower()
|
lower = text.lower()
|
||||||
@@ -496,6 +507,12 @@ def sync_imported_upstream_keys(
|
|||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
items: list[ImportAccountItem] = []
|
items: list[ImportAccountItem] = []
|
||||||
|
# 预载最新快照映射,用于结构化 platform 解析
|
||||||
|
upstream_ids = {row.upstream_id for row in rows}
|
||||||
|
latest_snapshots = {}
|
||||||
|
for uid in upstream_ids:
|
||||||
|
latest_snapshots[uid] = latest_rate_map(db, uid)
|
||||||
|
|
||||||
with _client(website) as c:
|
with _client(website) as c:
|
||||||
remote_accounts = None
|
remote_accounts = None
|
||||||
try:
|
try:
|
||||||
@@ -513,7 +530,9 @@ def sync_imported_upstream_keys(
|
|||||||
remote_ids = None
|
remote_ids = None
|
||||||
|
|
||||||
for row in rows:
|
for row in rows:
|
||||||
platform = _detect_platform(f"{row.group_name} {row.group_id} {row.key_name}", "openai")
|
snap_groups = latest_snapshots.get(row.upstream_id) or {}
|
||||||
|
group_snap = snap_groups.get(row.group_id) if isinstance(snap_groups, dict) else None
|
||||||
|
platform = _resolve_platform(f"{row.group_name} {row.group_id} {row.key_name}", group_snap, "openai")
|
||||||
if not row.imported_account_id:
|
if not row.imported_account_id:
|
||||||
continue
|
continue
|
||||||
old_account_id = row.imported_account_id
|
old_account_id = row.imported_account_id
|
||||||
@@ -645,12 +664,17 @@ def import_upstream_keys_as_accounts(
|
|||||||
)
|
)
|
||||||
for kid in missing_ids
|
for kid in missing_ids
|
||||||
]
|
]
|
||||||
# 预载上游以方便获取名称和 base_url
|
# 预载上游以方便获取名称 and base_url
|
||||||
from app.models.upstream import Upstream as _Up
|
from app.models.upstream import Upstream as _Up
|
||||||
upstream_ids = {row.upstream_id for row in rows}
|
upstream_ids = {row.upstream_id for row in rows}
|
||||||
upstreams_db = db.query(_Up).filter(_Up.id.in_(upstream_ids)).all()
|
upstreams_db = db.query(_Up).filter(_Up.id.in_(upstream_ids)).all()
|
||||||
upstreams_map = {u.id: u for u in upstreams_db}
|
upstreams_map = {u.id: u for u in upstreams_db}
|
||||||
|
|
||||||
|
# 预载最新快照映射,用于结构化 platform 解析
|
||||||
|
latest_snapshots: dict[int, dict[str, Any]] = {}
|
||||||
|
for uid in upstream_ids:
|
||||||
|
latest_snapshots[uid] = latest_rate_map(db, uid)
|
||||||
|
|
||||||
# 按倍率自动分配优先级
|
# 按倍率自动分配优先级
|
||||||
rate_priority_map: dict[tuple[str, int, str], int] = {}
|
rate_priority_map: dict[tuple[str, int, str], int] = {}
|
||||||
if body.auto_priority_by_rate:
|
if body.auto_priority_by_rate:
|
||||||
@@ -706,8 +730,11 @@ def import_upstream_keys_as_accounts(
|
|||||||
continue
|
continue
|
||||||
# 先确定平台(失败项也需要记录)
|
# 先确定平台(失败项也需要记录)
|
||||||
if body.platform_mode == "auto":
|
if body.platform_mode == "auto":
|
||||||
platform = _detect_platform(
|
snap_groups = latest_snapshots.get(row.upstream_id) or {}
|
||||||
|
group_snap = snap_groups.get(row.group_id) if isinstance(snap_groups, dict) else None
|
||||||
|
platform = _resolve_platform(
|
||||||
f"{row.group_name} {row.group_id} {row.key_name}",
|
f"{row.group_name} {row.group_id} {row.key_name}",
|
||||||
|
group_snap,
|
||||||
body.default_platform,
|
body.default_platform,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -1644,6 +1671,18 @@ def organize_website_groups(
|
|||||||
if acc_id:
|
if acc_id:
|
||||||
remote_account_map[str(acc_id)] = acc
|
remote_account_map[str(acc_id)] = acc
|
||||||
|
|
||||||
|
# 预载所有相关的上游快照映射
|
||||||
|
all_upstream_ids = set()
|
||||||
|
for b in bindings:
|
||||||
|
for src in binding_sources(b):
|
||||||
|
_uid = src.get("upstream_id")
|
||||||
|
if _uid:
|
||||||
|
all_upstream_ids.add(int(_uid))
|
||||||
|
|
||||||
|
latest_snapshots: dict[int, dict[str, Any]] = {}
|
||||||
|
for _uid in all_upstream_ids:
|
||||||
|
latest_snapshots[_uid] = latest_rate_map(db, _uid)
|
||||||
|
|
||||||
# 对每个绑定关系遍历其对应的上游 Key 进行整理
|
# 对每个绑定关系遍历其对应的上游 Key 进行整理
|
||||||
for b in bindings:
|
for b in bindings:
|
||||||
target_group_id = b.target_group_id
|
target_group_id = b.target_group_id
|
||||||
@@ -1659,14 +1698,10 @@ def organize_website_groups(
|
|||||||
_u = db.query(Upstream).filter(Upstream.id == uid).first()
|
_u = db.query(Upstream).filter(Upstream.id == uid).first()
|
||||||
upstream_name = _u.name if _u else f"#{uid}"
|
upstream_name = _u.name if _u else f"#{uid}"
|
||||||
|
|
||||||
|
snapshot_groups = latest_snapshots.get(int(uid)) or {}
|
||||||
# 来源名称优先取 src.group_name,再 fallback 快照,再 fallback ID
|
# 来源名称优先取 src.group_name,再 fallback 快照,再 fallback ID
|
||||||
source_group_name = src.get("group_name") or ""
|
source_group_name = src.get("group_name") or ""
|
||||||
if not source_group_name:
|
if not source_group_name:
|
||||||
snapshot_groups = {}
|
|
||||||
try:
|
|
||||||
snapshot_groups = latest_rate_map(db, uid)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
if gid in snapshot_groups:
|
if gid in snapshot_groups:
|
||||||
g_data = snapshot_groups[gid]
|
g_data = snapshot_groups[gid]
|
||||||
if isinstance(g_data, dict):
|
if isinstance(g_data, dict):
|
||||||
@@ -1725,8 +1760,10 @@ def organize_website_groups(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# 检测平台类型
|
# 检测平台类型
|
||||||
platform = _detect_platform(
|
group_snap = snapshot_groups.get(row.group_id) if isinstance(snapshot_groups, dict) else None
|
||||||
|
platform = _resolve_platform(
|
||||||
f"{row.group_name} {row.group_id} {row.key_name}",
|
f"{row.group_name} {row.group_id} {row.key_name}",
|
||||||
|
group_snap,
|
||||||
"openai",
|
"openai",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1771,11 +1808,31 @@ def organize_website_groups(
|
|||||||
old_set = {str(g) for g in current_group_ids}
|
old_set = {str(g) for g in current_group_ids}
|
||||||
new_set = {str(g) for g in new_group_ids}
|
new_set = {str(g) for g in new_group_ids}
|
||||||
|
|
||||||
|
remote_platform = remote_acc.get("platform")
|
||||||
|
if remote_platform is not None:
|
||||||
|
platform_mismatch = (str(remote_platform).lower() != str(platform).lower())
|
||||||
|
else:
|
||||||
|
platform_mismatch = (str(platform).lower() != "openai")
|
||||||
|
|
||||||
|
update_payload = {}
|
||||||
if old_set != new_set:
|
if old_set != new_set:
|
||||||
c.update_account(old_account_id, {"group_ids": new_group_ids})
|
update_payload["group_ids"] = new_group_ids
|
||||||
# 顺便更新下 remote_account_map 中的数据,防止同个账号后续在其他绑定中重复处理
|
if platform_mismatch:
|
||||||
|
update_payload["platform"] = platform
|
||||||
|
|
||||||
|
if update_payload:
|
||||||
|
c.update_account(old_account_id, update_payload)
|
||||||
|
if "group_ids" in update_payload:
|
||||||
remote_acc["group_ids"] = new_group_ids
|
remote_acc["group_ids"] = new_group_ids
|
||||||
msg = "已存在,已迁移到目标分组"
|
if "platform" in update_payload:
|
||||||
|
remote_acc["platform"] = platform
|
||||||
|
|
||||||
|
msg_parts = []
|
||||||
|
if old_set != new_set:
|
||||||
|
msg_parts.append("已迁移到目标分组")
|
||||||
|
if platform_mismatch:
|
||||||
|
msg_parts.append(f"平台从 {remote_platform} 修正为 {platform}")
|
||||||
|
msg = "已存在," + "且".join(msg_parts)
|
||||||
else:
|
else:
|
||||||
msg = "已存在且已对齐,已跳过"
|
msg = "已存在且已对齐,已跳过"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
|
||||||
|
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
from app.database import SessionLocal
|
||||||
|
from app.models.website import Website
|
||||||
|
from app.routers.websites import _client
|
||||||
|
|
||||||
|
db = SessionLocal()
|
||||||
|
try:
|
||||||
|
website = db.query(Website).filter(Website.id == 2).first()
|
||||||
|
if not website:
|
||||||
|
print("Error: website wangwang888 (id=2) not found!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Loaded website: {website.name}, URL: {website.base_url}")
|
||||||
|
|
||||||
|
with _client(website) as c:
|
||||||
|
accounts = c.list_accounts()
|
||||||
|
acc = next((a for a in accounts if str(c.extract_id(a)) == "935"), None)
|
||||||
|
if not acc:
|
||||||
|
print("Error: Account 935 not found on remote site!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
print(f"Found account 935: {acc.get('name')}, current platform: {acc.get('platform')}")
|
||||||
|
|
||||||
|
res = c.update_account("935", {"platform": "anthropic"})
|
||||||
|
print(f"Update response: {res}")
|
||||||
|
|
||||||
|
accounts_new = c.list_accounts()
|
||||||
|
acc_new = next((a for a in accounts_new if str(c.extract_id(a)) == "935"), None)
|
||||||
|
print(f"Verified account 935: {acc_new.get('name')}, new platform: {acc_new.get('platform')}")
|
||||||
|
finally:
|
||||||
|
db.close()
|
||||||
@@ -479,3 +479,102 @@ def test_organize_groups_force_alignment(db_session, monkeypatch):
|
|||||||
# 既然已经一致,不会触发 update_account
|
# 既然已经一致,不会触发 update_account
|
||||||
assert len(updated_accounts) == 0
|
assert len(updated_accounts) == 0
|
||||||
assert "已存在且已对齐 2" in response_aligned.message
|
assert "已存在且已对齐 2" in response_aligned.message
|
||||||
|
|
||||||
|
|
||||||
|
def test_organize_groups_corrects_mismatched_platform_instead_of_recreating(db_session, monkeypatch):
|
||||||
|
"""测试一键整理遇到已存在账号平台错配时,只调用 update_account() 修正平台,不创建新账号。"""
|
||||||
|
from app.models.snapshot import UpstreamRateSnapshot
|
||||||
|
|
||||||
|
w = Website(
|
||||||
|
name="W1",
|
||||||
|
site_type="sub2api",
|
||||||
|
base_url="http://w1",
|
||||||
|
enabled=True,
|
||||||
|
auth_config_json="{}",
|
||||||
|
timeout_seconds=30
|
||||||
|
)
|
||||||
|
u1 = Upstream(name="U1", base_url="http://u1")
|
||||||
|
db_session.add_all([w, u1])
|
||||||
|
db_session.commit()
|
||||||
|
db_session.refresh(w)
|
||||||
|
db_session.refresh(u1)
|
||||||
|
|
||||||
|
# 绑定关系:目标分组 TG1 ↔ G1
|
||||||
|
b1 = WebsiteGroupBinding(
|
||||||
|
website_id=w.id,
|
||||||
|
target_group_id="TG1",
|
||||||
|
target_group_name="TG1-Group",
|
||||||
|
source_groups_json=json.dumps([{"upstream_id": u1.id, "group_id": "G1"}]),
|
||||||
|
enabled=True
|
||||||
|
)
|
||||||
|
db_session.add(b1)
|
||||||
|
|
||||||
|
# G1: 已导入,导入的目标分组为 TG1,账号为 ACC-G1
|
||||||
|
k1 = UpstreamGeneratedKey(
|
||||||
|
upstream_id=u1.id,
|
||||||
|
group_id="G1",
|
||||||
|
group_name="G1-Group",
|
||||||
|
key_name="Key-G1",
|
||||||
|
key_value="sk-g1-secret",
|
||||||
|
status="imported",
|
||||||
|
imported_website_id=w.id,
|
||||||
|
imported_account_id="ACC-G1",
|
||||||
|
imported_target_group_id="TG1",
|
||||||
|
)
|
||||||
|
db_session.add(k1)
|
||||||
|
|
||||||
|
# 写入快照指定平台为 anthropic
|
||||||
|
snapshot = UpstreamRateSnapshot(
|
||||||
|
upstream_id=u1.id,
|
||||||
|
snapshot_json=json.dumps({
|
||||||
|
"groups": {
|
||||||
|
"G1": {
|
||||||
|
"group_name": "G1-Group",
|
||||||
|
"rate": 0.1,
|
||||||
|
"platform": "anthropic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
db_session.add(snapshot)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
updated_accounts = []
|
||||||
|
create_called = False
|
||||||
|
|
||||||
|
class MockClient:
|
||||||
|
def __init__(self, **kwargs): pass
|
||||||
|
def __enter__(self): return self
|
||||||
|
def __exit__(self, *a): pass
|
||||||
|
def get_groups(self, *a, **kw):
|
||||||
|
return [{"id": "TG1", "name": "TG1-Group"}]
|
||||||
|
def list_accounts(self):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"id": "ACC-G1",
|
||||||
|
"name": "SmartUp-G1",
|
||||||
|
"group_ids": ["TG1"],
|
||||||
|
"platform": "openai",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
def extract_id(self, val):
|
||||||
|
return val.get("id") if isinstance(val, dict) else str(val)
|
||||||
|
def create_account(self, body):
|
||||||
|
nonlocal create_called
|
||||||
|
create_called = True
|
||||||
|
return {"id": "NEW-ACC", "name": body["name"], "group_ids": body["group_ids"]}
|
||||||
|
def update_account(self, account_id, body):
|
||||||
|
updated_accounts.append((account_id, body))
|
||||||
|
return {"id": account_id, "platform": body.get("platform")}
|
||||||
|
|
||||||
|
monkeypatch.setattr("app.routers.websites.Sub2ApiWebsiteClient", MockClient)
|
||||||
|
monkeypatch.setattr("app.routers.websites.sync_account_priorities_for_website", lambda db, wid: [])
|
||||||
|
|
||||||
|
response = organize_website_groups(wid=w.id, db=db_session)
|
||||||
|
|
||||||
|
assert response.success is True
|
||||||
|
assert not create_called
|
||||||
|
assert len(updated_accounts) == 1
|
||||||
|
assert updated_accounts[0][0] == "ACC-G1"
|
||||||
|
assert updated_accounts[0][1]["platform"] == "anthropic"
|
||||||
|
assert "平台从 openai 修正为 anthropic" in response.items[0].message
|
||||||
|
|||||||
@@ -410,3 +410,157 @@ def test_import_upstream_key_with_custom_concurrency_and_priority(monkeypatch, d
|
|||||||
assert body["concurrency"] == 20
|
assert body["concurrency"] == 20
|
||||||
assert body["priority"] == 5
|
assert body["priority"] == 5
|
||||||
assert body["credentials"]["base_url"] == "http://packy.local"
|
assert body["credentials"]["base_url"] == "http://packy.local"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_platform_from_snapshot(monkeypatch, db_session):
|
||||||
|
"""验证快照 platform=anthropic 且名称不含 Claude 时,创建账号平台必须为 anthropic"""
|
||||||
|
from app.models.snapshot import UpstreamRateSnapshot
|
||||||
|
website, generated = seed_account_import_rows(db_session)
|
||||||
|
generated.key_name = "MyCustomKey" # 不含 Claude
|
||||||
|
|
||||||
|
# 写入快照指定平台为 anthropic
|
||||||
|
snapshot = UpstreamRateSnapshot(
|
||||||
|
upstream_id=generated.upstream_id,
|
||||||
|
snapshot_json=json.dumps({
|
||||||
|
"groups": {
|
||||||
|
"vip": {
|
||||||
|
"group_name": "VIP",
|
||||||
|
"rate": 0.1,
|
||||||
|
"platform": "anthropic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
db_session.add(snapshot)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
account_bodies = []
|
||||||
|
class FakeWebsiteClient:
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
pass
|
||||||
|
def __enter__(self): return self
|
||||||
|
def __exit__(self, *args): return False
|
||||||
|
def create_account(self, body, endpoint="/accounts"):
|
||||||
|
account_bodies.append(body)
|
||||||
|
return {"id": 101, "name": body["name"]}
|
||||||
|
def account_exists(self, account_id): return True
|
||||||
|
@staticmethod
|
||||||
|
def extract_id(data): return "101"
|
||||||
|
|
||||||
|
monkeypatch.setattr(websites_router, "Sub2ApiWebsiteClient", FakeWebsiteClient)
|
||||||
|
|
||||||
|
websites_router.import_upstream_keys_as_accounts(
|
||||||
|
website.id,
|
||||||
|
ImportAccountsRequest(
|
||||||
|
upstream_key_ids=[generated.id],
|
||||||
|
target_group_map={"vip": "7"},
|
||||||
|
default_platform="openai",
|
||||||
|
platform_mode="auto",
|
||||||
|
),
|
||||||
|
db_session,
|
||||||
|
object(),
|
||||||
|
)
|
||||||
|
assert len(account_bodies) == 1
|
||||||
|
assert account_bodies[0]["platform"] == "anthropic"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_platform_fallback_to_name(monkeypatch, db_session):
|
||||||
|
"""验证快照无 platform 但名称含 Claude 时,仍兜底为 anthropic"""
|
||||||
|
from app.models.snapshot import UpstreamRateSnapshot
|
||||||
|
website, generated = seed_account_import_rows(db_session)
|
||||||
|
generated.key_name = "Claude-Key"
|
||||||
|
|
||||||
|
# 写入快照但不含 platform 字段
|
||||||
|
snapshot = UpstreamRateSnapshot(
|
||||||
|
upstream_id=generated.upstream_id,
|
||||||
|
snapshot_json=json.dumps({
|
||||||
|
"groups": {
|
||||||
|
"vip": {
|
||||||
|
"group_name": "VIP",
|
||||||
|
"rate": 0.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
db_session.add(snapshot)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
account_bodies = []
|
||||||
|
class FakeWebsiteClient:
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
pass
|
||||||
|
def __enter__(self): return self
|
||||||
|
def __exit__(self, *args): return False
|
||||||
|
def create_account(self, body, endpoint="/accounts"):
|
||||||
|
account_bodies.append(body)
|
||||||
|
return {"id": 101, "name": body["name"]}
|
||||||
|
def account_exists(self, account_id): return True
|
||||||
|
@staticmethod
|
||||||
|
def extract_id(data): return "101"
|
||||||
|
|
||||||
|
monkeypatch.setattr(websites_router, "Sub2ApiWebsiteClient", FakeWebsiteClient)
|
||||||
|
|
||||||
|
websites_router.import_upstream_keys_as_accounts(
|
||||||
|
website.id,
|
||||||
|
ImportAccountsRequest(
|
||||||
|
upstream_key_ids=[generated.id],
|
||||||
|
target_group_map={"vip": "7"},
|
||||||
|
default_platform="openai",
|
||||||
|
platform_mode="auto",
|
||||||
|
),
|
||||||
|
db_session,
|
||||||
|
object(),
|
||||||
|
)
|
||||||
|
assert len(account_bodies) == 1
|
||||||
|
assert account_bodies[0]["platform"] == "anthropic"
|
||||||
|
|
||||||
|
|
||||||
|
def test_import_platform_manual_override(monkeypatch, db_session):
|
||||||
|
"""手动模式下不使用快照平台,仍按用户指定平台"""
|
||||||
|
from app.models.snapshot import UpstreamRateSnapshot
|
||||||
|
website, generated = seed_account_import_rows(db_session)
|
||||||
|
|
||||||
|
# 快照虽然指定为 anthropic
|
||||||
|
snapshot = UpstreamRateSnapshot(
|
||||||
|
upstream_id=generated.upstream_id,
|
||||||
|
snapshot_json=json.dumps({
|
||||||
|
"groups": {
|
||||||
|
"vip": {
|
||||||
|
"group_name": "VIP",
|
||||||
|
"rate": 0.1,
|
||||||
|
"platform": "anthropic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
db_session.add(snapshot)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
account_bodies = []
|
||||||
|
class FakeWebsiteClient:
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
pass
|
||||||
|
def __enter__(self): return self
|
||||||
|
def __exit__(self, *args): return False
|
||||||
|
def create_account(self, body, endpoint="/accounts"):
|
||||||
|
account_bodies.append(body)
|
||||||
|
return {"id": 101, "name": body["name"]}
|
||||||
|
def account_exists(self, account_id): return True
|
||||||
|
@staticmethod
|
||||||
|
def extract_id(data): return "101"
|
||||||
|
|
||||||
|
monkeypatch.setattr(websites_router, "Sub2ApiWebsiteClient", FakeWebsiteClient)
|
||||||
|
|
||||||
|
websites_router.import_upstream_keys_as_accounts(
|
||||||
|
website.id,
|
||||||
|
ImportAccountsRequest(
|
||||||
|
upstream_key_ids=[generated.id],
|
||||||
|
target_group_map={"vip": "7"},
|
||||||
|
default_platform="gemini",
|
||||||
|
platform_mode="manual", # 手动模式
|
||||||
|
),
|
||||||
|
db_session,
|
||||||
|
object(),
|
||||||
|
)
|
||||||
|
assert len(account_bodies) == 1
|
||||||
|
assert account_bodies[0]["platform"] == "gemini"
|
||||||
|
|||||||
Reference in New Issue
Block a user