107 lines
4.9 KiB
Python
107 lines
4.9 KiB
Python
"""Runtime configuration read from environment variables.
|
|
|
|
AppFactory injects variables/secrets as environment variables (see AGENTS.md).
|
|
This module holds only NON-secret infrastructure configuration. Per-request
|
|
credentials are never stored here - they arrive in X- headers (see
|
|
``app.credentials``).
|
|
"""
|
|
import os
|
|
|
|
# Public app metadata
|
|
APP_NAME = os.getenv("APP_NAME", "analytics")
|
|
APP_VERSION = os.getenv("APP_VERSION", "1.0.0")
|
|
|
|
# Reverse-proxy prefix injected by AppFactory (e.g. "/apps/analytics").
|
|
# Empty when running locally at the domain root.
|
|
ROOT_PATH = os.getenv("ROOT_PATH", "")
|
|
|
|
# --- Google Analytics ---------------------------------------------------------
|
|
# Base URLs are configurable so we can point at a staging/mock endpoint, but
|
|
# default to the production Google endpoints.
|
|
GA_DATA_BASE_URL = os.getenv(
|
|
"GA_DATA_BASE_URL", "https://analyticsdata.googleapis.com/v1beta"
|
|
)
|
|
GA_ADMIN_BASE_URL = os.getenv(
|
|
"GA_ADMIN_BASE_URL", "https://analyticsadmin.googleapis.com/v1beta"
|
|
)
|
|
# OAuth scope requested when minting an access token from a service account.
|
|
# analytics.readonly is sufficient for reporting (Data API) and for listing
|
|
# accounts/properties/data streams (Admin API read operations).
|
|
GA_SCOPE = os.getenv(
|
|
"GA_SCOPE", "https://www.googleapis.com/auth/analytics.readonly"
|
|
)
|
|
|
|
# --- Google Search Console ----------------------------------------------------
|
|
# Search Analytics, Sites and Sitemaps live under the Webmasters v3 API; the
|
|
# newer URL Inspection lives under searchconsole.googleapis.com/v1.
|
|
GSC_DATA_BASE_URL = os.getenv(
|
|
"GSC_DATA_BASE_URL", "https://www.googleapis.com/webmasters/v3"
|
|
)
|
|
GSC_INSPECT_BASE_URL = os.getenv(
|
|
"GSC_INSPECT_BASE_URL", "https://searchconsole.googleapis.com/v1"
|
|
)
|
|
GSC_SCOPE = os.getenv(
|
|
"GSC_SCOPE", "https://www.googleapis.com/auth/webmasters.readonly"
|
|
)
|
|
|
|
# --- Google Ads ---------------------------------------------------------------
|
|
# Google Ads API versions are deprecated roughly yearly - keep the version in an
|
|
# env var so it can be bumped without a code change.
|
|
GOOGLE_ADS_BASE_URL = os.getenv(
|
|
"GOOGLE_ADS_BASE_URL", "https://googleads.googleapis.com"
|
|
)
|
|
GOOGLE_ADS_API_VERSION = os.getenv("GOOGLE_ADS_API_VERSION", "v19")
|
|
GOOGLE_ADS_SCOPE = os.getenv(
|
|
"GOOGLE_ADS_SCOPE", "https://www.googleapis.com/auth/adwords"
|
|
)
|
|
|
|
# --- Sklik (Seznam) -----------------------------------------------------------
|
|
# Sklik "Drak" JSON API. The method name is appended to this base URL and the
|
|
# HTTP body is a JSON array of positional arguments.
|
|
SKLIK_BASE_URL = os.getenv("SKLIK_BASE_URL", "https://api.sklik.cz/drak/json/v5")
|
|
|
|
# Page size / safety cap for the typed list endpoints (campaigns, groups, ads).
|
|
SKLIK_LIST_PAGE_LIMIT = int(os.getenv("SKLIK_LIST_PAGE_LIMIT", "100"))
|
|
SKLIK_LIST_MAX_PAGES = int(os.getenv("SKLIK_LIST_MAX_PAGES", "200"))
|
|
|
|
# --- Sklik write guard rails --------------------------------------------------
|
|
# Optional backstops for the write endpoints. All amounts are in HALERS
|
|
# (100 = 1 Kc), the unit the Sklik API itself uses.
|
|
#
|
|
# All THREE ceilings default to 0 = DISABLED, i.e. the proxy does not second-
|
|
# guess the caller's budgets out of the box. Set a non-zero value to have the
|
|
# proxy reject anything above it - useful as a safety net against a misplaced
|
|
# decimal point (Sklik works in halers, so "50000" meant as korunas is 500 Kc).
|
|
# Enforcement is opt-in on purpose: the approval flow lives on the caller's side.
|
|
SKLIK_MAX_DAY_BUDGET_HALERS = int(os.getenv("SKLIK_MAX_DAY_BUDGET_HALERS", "0"))
|
|
SKLIK_MAX_TOTAL_BUDGET_HALERS = int(os.getenv("SKLIK_MAX_TOTAL_BUDGET_HALERS", "0"))
|
|
# Ceiling for a group's default max CPC / CPT.
|
|
SKLIK_MAX_CPC_HALERS = int(os.getenv("SKLIK_MAX_CPC_HALERS", "0"))
|
|
|
|
# How long a completed write is remembered for idempotent replay (seconds).
|
|
# Idempotency itself is opt-in per request via the X-Idempotency-Key header.
|
|
SKLIK_IDEMPOTENCY_TTL_SECONDS = float(
|
|
os.getenv("SKLIK_IDEMPOTENCY_TTL_SECONDS", "86400")
|
|
)
|
|
|
|
# Creation always forces status=suspend (see app.sklik_guards). UPDATE, however,
|
|
# is full CRUD and can set status=active by default - that is how you resume a
|
|
# paused campaign. Set this to "true" to refuse activation through the API as
|
|
# well, so starting a campaign stays a manual action in the Sklik UI.
|
|
SKLIK_BLOCK_ACTIVATION = os.getenv(
|
|
"SKLIK_BLOCK_ACTIVATION", "false"
|
|
).strip().lower() in ("1", "true", "yes")
|
|
|
|
# The generic /sklik/rpc passthrough reaches any method, including mutating ones
|
|
# (campaigns.create etc.), which bypass the typed endpoints' guard rails. That
|
|
# is the long-standing behaviour and stays ALLOWED by default. Set this to
|
|
# "false" to restrict the passthrough to read methods and funnel every write
|
|
# through the typed endpoints.
|
|
SKLIK_RPC_ALLOW_MUTATIONS = os.getenv(
|
|
"SKLIK_RPC_ALLOW_MUTATIONS", "true"
|
|
).strip().lower() in ("1", "true", "yes")
|
|
|
|
# --- HTTP ---------------------------------------------------------------------
|
|
# Upstream request timeout in seconds.
|
|
HTTP_TIMEOUT_SECONDS = float(os.getenv("HTTP_TIMEOUT_SECONDS", "60"))
|