feat: account ensure-web (pick-or-create for first-run UX)
All checks were successful
技能自动化发布 / release (push) Successful in 5s
All checks were successful
技能自动化发布 / release (push) Successful in 5s
This commit is contained in:
161
scripts/service/account_ensure_commands.py
Normal file
161
scripts/service/account_ensure_commands.py
Normal file
@@ -0,0 +1,161 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""account ensure-web — pick if present, otherwise add-web then pick."""
|
||||
from typing import Optional
|
||||
|
||||
from db.accounts_repo import count_active_accounts
|
||||
from db.connection import get_conn, init_db
|
||||
from service._svc_common import PlatformCallerMeta, _err_json, _resolve_or_auto_register, _say
|
||||
from service.account_add_commands import create_web_account_record
|
||||
from service.account_query_commands import cmd_account_pick_web
|
||||
from util.logging_config import get_skill_logger
|
||||
from util.platforms import seed_platforms
|
||||
|
||||
|
||||
def cmd_account_ensure_web(
|
||||
platform_input: str,
|
||||
*,
|
||||
login_id: Optional[str] = None,
|
||||
login_id_type: str = "unknown",
|
||||
label: Optional[str] = None,
|
||||
tenant_id: Optional[str] = None,
|
||||
environment: Optional[str] = None,
|
||||
role: Optional[str] = None,
|
||||
provider_code: Optional[str] = None,
|
||||
url: Optional[str] = None,
|
||||
extra_json_str: Optional[str] = None,
|
||||
profile_dir_override: Optional[str] = None,
|
||||
auth_strategy: Optional[str] = None,
|
||||
session_persistent: Optional[int] = None,
|
||||
device_fingerprint: Optional[str] = None,
|
||||
do_lease: bool = False,
|
||||
ttl_sec: int = 900,
|
||||
holder: Optional[str] = None,
|
||||
purpose: Optional[str] = None,
|
||||
platform_meta: Optional[PlatformCallerMeta] = None,
|
||||
) -> None:
|
||||
"""Pick a web account; if none exist for filters, create one then pick.
|
||||
|
||||
Does NOT create a new account when matching accounts exist but are all leased.
|
||||
Success stdout matches ``account pick-web`` (plus ``account_ensured`` when created).
|
||||
"""
|
||||
log = get_skill_logger()
|
||||
log.info(
|
||||
"account_ensure_web_attempt platform=%s env=%s tenant=%s role=%s lease=%s",
|
||||
platform_input,
|
||||
environment,
|
||||
tenant_id,
|
||||
role,
|
||||
do_lease,
|
||||
)
|
||||
|
||||
key = _resolve_or_auto_register(platform_input, platform_meta)
|
||||
if not key:
|
||||
return
|
||||
|
||||
init_db()
|
||||
conn = get_conn()
|
||||
try:
|
||||
seed_platforms(conn)
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
existing_count = count_active_accounts(
|
||||
platform_key=key,
|
||||
environment=environment,
|
||||
tenant_id=tenant_id,
|
||||
role=role,
|
||||
)
|
||||
created = False
|
||||
if existing_count == 0:
|
||||
create_env = (environment or "").strip() or "production"
|
||||
create_role = (role or "").strip() or "default"
|
||||
create_label = (label or "").strip() or None
|
||||
if not create_label:
|
||||
create_label = f"{key} 默认"
|
||||
|
||||
created_payload = create_web_account_record(
|
||||
platform_input,
|
||||
login_id,
|
||||
login_id_type,
|
||||
create_label,
|
||||
tenant_id,
|
||||
create_env,
|
||||
create_role,
|
||||
provider_code,
|
||||
url,
|
||||
extra_json_str,
|
||||
profile_dir_override,
|
||||
auth_strategy=auth_strategy,
|
||||
session_persistent=session_persistent,
|
||||
device_fingerprint=device_fingerprint,
|
||||
platform_meta=platform_meta,
|
||||
platform_key=key,
|
||||
)
|
||||
if not created_payload:
|
||||
return
|
||||
created = True
|
||||
log.info(
|
||||
"account_ensure_web_created id=%s platform=%s profile_dir=%s",
|
||||
created_payload.get("id"),
|
||||
key,
|
||||
created_payload.get("profile_dir"),
|
||||
)
|
||||
else:
|
||||
log.info(
|
||||
"account_ensure_web_reuse platform=%s existing_active=%s",
|
||||
key,
|
||||
existing_count,
|
||||
)
|
||||
|
||||
# Capture pick output so we can annotate / remap lease-busy errors.
|
||||
import io
|
||||
import json
|
||||
import sys
|
||||
|
||||
buf = io.StringIO()
|
||||
old_out = sys.stdout
|
||||
sys.stdout = buf
|
||||
try:
|
||||
cmd_account_pick_web(
|
||||
platform_input,
|
||||
environment=environment,
|
||||
tenant_id=tenant_id,
|
||||
role=role,
|
||||
do_lease=do_lease,
|
||||
ttl_sec=ttl_sec,
|
||||
holder=holder,
|
||||
purpose=purpose,
|
||||
platform_meta=platform_meta,
|
||||
)
|
||||
finally:
|
||||
sys.stdout = old_out
|
||||
|
||||
raw = buf.getvalue().strip()
|
||||
if not raw:
|
||||
_say(_err_json("ERROR:NO_ACCOUNT", "ensure 后未能挑选到账号。"))
|
||||
return
|
||||
|
||||
try:
|
||||
payload = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
_say(raw)
|
||||
return
|
||||
|
||||
if isinstance(payload, dict) and payload.get("success") is False:
|
||||
err = (payload.get("error") or {}) if isinstance(payload.get("error"), dict) else {}
|
||||
code = str(err.get("code") or "")
|
||||
if code == "ERROR:NO_ACCOUNT" and existing_count > 0 and not created:
|
||||
_say(_err_json(
|
||||
"ERROR:LEASE_CONFLICT",
|
||||
"该平台下已有账号,但均被其他任务占用。请稍后重试或释放租约;不会自动新建账号。",
|
||||
))
|
||||
return
|
||||
_say(raw)
|
||||
return
|
||||
|
||||
if isinstance(payload, dict) and created:
|
||||
payload["account_ensured"] = True
|
||||
_say(json.dumps(payload, ensure_ascii=False))
|
||||
return
|
||||
|
||||
_say(raw)
|
||||
Reference in New Issue
Block a user