Рефакторинг API-слоя, операций и БД

This commit is contained in:
2026-07-31 17:13:54 +04:00
parent 82a3be2067
commit 0783319fd1
15 changed files with 986 additions and 257 deletions
+45 -17
View File
@@ -3,15 +3,15 @@
Раньше _client(), _client_id(), _stand(), _token_info() были продублированы
в main.py и api_test.py с идентичным или почти идентичным кодом.
Теперь всё здесь — один источник правды.
Теперь всё здесь — один источник правды для всех роутов.
Функции:
get_token() — токен из cookie или env
Функции (все без аргументов — берут данные из Flask request/current_app):
get_token() — токен: cookie env-переменная
get_client() — HttpClient с автоопределением стенда
get_client_id() — ClientID из JWT (base64, без проверки подписи)
get_stand() — "dev"/"test" по токену
get_token_info() — {email, company, client_id} из JWT
get_token_masked() — маскированный токен (abc...xyz)
get_client_id() — ClientID из JWT (base64url, без проверки подписи)
get_stand() — "dev" / "test" по токену
get_token_info() — {email, company, client_id} из JWT для UI
get_token_masked() — маскированный токен (abc...xyz) для placeholder
"""
import base64
@@ -22,13 +22,19 @@ from api.http_client import HttpClient, detect_endpoint, stand_name
def get_token():
"""Токен: сначала из cookie, потом из env-переменной."""
"""Получить активный токен: сначала из cookie пользователя, потом из env.
Приоритет:
1. cookie "token" — пользователь ввёл свой токен в форме
2. NUBES_API_TOKEN из env — сервисный токен (для автоматических тестов)
Пользовательский токен приоритетнее — он переопределяет сервисный."""
return request.cookies.get("token") or current_app.config["NUBES_API_TOKEN"]
def get_client():
"""HttpClient с автоопределением стенда по токену.
"""HttpClient с автоопределением стенда по активному токену.
Использует detect_endpoint() — пробует dev→test стенды.
Если автоопределение не сработало — fallback на NUBES_API_ENDPOINT из конфига."""
token = get_token()
@@ -37,27 +43,45 @@ def get_client():
def get_client_id():
"""Извлечение ClientID из payload JWT-токена (base64url, без проверки подписи)."""
"""Извлечь ClientID из payload JWT-токена (base64url, без проверки подписи).
JWT состоит из трёх частей: header.payload.signature, разделённых точкой.
Нам нужен ТОЛЬКО payload — он в base64url (не base64!).
ClientID используется для:
- Изоляции данных в БД (runs.client_id)
- Изоляции трекера инстансов (/tmp/instances-{clientId}-{stand}.json)
- Отображения в UI
Безопасность: мы НЕ проверяем подпись — это не нужно.
Токен уже проверен Nubes API (detect_endpoint делает реальный запрос)."""
token = get_token()
try:
parts = token.split(".") # header.payload.signature
parts = token.split(".") # [header, payload, signature]
if len(parts) >= 2:
payload = base64.urlsafe_b64decode(parts[1] + "==") # padding
# base64url → добавляем padding ("==") на случай если длина не кратна 4
payload = base64.urlsafe_b64decode(parts[1] + "==")
return json.loads(payload).get("ClientID", "")
except Exception:
pass
pass # битый токен — не критично, вернём пустую строку
return ""
def get_stand():
"""dev/test — по токену (detect_endpoint → stand_name)."""
"""Определить стенд (dev/test) по активному токену.
detect_endpoint → stand_name. Если автоопределение не сработало —
fallback на NUBES_API_ENDPOINT из конфига."""
token = get_token()
endpoint = detect_endpoint(token) or current_app.config["NUBES_API_ENDPOINT"]
return stand_name(endpoint)
def get_token_info():
"""{email, company, client_id} из JWT — для отображения в топбаре UI."""
"""Извлечь {email, company, client_id} из JWT — для отображения в топбаре UI.
Возвращает dict с ключами: email, company, client_id.
Если JWT невалиден — возвращает пустой {}."""
token = get_token()
try:
parts = token.split(".")
@@ -75,8 +99,12 @@ def get_token_info():
def get_token_masked():
"""Маскированный токен для placeholder: abc...xyz."""
"""Маскированный env-токен для placeholder в форме: abc...xyz.
Используется ТОЛЬКО env-токен (не пользовательский!).
Если токен короче 8 символов — возвращает пустую строку."""
token = current_app.config["NUBES_API_TOKEN"]
if not token or len(token) < 8:
return ""
# Первые 4 символа + звёздочки + последние 4 символа
return token[:4] + "*" * (len(token) - 8) + token[-4:]