Save local changes (GSC/Bing integrations) before merging PR #354

This commit is contained in:
ajaysi
2026-02-13 13:11:27 +05:30
parent 43e66835ac
commit 08a1f4a1d8
144 changed files with 8310 additions and 2748 deletions

View File

@@ -43,6 +43,12 @@ async def get_gsc_auth_url(user: dict = Depends(get_current_user)):
logger.info(f"OAuth URL: {auth_url[:100]}...")
return {"auth_url": auth_url}
except FileNotFoundError as e:
logger.error(f"GSC credentials not found: {e}")
raise HTTPException(
status_code=503,
detail="Google Search Console integration is not configured. Please add gsc_credentials.json to the backend directory or set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables."
)
except Exception as e:
logger.error(f"Error generating GSC OAuth URL: {e}")
logger.error(f"Error details: {str(e)}")
@@ -73,34 +79,29 @@ async def handle_gsc_callback(
from services.platform_insights_monitoring_service import create_platform_insights_task
# Get user_id from state (stored during OAuth flow)
# Note: handle_oauth_callback already deleted state, so we need to get user_id from recent credentials
db = SessionLocal()
try:
# Get user_id from most recent GSC credentials (since state was deleted)
import sqlite3
with sqlite3.connect(gsc_service.db_path) as conn:
cursor = conn.cursor()
cursor.execute('SELECT user_id FROM gsc_credentials ORDER BY updated_at DESC LIMIT 1')
result = cursor.fetchone()
if result:
user_id = result[0]
# Don't fetch site_url here - it requires API calls
# The executor will fetch it when the task runs (weekly)
# Create insights task without site_url to avoid API calls
task_result = create_platform_insights_task(
user_id=user_id,
platform='gsc',
site_url=None, # Will be fetched by executor when task runs
db=db
)
if task_result.get('success'):
logger.info(f"Created GSC insights task for user {user_id}")
else:
logger.warning(f"Failed to create GSC insights task: {task_result.get('error')}")
finally:
db.close()
# Format is "user_id:random_string"
user_id = state.split(':')[0] if ':' in state else None
if user_id:
db = SessionLocal()
try:
# Create insights task without site_url to avoid API calls
# The executor will fetch it when the task runs (weekly)
task_result = create_platform_insights_task(
user_id=user_id,
platform='gsc',
site_url=None, # Will be fetched by executor when task runs
db=db
)
if task_result.get('success'):
logger.info(f"Created GSC insights task for user {user_id}")
else:
logger.warning(f"Failed to create GSC insights task: {task_result.get('error')}")
finally:
db.close()
else:
logger.warning(f"Could not extract user_id from state: {state}")
except Exception as e:
# Non-critical: log but don't fail OAuth callback
logger.warning(f"Failed to create GSC insights task after OAuth: {e}", exc_info=True)

View File

@@ -3,8 +3,8 @@ WordPress OAuth2 Routes
Handles WordPress.com OAuth2 authentication flow.
"""
from fastapi import APIRouter, Depends, HTTPException, status, Query
from fastapi.responses import RedirectResponse, HTMLResponse
from fastapi import APIRouter, Depends, HTTPException, status, Query, Request
from fastapi.responses import RedirectResponse, HTMLResponse, JSONResponse
from typing import Dict, Any, Optional
from pydantic import BaseModel
from loguru import logger
@@ -61,14 +61,23 @@ async def get_wordpress_auth_url(
@router.get("/callback")
async def handle_wordpress_callback(
request: Request,
code: str = Query(..., description="Authorization code from WordPress"),
state: str = Query(..., description="State parameter for security"),
error: Optional[str] = Query(None, description="Error from WordPress OAuth")
):
"""Handle WordPress OAuth2 callback."""
try:
# Check if JSON response is requested
wants_json = request.headers.get("accept") == "application/json" or request.query_params.get("format") == "json"
if error:
logger.error(f"WordPress OAuth error: {error}")
if wants_json:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"success": False, "error": error}
)
html_content = f"""
<!DOCTYPE html>
<html>
@@ -77,7 +86,7 @@ async def handle_wordpress_callback(
<script>
// Send error message to parent window
window.onload = function() {{
window.parent.postMessage({{
(window.opener || window.parent).postMessage({{
type: 'WPCOM_OAUTH_ERROR',
success: false,
error: '{error}'
@@ -100,6 +109,11 @@ async def handle_wordpress_callback(
if not code or not state:
logger.error("Missing code or state parameter in WordPress OAuth callback")
if wants_json:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"success": False, "error": "Missing parameters"}
)
html_content = """
<!DOCTYPE html>
<html>
@@ -134,6 +148,11 @@ async def handle_wordpress_callback(
if not result or not result.get('success'):
logger.error("Failed to exchange WordPress OAuth code for token")
if wants_json:
return JSONResponse(
status_code=status.HTTP_400_BAD_REQUEST,
content={"success": False, "error": "Token exchange failed"}
)
html_content = """
<!DOCTYPE html>
<html>
@@ -162,6 +181,18 @@ async def handle_wordpress_callback(
# Return success page with postMessage script
blog_url = result.get('blog_url', '')
blog_id = result.get('blog_id', '')
if wants_json:
return JSONResponse(
content={
"success": True,
"blog_url": blog_url,
"blog_id": blog_id,
"sites": [{"blog_url": blog_url, "blog_id": blog_id}] # Simplified for now
}
)
html_content = f"""
<!DOCTYPE html>
<html>
@@ -174,7 +205,7 @@ async def handle_wordpress_callback(
type: 'WPCOM_OAUTH_SUCCESS',
success: true,
blogUrl: '{blog_url}',
blogId: '{result.get('blog_id', '')}'
blogId: '{blog_id}'
}}, '*');
window.close();
}};