Implement real Wix token-backed routes and error mapping
This commit is contained in:
@@ -17,6 +17,7 @@ from middleware.auth_middleware import get_current_user
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
import requests
|
||||||
|
|
||||||
router = APIRouter(prefix="/api/wix", tags=["Wix Integration"])
|
router = APIRouter(prefix="/api/wix", tags=["Wix Integration"])
|
||||||
qa_router = APIRouter(prefix="/api/wix/test", tags=["Wix Integration QA"])
|
qa_router = APIRouter(prefix="/api/wix/test", tags=["Wix Integration QA"])
|
||||||
@@ -86,6 +87,63 @@ wix_service = WixService()
|
|||||||
wix_oauth_service = WixOAuthService()
|
wix_oauth_service = WixOAuthService()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_current_user_id(current_user: dict) -> str:
|
||||||
|
user_id = current_user.get("id") if current_user else None
|
||||||
|
if not user_id:
|
||||||
|
raise HTTPException(status_code=401, detail="Missing authenticated user context")
|
||||||
|
return user_id
|
||||||
|
|
||||||
|
|
||||||
|
def _map_wix_error(exc: Exception, fallback: str = "Wix API request failed") -> HTTPException:
|
||||||
|
if isinstance(exc, HTTPException):
|
||||||
|
return exc
|
||||||
|
if isinstance(exc, requests.HTTPError):
|
||||||
|
status = exc.response.status_code if exc.response is not None else None
|
||||||
|
if status == 401:
|
||||||
|
return HTTPException(status_code=401, detail="Wix authentication expired or invalid")
|
||||||
|
if status == 403:
|
||||||
|
return HTTPException(status_code=403, detail="Insufficient Wix permissions/scope")
|
||||||
|
return HTTPException(status_code=502, detail=fallback)
|
||||||
|
if isinstance(exc, requests.RequestException):
|
||||||
|
return HTTPException(status_code=502, detail=fallback)
|
||||||
|
return HTTPException(status_code=500, detail=str(exc))
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_valid_wix_token(current_user: dict) -> Dict[str, Any]:
|
||||||
|
user_id = _get_current_user_id(current_user)
|
||||||
|
tokens = wix_oauth_service.get_user_tokens(user_id)
|
||||||
|
if tokens:
|
||||||
|
return tokens[0]
|
||||||
|
|
||||||
|
token_status = wix_oauth_service.get_user_token_status(user_id)
|
||||||
|
expired_tokens = token_status.get("expired_tokens", [])
|
||||||
|
if not expired_tokens:
|
||||||
|
raise HTTPException(status_code=401, detail="Wix account not connected")
|
||||||
|
|
||||||
|
latest = expired_tokens[0]
|
||||||
|
refresh_token = latest.get("refresh_token")
|
||||||
|
if not refresh_token:
|
||||||
|
raise HTTPException(status_code=401, detail="Wix token expired and cannot be refreshed")
|
||||||
|
try:
|
||||||
|
refreshed = wix_service.refresh_access_token(refresh_token)
|
||||||
|
except Exception as exc:
|
||||||
|
raise _map_wix_error(exc, "Failed to refresh Wix access token")
|
||||||
|
|
||||||
|
wix_oauth_service.update_tokens(
|
||||||
|
user_id=user_id,
|
||||||
|
access_token=refreshed.get("access_token"),
|
||||||
|
refresh_token=refreshed.get("refresh_token", refresh_token),
|
||||||
|
expires_in=refreshed.get("expires_in"),
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"access_token": refreshed.get("access_token"),
|
||||||
|
"refresh_token": refreshed.get("refresh_token", refresh_token),
|
||||||
|
"member_id": latest.get("member_id"),
|
||||||
|
"site_id": latest.get("site_id"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class WixAuthRequest(BaseModel):
|
class WixAuthRequest(BaseModel):
|
||||||
"""Request model for Wix authentication"""
|
"""Request model for Wix authentication"""
|
||||||
code: str
|
code: str
|
||||||
@@ -351,21 +409,20 @@ async def get_connection_status(current_user: dict = Depends(get_current_user))
|
|||||||
Connection status and permissions
|
Connection status and permissions
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Check if user has Wix tokens stored in sessionStorage (frontend approach)
|
token_info = _resolve_valid_wix_token(current_user)
|
||||||
# This is a simplified check - in production you'd store tokens in database
|
access_token = token_info["access_token"]
|
||||||
|
site_info = wix_service.get_site_info(access_token)
|
||||||
|
permissions = wix_service.check_blog_permissions(access_token)
|
||||||
return WixConnectionStatus(
|
return WixConnectionStatus(
|
||||||
connected=False,
|
connected=True,
|
||||||
has_permissions=False,
|
has_permissions=permissions.get("has_permissions", False),
|
||||||
error="No Wix connection found. Please connect your Wix account first."
|
site_info=site_info,
|
||||||
|
permissions=permissions
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to check connection status: {e}")
|
logger.error(f"Failed to check connection status: {e}")
|
||||||
return WixConnectionStatus(
|
mapped = _map_wix_error(e, "Failed to check Wix connection status")
|
||||||
connected=False,
|
raise mapped
|
||||||
has_permissions=False,
|
|
||||||
error=str(e)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/status")
|
@router.get("/status")
|
||||||
@@ -376,22 +433,18 @@ async def get_wix_status(current_user: dict = Depends(get_current_user)) -> Dict
|
|||||||
The frontend will check sessionStorage and update the UI accordingly.
|
The frontend will check sessionStorage and update the UI accordingly.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Since Wix tokens are stored in frontend sessionStorage (not backend database),
|
token_info = _resolve_valid_wix_token(current_user)
|
||||||
# we return a default response. The frontend will check sessionStorage directly.
|
site_info = wix_service.get_site_info(token_info["access_token"])
|
||||||
return {
|
return {
|
||||||
"connected": False,
|
"connected": True,
|
||||||
"sites": [],
|
"sites": [site_info],
|
||||||
"total_sites": 0,
|
"total_sites": 1,
|
||||||
"error": "Wix connection status managed by frontend sessionStorage"
|
"site_info": site_info
|
||||||
}
|
}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to get Wix status: {e}")
|
logger.error(f"Failed to get Wix status: {e}")
|
||||||
return {
|
mapped = _map_wix_error(e, "Failed to get Wix status")
|
||||||
"connected": False,
|
raise mapped
|
||||||
"sites": [],
|
|
||||||
"total_sites": 0,
|
|
||||||
"error": str(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/publish")
|
@router.post("/publish")
|
||||||
@@ -407,63 +460,36 @@ async def publish_to_wix(request: WixPublishRequest, current_user: dict = Depend
|
|||||||
Published blog post information
|
Published blog post information
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# TODO: Retrieve stored access token from database for current_user
|
token_info = _resolve_valid_wix_token(current_user)
|
||||||
# For now, we'll return an error asking user to connect first
|
access_token = token_info["access_token"]
|
||||||
|
|
||||||
|
member_id = token_info.get("member_id") or wix_service.extract_member_id_from_access_token(access_token)
|
||||||
|
if not member_id:
|
||||||
|
member_info = wix_service.get_current_member(access_token)
|
||||||
|
member_id = (member_info.get("member") or {}).get("id") or member_info.get("id")
|
||||||
|
if not member_id:
|
||||||
|
raise HTTPException(status_code=401, detail="Unable to resolve Wix member ID")
|
||||||
|
|
||||||
|
result = wix_service.create_blog_post(
|
||||||
|
access_token=access_token,
|
||||||
|
title=request.title,
|
||||||
|
content=request.content,
|
||||||
|
cover_image_url=request.cover_image_url,
|
||||||
|
category_ids=request.category_ids,
|
||||||
|
tag_ids=request.tag_ids,
|
||||||
|
publish=request.publish,
|
||||||
|
member_id=member_id,
|
||||||
|
)
|
||||||
|
post = result.get("draftPost") or result.get("post") or result
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": True,
|
||||||
"error": "Wix account not connected. Please connect your Wix account first.",
|
"post_id": post.get("id"),
|
||||||
"message": "Use the /api/wix/auth/url endpoint to get the authorization URL"
|
"url": post.get("url"),
|
||||||
|
"publish_state": "PUBLISHED" if request.publish else "DRAFT"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Example of what the actual implementation would look like:
|
|
||||||
# access_token = get_stored_access_token(current_user['id'])
|
|
||||||
#
|
|
||||||
# if not access_token:
|
|
||||||
# raise HTTPException(status_code=401, detail="Wix account not connected")
|
|
||||||
#
|
|
||||||
# # Check if token is still valid, refresh if needed
|
|
||||||
# try:
|
|
||||||
# site_info = wix_service.get_site_info(access_token)
|
|
||||||
# except:
|
|
||||||
# # Token expired, try to refresh
|
|
||||||
# refresh_token = get_stored_refresh_token(current_user['id'])
|
|
||||||
# if refresh_token:
|
|
||||||
# new_tokens = wix_service.refresh_access_token(refresh_token)
|
|
||||||
# access_token = new_tokens['access_token']
|
|
||||||
# # Store new tokens
|
|
||||||
# else:
|
|
||||||
# raise HTTPException(status_code=401, detail="Wix session expired. Please reconnect.")
|
|
||||||
#
|
|
||||||
# # Get current member ID (required for third-party apps)
|
|
||||||
# member_info = wix_service.get_current_member(access_token)
|
|
||||||
# member_id = member_info.get('member', {}).get('id')
|
|
||||||
#
|
|
||||||
# if not member_id:
|
|
||||||
# raise HTTPException(status_code=400, detail="Could not retrieve member ID")
|
|
||||||
#
|
|
||||||
# # Create blog post
|
|
||||||
# result = wix_service.create_blog_post(
|
|
||||||
# access_token=access_token,
|
|
||||||
# title=request.title,
|
|
||||||
# content=request.content,
|
|
||||||
# cover_image_url=request.cover_image_url,
|
|
||||||
# category_ids=request.category_ids,
|
|
||||||
# tag_ids=request.tag_ids,
|
|
||||||
# publish=request.publish,
|
|
||||||
# member_id=member_id # Required for third-party apps
|
|
||||||
# )
|
|
||||||
#
|
|
||||||
# return {
|
|
||||||
# "success": True,
|
|
||||||
# "post_id": result.get('draftPost', {}).get('id'),
|
|
||||||
# "url": result.get('draftPost', {}).get('url'),
|
|
||||||
# "message": "Blog post published successfully to Wix"
|
|
||||||
# }
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to publish to Wix: {e}")
|
logger.error(f"Failed to publish to Wix: {e}")
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise _map_wix_error(e, "Failed to publish to Wix")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/categories")
|
@router.get("/categories")
|
||||||
@@ -478,23 +504,15 @@ async def get_blog_categories(current_user: dict = Depends(get_current_user)) ->
|
|||||||
List of blog categories
|
List of blog categories
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# TODO: Retrieve stored access token from database for current_user
|
token_info = _resolve_valid_wix_token(current_user)
|
||||||
|
categories = wix_service.get_blog_categories(token_info["access_token"])
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": True,
|
||||||
"error": "Wix account not connected. Please connect your Wix account first."
|
"categories": categories
|
||||||
}
|
}
|
||||||
|
|
||||||
# Example implementation:
|
|
||||||
# access_token = get_stored_access_token(current_user['id'])
|
|
||||||
# if not access_token:
|
|
||||||
# raise HTTPException(status_code=401, detail="Wix account not connected")
|
|
||||||
#
|
|
||||||
# categories = wix_service.get_blog_categories(access_token)
|
|
||||||
# return {"categories": categories}
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to get blog categories: {e}")
|
logger.error(f"Failed to get blog categories: {e}")
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise _map_wix_error(e, "Failed to fetch Wix blog categories")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/tags")
|
@router.get("/tags")
|
||||||
@@ -509,23 +527,15 @@ async def get_blog_tags(current_user: dict = Depends(get_current_user)) -> Dict[
|
|||||||
List of blog tags
|
List of blog tags
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# TODO: Retrieve stored access token from database for current_user
|
token_info = _resolve_valid_wix_token(current_user)
|
||||||
|
tags = wix_service.get_blog_tags(token_info["access_token"])
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"success": True,
|
||||||
"error": "Wix account not connected. Please connect your Wix account first."
|
"tags": tags
|
||||||
}
|
}
|
||||||
|
|
||||||
# Example implementation:
|
|
||||||
# access_token = get_stored_access_token(current_user['id'])
|
|
||||||
# if not access_token:
|
|
||||||
# raise HTTPException(status_code=401, detail="Wix account not connected")
|
|
||||||
#
|
|
||||||
# tags = wix_service.get_blog_tags(access_token)
|
|
||||||
# return {"tags": tags}
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to get blog tags: {e}")
|
logger.error(f"Failed to get blog tags: {e}")
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise _map_wix_error(e, "Failed to fetch Wix blog tags")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/disconnect")
|
@router.post("/disconnect")
|
||||||
@@ -540,15 +550,22 @@ async def disconnect_wix(current_user: dict = Depends(get_current_user)) -> Dict
|
|||||||
Disconnection status
|
Disconnection status
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# TODO: Remove stored tokens from database for current_user
|
user_id = _get_current_user_id(current_user)
|
||||||
|
token_status = wix_oauth_service.get_user_token_status(user_id)
|
||||||
|
all_tokens = token_status.get("active_tokens", []) + token_status.get("expired_tokens", [])
|
||||||
|
for token in all_tokens:
|
||||||
|
token_id = token.get("id")
|
||||||
|
if token_id:
|
||||||
|
wix_oauth_service.revoke_token(user_id, token_id)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
|
"connected": False,
|
||||||
"message": "Wix account disconnected successfully"
|
"message": "Wix account disconnected successfully"
|
||||||
}
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to disconnect Wix: {e}")
|
logger.error(f"Failed to disconnect Wix: {e}")
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise _map_wix_error(e, "Failed to disconnect Wix account")
|
||||||
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user