Add Google Drive authorization processing and error handling templates

- Implemented `google_drive_callback.html` for processing Google Drive authorization, including UI for success and error states.
- Added JavaScript functionality for exchanging authorization codes, saving settings, and handling folder selection.
- Created `google_drive_callback_error.html` to display error messages during the authorization process.
This commit is contained in:
Christian Krakau-Louis
2025-04-11 00:13:57 +02:00
parent b258dd2f29
commit 4c50c0aae6
26 changed files with 3297 additions and 727 deletions
+74 -40
View File
@@ -5,6 +5,9 @@ from fastapi import APIRouter, Request, HTTPException, status, Form
import logging
import os
import requests
import json
from datetime import datetime, timedelta
from typing import Optional
from app.auth import require_login
from app.config import settings
@@ -157,60 +160,91 @@ async def update_dropbox_settings(
@require_login
async def test_dropbox_token(request: Request):
"""
Test if the configured Dropbox refresh token is valid.
Test if the configured Dropbox token is valid and return expiration information.
"""
try:
from app.tasks.upload_to_dropbox import get_dropbox_client
logger.info("Testing Dropbox token validity")
if not settings.dropbox_refresh_token:
logger.warning("No Dropbox refresh token configured")
if not settings.dropbox_refresh_token or not settings.dropbox_app_key or not settings.dropbox_app_secret:
logger.warning("Dropbox credentials not fully configured")
return {
"status": "error",
"message": "No Dropbox refresh token is configured"
"message": "Dropbox credentials are not fully configured"
}
# Check if app key and app secret are configured
if not settings.dropbox_app_key or not settings.dropbox_app_secret:
logger.warning("Dropbox app key or app secret is missing")
# Check token validity by getting current account info
headers = {"Authorization": f"Bearer {settings.dropbox_refresh_token}"}
response = requests.post(
"https://api.dropboxapi.com/2/users/get_current_account",
headers=headers
)
# 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)
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",
headers=headers
)
if response.status_code != 200:
logger.error(f"Dropbox token test failed: {response.status_code} {response.text}")
return {
"status": "error",
"message": "Dropbox app key or app secret is missing",
"missing_config": True
"message": f"Token validation failed with status {response.status_code}: {response.text}"
}
# Try to get a client using the configured refresh token
try:
dbx = get_dropbox_client()
# Test connection by getting account info
account = dbx.users_get_current_account()
logger.info(f"Successfully connected to Dropbox as {account.name.display_name}")
return {
"status": "success",
"message": f"Token is valid! Connected as {account.name.display_name}",
"account": account.name.display_name,
"email": account.email
}
except Exception as e:
error_msg = str(e)
logger.error(f"Dropbox token test failed: {error_msg}")
# Determine if this is an authentication error
is_auth_error = "auth" in error_msg.lower() or "invalid" in error_msg.lower()
return {
"status": "error",
"message": f"Token validation failed: {error_msg}",
"is_auth_error": is_auth_error,
"needs_reauth": is_auth_error
}
# Get account info
account_info = response.json()
account_email = account_info.get("email", "Unknown account")
account_name = account_info.get("name", {}).get("display_name", "Unknown user")
# Dropbox refresh tokens don't expire, but we should note that in our response
token_info = {
"expires_in_human": "Never expires (perpetual token)",
"is_perpetual": True
}
logger.info(f"Successfully connected to Dropbox as {account_email}")
return {
"status": "success",
"message": f"Dropbox connection successful",
"account": account_email,
"account_name": account_name,
"token_info": token_info
}
except Exception as e:
logger.exception("Unexpected error testing Dropbox token")
logger.exception(f"Unexpected error testing Dropbox token: {str(e)}")
return {
"status": "error",
"message": f"Unexpected error: {str(e)}"
"message": f"Connection error: {str(e)}"
}
@router.post("/dropbox/save-settings")