Base code
This commit is contained in:
678
backend/api/wix_routes.py
Normal file
678
backend/api/wix_routes.py
Normal file
@@ -0,0 +1,678 @@
|
||||
"""
|
||||
Wix Integration API Routes
|
||||
|
||||
Handles Wix authentication, connection status, and blog publishing.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Depends, Request
|
||||
from fastapi.responses import HTMLResponse
|
||||
from typing import Dict, Any, Optional
|
||||
from loguru import logger
|
||||
from pydantic import BaseModel
|
||||
|
||||
from services.wix_service import WixService
|
||||
from services.integrations.wix_oauth import WixOAuthService
|
||||
from middleware.auth_middleware import get_current_user
|
||||
import os
|
||||
|
||||
router = APIRouter(prefix="/api/wix", tags=["Wix Integration"])
|
||||
|
||||
# Initialize Wix service
|
||||
wix_service = WixService()
|
||||
|
||||
# Initialize Wix OAuth service for token storage
|
||||
wix_oauth_service = WixOAuthService(db_path=os.path.abspath("alwrity.db"))
|
||||
|
||||
|
||||
class WixAuthRequest(BaseModel):
|
||||
"""Request model for Wix authentication"""
|
||||
code: str
|
||||
state: Optional[str] = None
|
||||
|
||||
|
||||
class WixPublishRequest(BaseModel):
|
||||
"""Request model for publishing to Wix"""
|
||||
title: str
|
||||
content: str
|
||||
cover_image_url: Optional[str] = None
|
||||
category_ids: Optional[list] = None
|
||||
tag_ids: Optional[list] = None
|
||||
publish: bool = True
|
||||
# Optional access token for test-real publish flow
|
||||
access_token: Optional[str] = None
|
||||
class WixCreateCategoryRequest(BaseModel):
|
||||
access_token: str
|
||||
label: str
|
||||
description: Optional[str] = None
|
||||
language: Optional[str] = None
|
||||
|
||||
|
||||
class WixCreateTagRequest(BaseModel):
|
||||
access_token: str
|
||||
label: str
|
||||
language: Optional[str] = None
|
||||
|
||||
|
||||
class WixConnectionStatus(BaseModel):
|
||||
"""Response model for Wix connection status"""
|
||||
connected: bool
|
||||
has_permissions: bool
|
||||
site_info: Optional[Dict[str, Any]] = None
|
||||
permissions: Optional[Dict[str, Any]] = None
|
||||
error: Optional[str] = None
|
||||
|
||||
|
||||
@router.get("/auth/url")
|
||||
async def get_authorization_url(state: Optional[str] = None) -> Dict[str, str]:
|
||||
"""
|
||||
Get Wix OAuth authorization URL
|
||||
|
||||
Args:
|
||||
state: Optional state parameter for security
|
||||
|
||||
Returns:
|
||||
Authorization URL
|
||||
"""
|
||||
try:
|
||||
url = wix_service.get_authorization_url(state)
|
||||
return {"authorization_url": url}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to generate authorization URL: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/auth/callback")
|
||||
async def handle_oauth_callback(request: WixAuthRequest, current_user: dict = Depends(get_current_user)) -> Dict[str, Any]:
|
||||
"""
|
||||
Handle OAuth callback and exchange code for tokens
|
||||
|
||||
Args:
|
||||
request: OAuth callback request with code
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
Token information and connection status
|
||||
"""
|
||||
try:
|
||||
user_id = current_user.get('id')
|
||||
if not user_id:
|
||||
raise HTTPException(status_code=400, detail="User ID not found")
|
||||
|
||||
# Exchange code for tokens
|
||||
tokens = wix_service.exchange_code_for_tokens(request.code)
|
||||
|
||||
# Get site information to extract site_id and member_id
|
||||
site_info = wix_service.get_site_info(tokens['access_token'])
|
||||
site_id = site_info.get('siteId') or site_info.get('site_id')
|
||||
|
||||
# Extract member_id from token if possible
|
||||
member_id = None
|
||||
try:
|
||||
member_id = wix_service.extract_member_id_from_access_token(tokens['access_token'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Check permissions
|
||||
permissions = wix_service.check_blog_permissions(tokens['access_token'])
|
||||
|
||||
# Store tokens securely in database
|
||||
stored = wix_oauth_service.store_tokens(
|
||||
user_id=user_id,
|
||||
access_token=tokens['access_token'],
|
||||
refresh_token=tokens.get('refresh_token'),
|
||||
expires_in=tokens.get('expires_in'),
|
||||
token_type=tokens.get('token_type', 'Bearer'),
|
||||
scope=tokens.get('scope'),
|
||||
site_id=site_id,
|
||||
member_id=member_id
|
||||
)
|
||||
|
||||
if not stored:
|
||||
logger.warning(f"Failed to store Wix tokens for user {user_id}, but OAuth succeeded")
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"tokens": {
|
||||
"access_token": tokens['access_token'],
|
||||
"refresh_token": tokens.get('refresh_token'),
|
||||
"expires_in": tokens.get('expires_in'),
|
||||
"token_type": tokens.get('token_type', 'Bearer')
|
||||
},
|
||||
"site_info": site_info,
|
||||
"permissions": permissions,
|
||||
"message": "Successfully connected to Wix"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to handle OAuth callback: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/callback")
|
||||
async def handle_oauth_callback_get(code: str, state: Optional[str] = None, request: Request = None, current_user: dict = Depends(get_current_user)):
|
||||
"""HTML callback page for Wix OAuth that exchanges code and notifies opener via postMessage."""
|
||||
try:
|
||||
tokens = wix_service.exchange_code_for_tokens(code)
|
||||
site_info = wix_service.get_site_info(tokens['access_token'])
|
||||
permissions = wix_service.check_blog_permissions(tokens['access_token'])
|
||||
|
||||
# Store tokens in database if we have user_id
|
||||
user_id = current_user.get('id') if current_user else None
|
||||
if user_id:
|
||||
site_id = site_info.get('siteId') or site_info.get('site_id')
|
||||
member_id = None
|
||||
try:
|
||||
member_id = wix_service.extract_member_id_from_access_token(tokens['access_token'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
stored = wix_oauth_service.store_tokens(
|
||||
user_id=user_id,
|
||||
access_token=tokens['access_token'],
|
||||
refresh_token=tokens.get('refresh_token'),
|
||||
expires_in=tokens.get('expires_in'),
|
||||
token_type=tokens.get('token_type', 'Bearer'),
|
||||
scope=tokens.get('scope'),
|
||||
site_id=site_id,
|
||||
member_id=member_id
|
||||
)
|
||||
if not stored:
|
||||
logger.warning(f"Failed to store Wix tokens for user {user_id} in GET callback")
|
||||
|
||||
# Build success payload for postMessage
|
||||
payload = {
|
||||
"type": "WIX_OAUTH_SUCCESS",
|
||||
"success": True,
|
||||
"tokens": {
|
||||
"access_token": tokens['access_token'],
|
||||
"refresh_token": tokens.get('refresh_token'),
|
||||
"expires_in": tokens.get('expires_in'),
|
||||
"token_type": tokens.get('token_type', 'Bearer')
|
||||
},
|
||||
"site_info": site_info,
|
||||
"permissions": permissions
|
||||
}
|
||||
|
||||
html = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Wix Connected</title></head>
|
||||
<body>
|
||||
<script>
|
||||
(function() {{
|
||||
try {{
|
||||
var payload = {payload};
|
||||
(window.opener || window.parent).postMessage(payload, '*');
|
||||
}} catch (e) {{}}
|
||||
window.close();
|
||||
}})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return HTMLResponse(content=html, headers={
|
||||
"Cross-Origin-Opener-Policy": "unsafe-none",
|
||||
"Cross-Origin-Embedder-Policy": "unsafe-none"
|
||||
})
|
||||
except Exception as e:
|
||||
logger.error(f"Wix OAuth GET callback failed: {e}")
|
||||
html = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Wix Connection Failed</title></head>
|
||||
<body>
|
||||
<script>
|
||||
(function() {{
|
||||
try {{
|
||||
(window.opener || window.parent).postMessage({{ type: 'WIX_OAUTH_ERROR', success: false, error: '{str(e)}' }}, '*');
|
||||
}} catch (e) {{}}
|
||||
window.close();
|
||||
}})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return HTMLResponse(content=html, headers={
|
||||
"Cross-Origin-Opener-Policy": "unsafe-none",
|
||||
"Cross-Origin-Embedder-Policy": "unsafe-none"
|
||||
})
|
||||
|
||||
|
||||
@router.get("/connection/status")
|
||||
async def get_connection_status(current_user: dict = Depends(get_current_user)) -> WixConnectionStatus:
|
||||
"""
|
||||
Check Wix connection status and permissions
|
||||
|
||||
Args:
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
Connection status and permissions
|
||||
"""
|
||||
try:
|
||||
# Check if user has Wix tokens stored in sessionStorage (frontend approach)
|
||||
# This is a simplified check - in production you'd store tokens in database
|
||||
return WixConnectionStatus(
|
||||
connected=False,
|
||||
has_permissions=False,
|
||||
error="No Wix connection found. Please connect your Wix account first."
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to check connection status: {e}")
|
||||
return WixConnectionStatus(
|
||||
connected=False,
|
||||
has_permissions=False,
|
||||
error=str(e)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
async def get_wix_status(current_user: dict = Depends(get_current_user)) -> Dict[str, Any]:
|
||||
"""
|
||||
Get Wix connection status (similar to GSC/WordPress pattern)
|
||||
Note: Wix tokens are stored in frontend sessionStorage, so we can't directly check them here.
|
||||
The frontend will check sessionStorage and update the UI accordingly.
|
||||
"""
|
||||
try:
|
||||
# Since Wix tokens are stored in frontend sessionStorage (not backend database),
|
||||
# we return a default response. The frontend will check sessionStorage directly.
|
||||
return {
|
||||
"connected": False,
|
||||
"sites": [],
|
||||
"total_sites": 0,
|
||||
"error": "Wix connection status managed by frontend sessionStorage"
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get Wix status: {e}")
|
||||
return {
|
||||
"connected": False,
|
||||
"sites": [],
|
||||
"total_sites": 0,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
|
||||
@router.post("/publish")
|
||||
async def publish_to_wix(request: WixPublishRequest, current_user: dict = Depends(get_current_user)) -> Dict[str, Any]:
|
||||
"""
|
||||
Publish blog post to Wix
|
||||
|
||||
Args:
|
||||
request: Blog post data
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
Published blog post information
|
||||
"""
|
||||
try:
|
||||
# TODO: Retrieve stored access token from database for current_user
|
||||
# For now, we'll return an error asking user to connect first
|
||||
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Wix account not connected. Please connect your Wix account first.",
|
||||
"message": "Use the /api/wix/auth/url endpoint to get the authorization URL"
|
||||
}
|
||||
|
||||
# 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:
|
||||
logger.error(f"Failed to publish to Wix: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/categories")
|
||||
async def get_blog_categories(current_user: dict = Depends(get_current_user)) -> Dict[str, Any]:
|
||||
"""
|
||||
Get available blog categories from Wix
|
||||
|
||||
Args:
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
List of blog categories
|
||||
"""
|
||||
try:
|
||||
# TODO: Retrieve stored access token from database for current_user
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Wix account not connected. Please connect your Wix account first."
|
||||
}
|
||||
|
||||
# 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:
|
||||
logger.error(f"Failed to get blog categories: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/tags")
|
||||
async def get_blog_tags(current_user: dict = Depends(get_current_user)) -> Dict[str, Any]:
|
||||
"""
|
||||
Get available blog tags from Wix
|
||||
|
||||
Args:
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
List of blog tags
|
||||
"""
|
||||
try:
|
||||
# TODO: Retrieve stored access token from database for current_user
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Wix account not connected. Please connect your Wix account first."
|
||||
}
|
||||
|
||||
# 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:
|
||||
logger.error(f"Failed to get blog tags: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/disconnect")
|
||||
async def disconnect_wix(current_user: dict = Depends(get_current_user)) -> Dict[str, Any]:
|
||||
"""
|
||||
Disconnect Wix account
|
||||
|
||||
Args:
|
||||
current_user: Current authenticated user
|
||||
|
||||
Returns:
|
||||
Disconnection status
|
||||
"""
|
||||
try:
|
||||
# TODO: Remove stored tokens from database for current_user
|
||||
return {
|
||||
"success": True,
|
||||
"message": "Wix account disconnected successfully"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to disconnect Wix: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TEST ENDPOINTS - No authentication required for testing
|
||||
# =============================================================================
|
||||
|
||||
@router.get("/test/connection/status")
|
||||
async def get_test_connection_status() -> WixConnectionStatus:
|
||||
"""
|
||||
TEST ENDPOINT: Check Wix connection status without authentication
|
||||
|
||||
Returns:
|
||||
Connection status and permissions
|
||||
"""
|
||||
try:
|
||||
logger.info("TEST: Checking Wix connection status (no auth required)")
|
||||
|
||||
return WixConnectionStatus(
|
||||
connected=False,
|
||||
has_permissions=False,
|
||||
error="No stored tokens found. Please connect your Wix account first."
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"TEST: Failed to check connection status: {e}")
|
||||
return WixConnectionStatus(
|
||||
connected=False,
|
||||
has_permissions=False,
|
||||
error=str(e)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/test/auth/url")
|
||||
async def get_test_authorization_url(state: Optional[str] = None) -> Dict[str, str]:
|
||||
"""
|
||||
TEST ENDPOINT: Get Wix OAuth authorization URL without authentication
|
||||
|
||||
Args:
|
||||
state: Optional state parameter for security
|
||||
|
||||
Returns:
|
||||
Authorization URL for user to visit
|
||||
"""
|
||||
try:
|
||||
logger.info("TEST: Generating Wix authorization URL (no auth required)")
|
||||
|
||||
# Check if Wix service is properly configured
|
||||
if not wix_service.client_id:
|
||||
logger.warning("TEST: Wix Client ID not configured, returning mock URL")
|
||||
return {
|
||||
"url": (
|
||||
"https://www.wix.com/oauth/access?client_id=YOUR_CLIENT_ID"
|
||||
"&redirect_uri=http://localhost:3000/wix/callback"
|
||||
"&response_type=code&scope="
|
||||
"BLOG.CREATE-DRAFT,BLOG.PUBLISH-POST,BLOG.READ-CATEGORY,"
|
||||
"BLOG.CREATE-CATEGORY,BLOG.READ-TAG,BLOG.CREATE-TAG,"
|
||||
"MEDIA.SITE_MEDIA_FILES_IMPORT"
|
||||
"&code_challenge=test&code_challenge_method=S256"
|
||||
),
|
||||
"state": state or "test_state",
|
||||
"message": "WIX_CLIENT_ID not configured. Please set it in your .env file to get a real authorization URL."
|
||||
}
|
||||
|
||||
auth_url = wix_service.get_authorization_url(state)
|
||||
return {"url": auth_url, "state": state or "test_state"}
|
||||
except Exception as e:
|
||||
logger.error(f"TEST: Failed to generate authorization URL: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/test/publish")
|
||||
async def test_publish_to_wix(request: WixPublishRequest) -> Dict[str, Any]:
|
||||
"""
|
||||
TEST ENDPOINT: Simulate publishing a blog post to Wix without authentication.
|
||||
|
||||
Returns a fake success response so the frontend can validate the flow.
|
||||
"""
|
||||
try:
|
||||
logger.info("TEST: Simulating publish to Wix (no auth required)")
|
||||
return {
|
||||
"success": True,
|
||||
"post_id": "test_post_id",
|
||||
"url": "https://example.com/blog/test-post",
|
||||
"message": "Simulated blog post published successfully (test mode)"
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"TEST: Failed to simulate publish: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/refresh-token")
|
||||
async def refresh_wix_token(request: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Refresh Wix access token using refresh token
|
||||
|
||||
Args:
|
||||
request: Dict containing refresh_token
|
||||
|
||||
Returns:
|
||||
New token information with access_token, refresh_token, expires_in
|
||||
"""
|
||||
try:
|
||||
refresh_token = request.get("refresh_token")
|
||||
if not refresh_token:
|
||||
raise HTTPException(status_code=400, detail="Missing refresh_token")
|
||||
|
||||
# Refresh the token
|
||||
new_tokens = wix_service.refresh_access_token(refresh_token)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"access_token": new_tokens.get("access_token"),
|
||||
"refresh_token": new_tokens.get("refresh_token"),
|
||||
"expires_in": new_tokens.get("expires_in"),
|
||||
"token_type": new_tokens.get("token_type", "Bearer")
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to refresh Wix token: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to refresh token: {str(e)}")
|
||||
|
||||
|
||||
@router.post("/test/publish/real")
|
||||
async def test_publish_real(payload: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
TEST ENDPOINT: Perform a real publish to Wix using a provided access token.
|
||||
|
||||
Notes:
|
||||
- Expects request.access_token from the frontend's Wix SDK tokens
|
||||
- Derives member_id server-side (required by Wix for third-party apps)
|
||||
"""
|
||||
try:
|
||||
# Normalize access_token from payload (could be string, dict, or other format)
|
||||
from services.integrations.wix.utils import normalize_token_string
|
||||
raw_access_token = payload.get("access_token")
|
||||
if not raw_access_token:
|
||||
raise HTTPException(status_code=400, detail="Missing access_token")
|
||||
|
||||
# Normalize token to string (handles dict with accessToken.value, int, etc.)
|
||||
access_token = normalize_token_string(raw_access_token)
|
||||
if not access_token:
|
||||
# Fallback: try to convert to string directly
|
||||
access_token = str(raw_access_token).strip()
|
||||
if not access_token or access_token == "None":
|
||||
raise HTTPException(status_code=400, detail="Invalid access_token format")
|
||||
|
||||
# Derive current member id from token (try local decode first, then API fallback)
|
||||
member_id = 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=400, detail="Unable to resolve member_id from token")
|
||||
|
||||
# Extract SEO metadata if provided
|
||||
seo_metadata = payload.get("seo_metadata")
|
||||
|
||||
# Extract category/tag IDs or names
|
||||
# Can be either:
|
||||
# - IDs: List of UUID strings
|
||||
# - Names: List of name strings (will be looked up/created)
|
||||
category_ids = payload.get("category_ids") or payload.get("category_names")
|
||||
tag_ids = payload.get("tag_ids") or payload.get("tag_names")
|
||||
|
||||
# If SEO metadata has categories/tags but they weren't explicitly provided, use them
|
||||
if seo_metadata:
|
||||
if not category_ids and seo_metadata.get("blog_categories"):
|
||||
category_ids = seo_metadata.get("blog_categories")
|
||||
if not tag_ids and seo_metadata.get("blog_tags"):
|
||||
tag_ids = seo_metadata.get("blog_tags")
|
||||
|
||||
result = wix_service.create_blog_post(
|
||||
access_token=access_token,
|
||||
title=payload.get("title") or "Untitled",
|
||||
content=payload.get("content") or "",
|
||||
cover_image_url=payload.get("cover_image_url"),
|
||||
category_ids=category_ids,
|
||||
tag_ids=tag_ids,
|
||||
publish=bool(payload.get("publish", True)),
|
||||
member_id=member_id,
|
||||
seo_metadata=seo_metadata,
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"post_id": (result.get("draftPost") or result.get("post") or {}).get("id"),
|
||||
"url": (result.get("draftPost") or result.get("post") or {}).get("url"),
|
||||
"message": "Blog post published to Wix",
|
||||
"raw": result,
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"TEST: Real publish failed: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/test/category")
|
||||
async def test_create_category(request: WixCreateCategoryRequest) -> Dict[str, Any]:
|
||||
try:
|
||||
result = wix_service.create_category(
|
||||
access_token=request.access_token,
|
||||
label=request.label,
|
||||
description=request.description,
|
||||
language=request.language,
|
||||
)
|
||||
return {"success": True, "category": result.get("category", {}), "raw": result}
|
||||
except Exception as e:
|
||||
logger.error(f"TEST: Create category failed: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.post("/test/tag")
|
||||
async def test_create_tag(request: WixCreateTagRequest) -> Dict[str, Any]:
|
||||
try:
|
||||
result = wix_service.create_tag(
|
||||
access_token=request.access_token,
|
||||
label=request.label,
|
||||
language=request.language,
|
||||
)
|
||||
return {"success": True, "tag": result.get("tag", {}), "raw": result}
|
||||
except Exception as e:
|
||||
logger.error(f"TEST: Create tag failed: {e}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
Reference in New Issue
Block a user