chat/utils/clients/accounts_client.py
2026-07-28 13:17:01 +03:30

101 lines
3.1 KiB
Python

import time
import requests
from django.conf import settings
from django.core.cache import cache
from utils.clients.gooyal_accounts_client import AuthenticatedClient
from utils.clients.gooyal_accounts_client.models import PublicUser
from utils.clients.gooyal_accounts_client.api.users import users_api_users_retrieve
ACCESS_TOKEN_CACHE_KEY = "chat_account_access_token"
USER_PUBLIC_INFO_CACHE_KEY = "chat_account_public_info_{uuid}"
USER_PUBLIC_INFO_CACHE_TIMEOUT_SECONDS = 300
def login_as_client_credentials() -> dict:
"""
Client-credentials OAuth2 grant against the gooyal accounts service,
reusing a cached access token until it's within 5s of expiry.
"""
cached = cache.get(ACCESS_TOKEN_CACHE_KEY)
if cached:
return cached
data = {
"grant_type": "client_credentials",
"scope": settings.OAUTH2_PROVIDER_SCOPES,
}
auth = (settings.OAUTH2_PROVIDER_CLIENT_ID, settings.OAUTH2_PROVIDER_CLIENT_SECRET)
response = requests.post(
f"{settings.OAUTH2_PROVIDER_BASE_PUBLIC_URL}/token/", data=data, auth=auth
)
response.raise_for_status()
auth_data = response.json()
if "access_token" in auth_data:
auth_data["created_at"] = time.time()
cache.set(
ACCESS_TOKEN_CACHE_KEY, auth_data, timeout=auth_data.get("expires_in", 300) - 5
)
return auth_data
def get_client() -> AuthenticatedClient:
access_token = login_as_client_credentials()["access_token"]
return AuthenticatedClient(
base_url=settings.ACCOUNTS_BASE_PUBLIC_URL, token=access_token
)
def get_user_public_info(uuid) -> PublicUser | None:
"""Fetch a single user's public profile (name, avatar) — not cached."""
client = get_client()
return users_api_users_retrieve.sync(uuid=uuid, client=client)
def get_users_public_info_bulk(uuids: list) -> dict[str, dict]:
"""
Fetch public profiles (name, avatar) for multiple users in one call.
Checks the cache per UUID first; only uncached UUIDs hit the network.
Returns {str(uuid): profile_dict} for every user found.
"""
if not uuids:
return {}
result = {}
uncached = []
for uid in uuids:
cache_key = USER_PUBLIC_INFO_CACHE_KEY.format(uuid=uid)
cached = cache.get(cache_key)
if cached is not None:
result[str(uid)] = cached
else:
uncached.append(uid)
if not uncached:
return result
try:
client = get_client()
uuid_in = ",".join(str(u) for u in uncached)
response = client.get_httpx_client().request(
method="get",
url=f"/users/api/users/?uuid__in={uuid_in}",
)
if response.status_code == 200:
for profile in response.json().get("results", []):
uid_str = profile.get("uuid")
if uid_str:
cache_key = USER_PUBLIC_INFO_CACHE_KEY.format(uuid=uid_str)
cache.set(
cache_key, profile, timeout=USER_PUBLIC_INFO_CACHE_TIMEOUT_SECONDS
)
result[uid_str] = profile
except Exception:
pass
return result