Files
ALwrity/backend/api/oauth_token_monitoring_routes.py
2025-11-05 08:51:00 +05:30

311 lines
12 KiB
Python

"""
OAuth Token Monitoring API Routes
Provides endpoints for managing OAuth token monitoring tasks and manual triggers.
"""
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from typing import List, Dict, Any, Optional
from datetime import datetime
from loguru import logger
from services.database import get_db_session
from middleware.auth_middleware import get_current_user
from models.oauth_token_monitoring_models import OAuthTokenMonitoringTask, OAuthTokenExecutionLog
from services.scheduler import get_scheduler
from services.oauth_token_monitoring_service import create_oauth_monitoring_tasks, get_connected_platforms
router = APIRouter(prefix="/api/oauth-tokens", tags=["oauth-tokens"])
@router.get("/status/{user_id}")
async def get_oauth_token_status(
user_id: str,
db: Session = Depends(get_db_session),
current_user: Dict[str, Any] = Depends(get_current_user)
) -> Dict[str, Any]:
"""
Get OAuth token monitoring status for all platforms for a user.
Returns:
- List of monitoring tasks with status
- Connection status for each platform
- Last check time, last success, last failure
"""
try:
# Verify user can only access their own data
if str(current_user.get('id')) != user_id:
raise HTTPException(status_code=403, detail="Access denied")
# Get all monitoring tasks for user
tasks = db.query(OAuthTokenMonitoringTask).filter(
OAuthTokenMonitoringTask.user_id == user_id
).all()
# Get connected platforms
logger.info(f"[OAuth Status API] Getting token status for user: {user_id}")
connected_platforms = get_connected_platforms(user_id)
logger.info(f"[OAuth Status API] Found {len(connected_platforms)} connected platforms: {connected_platforms}")
# Build status response
platform_status = {}
for platform in ['gsc', 'bing', 'wordpress', 'wix']:
task = next((t for t in tasks if t.platform == platform), None)
is_connected = platform in connected_platforms
platform_status[platform] = {
'connected': is_connected,
'monitoring_task': {
'id': task.id if task else None,
'status': task.status if task else 'not_created',
'last_check': task.last_check.isoformat() if task and task.last_check else None,
'last_success': task.last_success.isoformat() if task and task.last_success else None,
'last_failure': task.last_failure.isoformat() if task and task.last_failure else None,
'failure_reason': task.failure_reason if task else None,
'next_check': task.next_check.isoformat() if task and task.next_check else None,
} if task else None
}
logger.info(
f"[OAuth Status API] Platform {platform}: "
f"connected={is_connected}, "
f"task_exists={task is not None}, "
f"task_status={task.status if task else 'N/A'}"
)
response_data = {
"success": True,
"data": {
"user_id": user_id,
"platform_status": platform_status,
"connected_platforms": connected_platforms
}
}
logger.info(f"[OAuth Status API] Returning status for user {user_id}: {len(connected_platforms)} platforms connected")
return response_data
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting OAuth token status for user {user_id}: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to get token status: {str(e)}")
@router.post("/refresh/{user_id}/{platform}")
async def manual_refresh_token(
user_id: str,
platform: str,
db: Session = Depends(get_db_session),
current_user: Dict[str, Any] = Depends(get_current_user)
) -> Dict[str, Any]:
"""
Manually trigger token refresh for a specific platform.
This will:
1. Find or create the monitoring task
2. Execute the token check/refresh immediately
3. Update the task status and next_check time
Args:
user_id: User ID
platform: Platform identifier ('gsc', 'bing', 'wordpress', 'wix')
"""
try:
# Verify user can only access their own data
if str(current_user.get('id')) != user_id:
raise HTTPException(status_code=403, detail="Access denied")
# Validate platform
valid_platforms = ['gsc', 'bing', 'wordpress', 'wix']
if platform not in valid_platforms:
raise HTTPException(
status_code=400,
detail=f"Invalid platform. Must be one of: {', '.join(valid_platforms)}"
)
# Get or create monitoring task
task = db.query(OAuthTokenMonitoringTask).filter(
OAuthTokenMonitoringTask.user_id == user_id,
OAuthTokenMonitoringTask.platform == platform
).first()
if not task:
# Create task if it doesn't exist
task = OAuthTokenMonitoringTask(
user_id=user_id,
platform=platform,
status='active',
next_check=datetime.utcnow(), # Set to now to trigger immediately
created_at=datetime.utcnow(),
updated_at=datetime.utcnow()
)
db.add(task)
db.commit()
db.refresh(task)
logger.info(f"Created monitoring task for manual refresh: user={user_id}, platform={platform}")
# Get scheduler and executor
scheduler = get_scheduler()
try:
executor = scheduler.registry.get_executor('oauth_token_monitoring')
except ValueError:
raise HTTPException(status_code=500, detail="OAuth token monitoring executor not available")
# Execute task immediately
logger.info(f"Manually triggering token refresh: user={user_id}, platform={platform}")
result = await executor.execute_task(task, db)
# Get updated task
db.refresh(task)
return {
"success": result.success,
"message": "Token refresh completed" if result.success else "Token refresh failed",
"data": {
"platform": platform,
"status": task.status,
"last_check": task.last_check.isoformat() if task.last_check else None,
"last_success": task.last_success.isoformat() if task.last_success else None,
"last_failure": task.last_failure.isoformat() if task.last_failure else None,
"failure_reason": task.failure_reason,
"next_check": task.next_check.isoformat() if task.next_check else None,
"execution_result": {
"success": result.success,
"error_message": result.error_message,
"execution_time_ms": result.execution_time_ms,
"result_data": result.result_data
}
}
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error manually refreshing token for user {user_id}, platform {platform}: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to refresh token: {str(e)}")
@router.get("/execution-logs/{user_id}")
async def get_execution_logs(
user_id: str,
platform: Optional[str] = Query(None, description="Filter by platform"),
limit: int = Query(50, ge=1, le=100, description="Maximum number of logs"),
offset: int = Query(0, ge=0, description="Offset for pagination"),
db: Session = Depends(get_db_session),
current_user: Dict[str, Any] = Depends(get_current_user)
) -> Dict[str, Any]:
"""
Get execution logs for OAuth token monitoring tasks.
Args:
user_id: User ID
platform: Optional platform filter
limit: Maximum number of logs to return
offset: Pagination offset
"""
try:
# Verify user can only access their own data
if str(current_user.get('id')) != user_id:
raise HTTPException(status_code=403, detail="Access denied")
# Build query
query = db.query(OAuthTokenExecutionLog).join(
OAuthTokenMonitoringTask,
OAuthTokenExecutionLog.task_id == OAuthTokenMonitoringTask.id
).filter(
OAuthTokenMonitoringTask.user_id == user_id
)
# Apply platform filter if provided
if platform:
query = query.filter(OAuthTokenMonitoringTask.platform == platform)
# Get total count
total_count = query.count()
# Get paginated logs
logs = query.order_by(
OAuthTokenExecutionLog.execution_date.desc()
).offset(offset).limit(limit).all()
# Format logs
logs_data = []
for log in logs:
logs_data.append({
"id": log.id,
"task_id": log.task_id,
"platform": log.task.platform, # Get platform from relationship
"execution_date": log.execution_date.isoformat(),
"status": log.status,
"result_data": log.result_data,
"error_message": log.error_message,
"execution_time_ms": log.execution_time_ms,
"created_at": log.created_at.isoformat()
})
return {
"success": True,
"data": {
"logs": logs_data,
"total_count": total_count,
"limit": limit,
"offset": offset
}
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting execution logs for user {user_id}: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to get execution logs: {str(e)}")
@router.post("/create-tasks/{user_id}")
async def create_monitoring_tasks(
user_id: str,
platforms: Optional[List[str]] = None,
db: Session = Depends(get_db_session),
current_user: Dict[str, Any] = Depends(get_current_user)
) -> Dict[str, Any]:
"""
Manually create OAuth token monitoring tasks for a user.
If platforms are not provided, automatically detects connected platforms.
Args:
user_id: User ID
platforms: Optional list of platforms to create tasks for
"""
try:
# Verify user can only access their own data
if str(current_user.get('id')) != user_id:
raise HTTPException(status_code=403, detail="Access denied")
# Create tasks
tasks = create_oauth_monitoring_tasks(user_id, db, platforms)
return {
"success": True,
"message": f"Created {len(tasks)} monitoring task(s)",
"data": {
"tasks_created": len(tasks),
"tasks": [
{
"id": task.id,
"platform": task.platform,
"status": task.status,
"next_check": task.next_check.isoformat() if task.next_check else None
}
for task in tasks
]
}
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error creating monitoring tasks for user {user_id}: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"Failed to create monitoring tasks: {str(e)}")