146 lines
5.2 KiB
Python
146 lines
5.2 KiB
Python
import os
|
|
import sys
|
|
import requests
|
|
from dotenv import load_dotenv, set_key
|
|
|
|
load_dotenv()
|
|
|
|
sys.path.insert(0, os.path.dirname(__file__))
|
|
from utils.retry import RetryableHTTPError, raise_for_retryable_status, retry_with_backoff
|
|
|
|
_RETRY = dict(max_retries=3, base_delay=1.0, max_delay=16.0, retryable_exceptions=(RetryableHTTPError,))
|
|
|
|
SHARD = "eu2"
|
|
TOKEN_URL = f"https://api.{SHARD}.adobesign.com/oauth/v2/token" # initial auth code exchange
|
|
REFRESH_URL = f"https://api.{SHARD}.adobesign.com/oauth/v2/refresh" # token refresh (non-standard separate endpoint)
|
|
ENV_FILE = os.path.join(os.path.dirname(__file__), "..", ".env")
|
|
|
|
|
|
def _refresh_access_token():
|
|
client_id = os.getenv("ADOBE_CLIENT_ID")
|
|
client_secret = os.getenv("ADOBE_CLIENT_SECRET")
|
|
refresh_token = os.getenv("ADOBE_REFRESH_TOKEN")
|
|
|
|
if not all([client_id, client_secret, refresh_token]):
|
|
raise RuntimeError("Missing credentials for token refresh. Run src/adobe_auth.py first.")
|
|
|
|
data = {
|
|
"grant_type": "refresh_token",
|
|
"refresh_token": refresh_token,
|
|
"client_id": client_id,
|
|
"client_secret": client_secret,
|
|
}
|
|
resp = requests.post(REFRESH_URL, data=data)
|
|
if not resp.ok:
|
|
raise RuntimeError(
|
|
f"Adobe Sign refresh token is invalid or expired ({resp.status_code}: {resp.text}). "
|
|
"Run `python3 src/adobe_auth.py` to re-authenticate."
|
|
)
|
|
new_token = resp.json()["access_token"]
|
|
set_key(os.path.abspath(ENV_FILE), "ADOBE_ACCESS_TOKEN", new_token)
|
|
os.environ["ADOBE_ACCESS_TOKEN"] = new_token
|
|
return new_token
|
|
|
|
|
|
@retry_with_backoff(**_RETRY)
|
|
def adobe_api_post_multipart(endpoint, files, data=None):
|
|
"""Upload a file via multipart/form-data (e.g. transient documents)."""
|
|
token = os.getenv("ADOBE_ACCESS_TOKEN")
|
|
base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6")
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
url = f"{base_url}/{endpoint}"
|
|
resp = requests.post(url, headers=headers, files=files, data=data or {})
|
|
if resp.status_code == 401:
|
|
token = _refresh_access_token()
|
|
headers["Authorization"] = f"Bearer {token}"
|
|
resp = requests.post(url, headers=headers, files=files, data=data or {})
|
|
raise_for_retryable_status(resp)
|
|
return resp.json()
|
|
|
|
|
|
@retry_with_backoff(**_RETRY)
|
|
def adobe_api_post_json(endpoint, body):
|
|
"""POST JSON body to an Adobe Sign endpoint."""
|
|
token = os.getenv("ADOBE_ACCESS_TOKEN")
|
|
base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6")
|
|
headers = {
|
|
"Authorization": f"Bearer {token}",
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json",
|
|
}
|
|
url = f"{base_url}/{endpoint}"
|
|
resp = requests.post(url, headers=headers, json=body)
|
|
if resp.status_code == 401:
|
|
token = _refresh_access_token()
|
|
headers["Authorization"] = f"Bearer {token}"
|
|
resp = requests.post(url, headers=headers, json=body)
|
|
raise_for_retryable_status(resp)
|
|
return resp.json()
|
|
|
|
|
|
@retry_with_backoff(**_RETRY)
|
|
def adobe_api_put_json(endpoint, body):
|
|
"""PUT JSON body to an Adobe Sign endpoint."""
|
|
token = os.getenv("ADOBE_ACCESS_TOKEN")
|
|
base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6")
|
|
headers = {
|
|
"Authorization": f"Bearer {token}",
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json",
|
|
}
|
|
url = f"{base_url}/{endpoint}"
|
|
resp = requests.put(url, headers=headers, json=body)
|
|
if resp.status_code == 401:
|
|
token = _refresh_access_token()
|
|
headers["Authorization"] = f"Bearer {token}"
|
|
resp = requests.put(url, headers=headers, json=body)
|
|
raise_for_retryable_status(resp)
|
|
return resp.json()
|
|
|
|
|
|
@retry_with_backoff(**_RETRY)
|
|
def adobe_api_get_bytes(endpoint):
|
|
"""Download binary content (e.g. PDF files) from the Adobe Sign API."""
|
|
token = os.getenv("ADOBE_ACCESS_TOKEN")
|
|
base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6")
|
|
|
|
headers = {"Authorization": f"Bearer {token}"}
|
|
url = f"{base_url}/{endpoint}"
|
|
resp = requests.get(url, headers=headers)
|
|
|
|
if resp.status_code == 401:
|
|
token = _refresh_access_token()
|
|
headers["Authorization"] = f"Bearer {token}"
|
|
resp = requests.get(url, headers=headers)
|
|
|
|
raise_for_retryable_status(resp)
|
|
return resp.content
|
|
|
|
|
|
@retry_with_backoff(**_RETRY)
|
|
def adobe_api_get(endpoint, params=None):
|
|
token = os.getenv("ADOBE_ACCESS_TOKEN")
|
|
base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6")
|
|
|
|
headers = {
|
|
"Authorization": f"Bearer {token}",
|
|
"Accept": "application/json",
|
|
}
|
|
|
|
url = f"{base_url}/{endpoint}"
|
|
resp = requests.get(url, headers=headers, params=params)
|
|
|
|
if resp.status_code == 401:
|
|
# Token expired — refresh and retry once
|
|
token = _refresh_access_token()
|
|
headers["Authorization"] = f"Bearer {token}"
|
|
resp = requests.get(url, headers=headers, params=params)
|
|
|
|
raise_for_retryable_status(resp)
|
|
return resp.json()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
library_docs = adobe_api_get("libraryDocuments")
|
|
print("Library Documents:", library_docs)
|