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