Merge pull request #711 from christianlouis/performance-optimize-dropbox-token-2748375428782384195

 Optimize Dropbox token check by using async httpx
This commit is contained in:
Christian Krakau-Louis
2026-03-16 10:49:34 +01:00
committed by GitHub
2 changed files with 60 additions and 53 deletions
+49 -46
View File
@@ -6,7 +6,7 @@ import logging
import os import os
from typing import Annotated, Optional from typing import Annotated, Optional
import requests import httpx
from fastapi import APIRouter, Depends, Form, HTTPException, Request, status from fastapi import APIRouter, Depends, Form, HTTPException, Request, status
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -132,57 +132,60 @@ async def test_dropbox_token(request: Request):
"message": "Dropbox credentials are not fully configured", "message": "Dropbox credentials are not fully configured",
} }
# Check token validity by getting current account info async with httpx.AsyncClient() as client:
headers = {"Authorization": f"Bearer {settings.dropbox_refresh_token}"} # Check token validity by getting current account info
response = requests.post( headers = {"Authorization": f"Bearer {settings.dropbox_refresh_token}"}
"https://api.dropboxapi.com/2/users/get_current_account", response = await client.post(
headers=headers,
timeout=settings.http_request_timeout,
)
# If token is invalid, try refreshing it
if response.status_code == 401:
logger.info("Dropbox access token invalid or expired, trying to refresh")
# Get a new access token using the refresh token
refresh_url = "https://api.dropbox.com/oauth2/token"
refresh_data = {
"grant_type": "refresh_token",
"refresh_token": settings.dropbox_refresh_token,
"client_id": settings.dropbox_app_key,
"client_secret": settings.dropbox_app_secret,
}
refresh_response = requests.post(refresh_url, data=refresh_data, timeout=settings.http_request_timeout)
if refresh_response.status_code != 200:
logger.error(f"Failed to refresh Dropbox token: {refresh_response.text}")
return {
"status": "error",
"message": "Refresh token has expired or is invalid",
"needs_reauth": True,
}
token_info = refresh_response.json()
access_token = token_info.get("access_token")
# Try again with the new access token
headers = {"Authorization": f"Bearer {access_token}"}
response = requests.post(
"https://api.dropboxapi.com/2/users/get_current_account", "https://api.dropboxapi.com/2/users/get_current_account",
headers=headers, headers=headers,
timeout=settings.http_request_timeout, timeout=settings.http_request_timeout,
) )
if response.status_code != 200: # If token is invalid, try refreshing it
logger.error(f"Dropbox token test failed: {response.status_code} {response.text}") if response.status_code == 401:
return { logger.info("Dropbox access token invalid or expired, trying to refresh")
"status": "error",
"message": f"Token validation failed with status {response.status_code}: {response.text}",
}
# Get account info # Get a new access token using the refresh token
account_info = response.json() refresh_url = "https://api.dropbox.com/oauth2/token"
refresh_data = {
"grant_type": "refresh_token",
"refresh_token": settings.dropbox_refresh_token,
"client_id": settings.dropbox_app_key,
"client_secret": settings.dropbox_app_secret,
}
refresh_response = await client.post(
refresh_url, data=refresh_data, timeout=settings.http_request_timeout
)
if refresh_response.status_code != 200:
logger.error(f"Failed to refresh Dropbox token: {refresh_response.text}")
return {
"status": "error",
"message": "Refresh token has expired or is invalid",
"needs_reauth": True,
}
token_info = refresh_response.json()
access_token = token_info.get("access_token")
# Try again with the new access token
headers = {"Authorization": f"Bearer {access_token}"}
response = await client.post(
"https://api.dropboxapi.com/2/users/get_current_account",
headers=headers,
timeout=settings.http_request_timeout,
)
if response.status_code != 200:
logger.error(f"Dropbox token test failed: {response.status_code} {response.text}")
return {
"status": "error",
"message": f"Token validation failed with status {response.status_code}: {response.text}",
}
# Get account info
account_info = response.json()
account_email = account_info.get("email", "Unknown account") account_email = account_info.get("email", "Unknown account")
account_name = account_info.get("name", {}).get("display_name", "Unknown user") account_name = account_info.get("name", {}).get("display_name", "Unknown user")
+11 -7
View File
@@ -7,7 +7,6 @@ Covers Dropbox OAuth endpoints, settings management, and token testing.
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
import pytest import pytest
import requests
@pytest.mark.unit @pytest.mark.unit
@@ -137,7 +136,7 @@ class TestTestDropboxToken:
assert data["status"] == "error" assert data["status"] == "error"
assert "not fully configured" in data["message"] assert "not fully configured" in data["message"]
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_valid_token(self, mock_settings, mock_post, client): def test_valid_token(self, mock_settings, mock_post, client):
"""Test successful token validation.""" """Test successful token validation."""
@@ -162,7 +161,7 @@ class TestTestDropboxToken:
assert data["account"] == "user@example.com" assert data["account"] == "user@example.com"
assert data["account_name"] == "Test User" assert data["account_name"] == "Test User"
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_expired_token_refreshed(self, mock_settings, mock_post, client): def test_expired_token_refreshed(self, mock_settings, mock_post, client):
"""Test that expired token triggers refresh and retry.""" """Test that expired token triggers refresh and retry."""
@@ -194,7 +193,7 @@ class TestTestDropboxToken:
data = response.json() data = response.json()
assert data["status"] == "success" assert data["status"] == "success"
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_refresh_token_expired(self, mock_settings, mock_post, client): def test_refresh_token_expired(self, mock_settings, mock_post, client):
"""Test handling when refresh token itself is expired.""" """Test handling when refresh token itself is expired."""
@@ -220,7 +219,7 @@ class TestTestDropboxToken:
assert data["status"] == "error" assert data["status"] == "error"
assert data["needs_reauth"] is True assert data["needs_reauth"] is True
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_token_validation_failure(self, mock_settings, mock_post, client): def test_token_validation_failure(self, mock_settings, mock_post, client):
"""Test handling non-401, non-200 response.""" """Test handling non-401, non-200 response."""
@@ -240,16 +239,21 @@ class TestTestDropboxToken:
data = response.json() data = response.json()
assert data["status"] == "error" assert data["status"] == "error"
@patch("app.api.dropbox.requests.post") @patch("app.api.dropbox.httpx.AsyncClient.post")
@patch("app.api.dropbox.settings") @patch("app.api.dropbox.settings")
def test_connection_error(self, mock_settings, mock_post, client): def test_connection_error(self, mock_settings, mock_post, client):
"""Test handling of connection exceptions.""" """Test handling of connection exceptions."""
import httpx
mock_settings.dropbox_refresh_token = "token" mock_settings.dropbox_refresh_token = "token"
mock_settings.dropbox_app_key = "app-key" mock_settings.dropbox_app_key = "app-key"
mock_settings.dropbox_app_secret = "app-secret" mock_settings.dropbox_app_secret = "app-secret"
mock_settings.http_request_timeout = 30 mock_settings.http_request_timeout = 30
mock_post.side_effect = requests.exceptions.ConnectionError("Connection refused") mock_post.side_effect = httpx.RequestError(
"Connection refused",
request=httpx.Request("POST", "https://api.dropboxapi.com/2/users/get_current_account"),
)
response = client.get("/api/dropbox/test-token") response = client.get("/api/dropbox/test-token")