feat: sync upstream keys and reorder priorities

This commit is contained in:
SmartUp Developer
2026-06-03 17:03:11 +08:00
parent a42bcba483
commit b866b387e0
8 changed files with 415 additions and 57 deletions
+90 -25
View File
@@ -407,17 +407,25 @@ class UpstreamClient:
out["group_name"] = str(out.get("group"))
return out
def _list_new_api_tokens(
self,
search: str = "",
group_id: str | int | None = None,
) -> list[dict[str, Any]]:
if search:
path = "/api/token/search"
params = {"keyword": search, "token": "", "p": 1, "size": 100}
else:
path = "/api/token/"
params = {"p": 1, "size": 100}
@staticmethod
def _extract_new_api_token_items(payload: Any) -> tuple[list[dict[str, Any]], dict[str, Any]]:
nested = _unwrap_data(payload)
meta: dict[str, Any] = {}
items: list[dict[str, Any]] | None = None
if isinstance(nested, list):
items = [i for i in nested if isinstance(i, dict)]
elif isinstance(nested, dict):
meta = nested
for key in ("items", "tokens", "list", "records"):
value = nested.get(key)
if isinstance(value, list):
items = [i for i in value if isinstance(i, dict)]
break
if items is None:
raise UpstreamError("unexpected New-API token list response")
return items, meta
def _request_new_api_token_list(self, path: str, params: dict[str, Any]) -> tuple[list[dict[str, Any]], dict[str, Any]]:
resp = self._client.request(
"GET",
self._url(path),
@@ -429,23 +437,80 @@ class UpstreamClient:
resp.raise_for_status()
data = resp.json()
self._ensure_api_success(data, "list New-API tokens")
nested = _unwrap_data(data)
items: list[dict[str, Any]] | None = None
if isinstance(nested, list):
items = [i for i in nested if isinstance(i, dict)]
elif isinstance(nested, dict):
for key in ("items", "tokens", "list", "records"):
value = nested.get(key)
if isinstance(value, list):
items = [i for i in value if isinstance(i, dict)]
break
if items is None:
raise UpstreamError("unexpected New-API token list response")
normalized = [self._normalize_key_record(i) for i in items]
return self._extract_new_api_token_items(data)
def _list_all_new_api_tokens(self, page_size: int = 100, max_pages: int = 20) -> list[dict[str, Any]]:
all_items: list[dict[str, Any]] = []
for page in range(1, max_pages + 1):
items, meta = self._request_new_api_token_list(
"/api/token/",
{"p": page, "size": page_size},
)
all_items.extend(items)
total = meta.get("total") if isinstance(meta, dict) else None
if isinstance(total, int) and len(all_items) >= total:
break
if len(items) < page_size:
break
return [self._normalize_key_record(i) for i in all_items]
@staticmethod
def _matches_new_api_token_search(record: dict[str, Any], search: str) -> bool:
if not search:
return True
needle = search.strip()
if not needle:
return True
name = str(record.get("name") or record.get("key_name") or "")
key = str(record.get("key") or record.get("api_key") or record.get("apiKey") or record.get("token") or "")
return name.startswith(needle) or name == needle or key == needle
def _hydrate_new_api_token_key(self, record: dict[str, Any]) -> dict[str, Any]:
out = dict(record)
key_value = _extract_key_value(out)
if key_value and "*" not in key_value:
out["key"] = key_value
out["masked_key"] = out.get("masked_key") or mask_secret(key_value)
return out
token_id = out.get("id")
if token_id is None:
return out
try:
plaintext = self._get_new_api_token_key(token_id)
except Exception:
return out
out["key"] = plaintext
out["masked_key"] = mask_secret(plaintext)
return out
def _list_new_api_tokens(
self,
search: str = "",
group_id: str | int | None = None,
) -> list[dict[str, Any]]:
normalized: list[dict[str, Any]] = []
if search:
search_items, _ = self._request_new_api_token_list(
"/api/token/search",
{"keyword": search, "token": "", "p": 1, "size": 100},
)
normalized.extend(self._normalize_key_record(i) for i in search_items)
all_tokens = self._list_all_new_api_tokens()
seen_ids = {str(i.get("id")) for i in normalized if i.get("id") is not None}
for item in all_tokens:
item_id = item.get("id")
if item_id is not None and str(item_id) in seen_ids:
continue
if self._matches_new_api_token_search(item, search):
normalized.append(item)
if item_id is not None:
seen_ids.add(str(item_id))
if group_id is not None:
gid = str(group_id)
normalized = [i for i in normalized if str(i.get("group_id") or i.get("group") or "") == gid]
return normalized
return [self._hydrate_new_api_token_key(i) for i in normalized]
def _get_new_api_token_key(self, token_id: str | int) -> str:
payload = self._request("POST", f"/api/token/{token_id}/key")