diff --git a/SKILL.md b/SKILL.md index 86a3f58..b76f6a7 100644 --- a/SKILL.md +++ b/SKILL.md @@ -1,7 +1,7 @@ --- name: 账号与凭据管理 description: "通用账号 & 凭据 & 登录流程管理器。管理网页/RPA 账号、API Key/Token;支持 9 种登录策略(账密自动、扫码、2FA、SSO 等);提供加密本地存储(Fernet);提供 rpa_helpers 库供业务 skill 同进程调用 ensure_logged_in 完成多平台自动登录。涵盖物流、LLM、内容、开发、API 五类平台。" -version: 2.0.17 +version: 2.0.18 author: 深圳匠厂科技有限公司 metadata: openclaw: diff --git a/scripts/db/display_metadata.py b/scripts/db/display_metadata.py index 657f039..c75ca47 100644 --- a/scripts/db/display_metadata.py +++ b/scripts/db/display_metadata.py @@ -6,6 +6,7 @@ SQLite 无原生表/字段 COMMENT;中文展示名称通过这两张元数据 from __future__ import annotations +import json from typing import Iterable INTERNAL_METADATA_TABLES = frozenset({"_jiangchang_tables", "_jiangchang_columns"}) @@ -20,6 +21,26 @@ ACCOUNT_LEASES_TABLE = "account_leases" DATETIME_UNIX_SECONDS = "datetime_unix_seconds" STANDARD_TIMESTAMP_COLUMNS = frozenset({"created_at", "updated_at"}) +# Data-management lookup: host resolves options_json object into select options. +PLATFORM_KEY_LOOKUP_JSON = json.dumps( + { + "ref_table": "platforms", + "value_column": "platform_key", + "label_column": "display_name", + "filter_column": "enabled", + "filter_value": 1, + }, + ensure_ascii=False, +) +ACCOUNT_ID_LOOKUP_JSON = json.dumps( + { + "ref_table": "accounts", + "value_column": "id", + "label_column": "account_label", + }, + ensure_ascii=False, +) + USER_BUSINESS_TABLES = ( PLATFORMS_TABLE, ACCOUNTS_TABLE, @@ -123,7 +144,13 @@ ACCOUNTS_TABLE_METADATA = { ACCOUNTS_COLUMN_METADATA: tuple[dict[str, object], ...] = ( _col("id", "编号", description="账号唯一编号", editable=0), - _col("platform_key", "平台", description="所属平台键"), + _col( + "platform_key", + "平台", + description="所属平台键(来自平台信息表)", + display_type="lookup", + options_json=PLATFORM_KEY_LOOKUP_JSON, + ), _col("account_label", "账号名称", description="人可读的账号名称"), _col("login_id", "登录账号", description="手机号、邮箱、用户名等登录标识"), _col("login_id_type", "登录标识类型", description="phone / email / username / unknown 等"), @@ -158,8 +185,20 @@ CREDENTIALS_TABLE_METADATA = { CREDENTIALS_COLUMN_METADATA: tuple[dict[str, object], ...] = ( _col("id", "编号", description="凭据唯一编号", editable=0), - _col("account_id", "账号编号", description="关联的 accounts.id,可空"), - _col("platform_key", "平台", description="所属平台键"), + _col( + "account_id", + "账号编号", + description="关联的 accounts.id,可空", + display_type="lookup", + options_json=ACCOUNT_ID_LOOKUP_JSON, + ), + _col( + "platform_key", + "平台", + description="所属平台键(来自平台信息表)", + display_type="lookup", + options_json=PLATFORM_KEY_LOOKUP_JSON, + ), _col("credential_label", "凭据名称", description="人可读的凭据名称"), _col("credential_type", "凭据类型", description="api_key / password / bearer_token 等"), _col("secret_storage", "密钥存储方式", description="none / env / windows_credential / local_encrypted", editable=0), diff --git a/tests/test_display_metadata.py b/tests/test_display_metadata.py index 53f7a14..16af299 100644 --- a/tests/test_display_metadata.py +++ b/tests/test_display_metadata.py @@ -102,6 +102,44 @@ def test_sensitive_credential_fields_not_editable(metadata_db): assert int(searchable) == 0, column_name +def test_account_and_credential_platform_lookups(metadata_db): + import json + + cur = metadata_db.cursor() + for table_name, column_name in ( + (ACCOUNTS_TABLE, "platform_key"), + (CREDENTIALS_TABLE, "platform_key"), + ): + cur.execute( + """ + SELECT display_type, options_json + FROM _jiangchang_columns + WHERE table_name = ? AND column_name = ? + """, + (table_name, column_name), + ) + display_type, options_json = cur.fetchone() + assert display_type == "lookup", table_name + payload = json.loads(options_json) + assert payload["ref_table"] == "platforms" + assert payload["value_column"] == "platform_key" + assert payload["label_column"] == "display_name" + + cur.execute( + """ + SELECT display_type, options_json + FROM _jiangchang_columns + WHERE table_name = ? AND column_name = 'account_id' + """, + (CREDENTIALS_TABLE,), + ) + display_type, options_json = cur.fetchone() + assert display_type == "lookup" + payload = json.loads(options_json) + assert payload["ref_table"] == "accounts" + assert payload["value_column"] == "id" + + def test_lease_token_not_editable(metadata_db): cur = metadata_db.cursor() cur.execute(