49-# --------------------------------------------------------------------------- 50-# OAuth client configuration resolution 51-# --------------------------------------------------------------------------- 52:def resolve_client_config(config=None) -> dict: 53- """Return {client_id, client_secret, redirect_uri} for OAuth flows. 54- 55- Priority: explicit config dict (per-user imported config) > DB row > env file path > error. 56- """ 57- if config and config.client_id: 58- return { 59- "client_id": config.client_id, 60- "client_secret": config.client_secret, # decrypted property 61- "redirect_uri": config.redirect_uri or f"{settings.BASE_URL}/auth/google/callback", 62- } 63- path = settings.GOOGLE_OAUTH_CLIENT_JSON_PATH 64- if path and __import__("os").path.exists(path): 65- with open(path) as f: 66- data = json.load(f) 67- inst = data.get("installed") or data.get("web") 68- if not inst: 69- raise GmailOauthError("Invalid Google OAuth client JSON: no 'installed' or 'web' key") 70- return { 71- "client_id": inst["client_id"], 72- "client_secret": inst["client_secret"], 73- "redirect_uri": f"{settings.BASE_URL}/auth/google/callback", 74- } 75- raise GmailOauthError( 76- "No Google OAuth client configuration available. Import a client_secret.json in " 77- "Gmail Accounts → Import Gmail Configuration, or set GOOGLE_OAUTH_CLIENT_JSON_PATH." -- 259- ) 260- 261- 262:def resolve_client_config_for_account(account) -> dict: 263- """Resolve client config for an account: its imported config row or server default.""" 264- # Called from sync or async context; imports DB lazily. 265- from app.db.session import SyncSession 266- from app.models import OAuthClientConfig 267- if account.oauth_config_id: 268- with SyncSession() as s: 269- cfg = s.get(OAuthClientConfig, account.oauth_config_id) 270- if cfg and cfg.is_active: 271- return {"client_id": cfg.client_id, "client_secret": cfg.client_secret, 272- "redirect_uri": cfg.redirect_uri or f"{settings.BASE_URL}/auth/google/callback"} 273- return resolve_client_config(None) 3 |