70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
from __future__ import annotations
|
||
|
||
import json
|
||
import os
|
||
import urllib.error
|
||
import urllib.request
|
||
from typing import Any, Optional
|
||
|
||
from worklib.auth_as_employer import get_access_token
|
||
|
||
|
||
DEFAULT_COMPANY_ID = "65437401ae3af6f8ffcdbaf8"
|
||
DEFAULT_GRAPHQL_URL = "https://admin.dev.dipal.ru/graphql"
|
||
|
||
|
||
def build_headers(access_token: str, *, company_id: str = DEFAULT_COMPANY_ID) -> dict[str, str]:
|
||
return {
|
||
"Authorization": f"Bearer {access_token}",
|
||
"x-company-id": company_id,
|
||
}
|
||
|
||
|
||
def execute_graphql(
|
||
*,
|
||
query: str,
|
||
variables: Optional[dict[str, Any]] = None,
|
||
graphql_url: Optional[str] = None,
|
||
company_id: str = DEFAULT_COMPANY_ID,
|
||
access_token: Optional[str] = None,
|
||
timeout_s: int = 30,
|
||
) -> dict[str, Any]:
|
||
graphql_url = graphql_url or os.getenv("GRAPHQL_URL") or DEFAULT_GRAPHQL_URL
|
||
if not graphql_url:
|
||
raise ValueError("Не задан GRAPHQL_URL (передайте graphql_url или установите env GRAPHQL_URL)")
|
||
|
||
token = access_token or get_access_token()
|
||
headers = build_headers(token, company_id=company_id)
|
||
|
||
payload: dict[str, Any] = {"query": query}
|
||
if variables is not None:
|
||
payload["variables"] = variables
|
||
|
||
req = urllib.request.Request(
|
||
graphql_url,
|
||
data=json.dumps(payload).encode("utf-8"),
|
||
headers={"content-type": "application/json", **headers},
|
||
method="POST",
|
||
)
|
||
try:
|
||
with urllib.request.urlopen(req, timeout=timeout_s) as resp:
|
||
raw = resp.read().decode("utf-8")
|
||
except urllib.error.HTTPError as e:
|
||
body = e.read().decode("utf-8", errors="replace")
|
||
raise RuntimeError(f"GraphQL HTTP {e.code}: {body}") from e
|
||
|
||
data = json.loads(raw) if raw else {}
|
||
if isinstance(data, dict) and data.get("errors"):
|
||
errors = data["errors"]
|
||
# На стенде часть операций возвращает Forbidden как GraphQL error (не HTTP 403).
|
||
if isinstance(errors, list) and any(getattr(err, "get", lambda *_: None)("status") == 403 for err in errors):
|
||
raise PermissionError(
|
||
"Forbidden (403) для GraphQL операции. "
|
||
"Проверьте креды/права. Можно задать env: AUTH_USERNAME/AUTH_PASSWORD/AUTH_GRANT_TYPE."
|
||
)
|
||
raise RuntimeError(f"GraphQL errors: {errors}")
|
||
if not isinstance(data, dict):
|
||
raise RuntimeError(f"GraphQL response is not an object: {data!r}")
|
||
return data
|
||
|