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