igny8-wp
This commit is contained in:
400
backend/igny8_core/api/wordpress_publishing.py
Normal file
400
backend/igny8_core/api/wordpress_publishing.py
Normal file
@@ -0,0 +1,400 @@
|
||||
"""
|
||||
WordPress Publishing API Views
|
||||
Handles manual content publishing to WordPress sites
|
||||
"""
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils import timezone
|
||||
from typing import Dict, Any, List
|
||||
|
||||
from igny8_core.models import ContentPost, SiteIntegration
|
||||
from igny8_core.tasks.wordpress_publishing import (
|
||||
publish_content_to_wordpress,
|
||||
bulk_publish_content_to_wordpress
|
||||
)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def publish_single_content(request, content_id: int) -> Response:
|
||||
"""
|
||||
Publish a single content item to WordPress
|
||||
|
||||
POST /api/v1/content/{content_id}/publish-to-wordpress/
|
||||
|
||||
Body:
|
||||
{
|
||||
"site_integration_id": 123, // Optional - will use default if not provided
|
||||
"force": false // Optional - force republish even if already published
|
||||
}
|
||||
"""
|
||||
try:
|
||||
content = get_object_or_404(ContentPost, id=content_id)
|
||||
|
||||
# Check permissions
|
||||
if not request.user.has_perm('content.change_contentpost'):
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Permission denied',
|
||||
'error': 'insufficient_permissions'
|
||||
},
|
||||
status=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
# Get site integration
|
||||
site_integration_id = request.data.get('site_integration_id')
|
||||
force = request.data.get('force', False)
|
||||
|
||||
if site_integration_id:
|
||||
site_integration = get_object_or_404(SiteIntegration, id=site_integration_id)
|
||||
else:
|
||||
# Get default WordPress integration for user's organization
|
||||
site_integration = SiteIntegration.objects.filter(
|
||||
platform='wordpress',
|
||||
is_active=True,
|
||||
# Add organization filter if applicable
|
||||
).first()
|
||||
|
||||
if not site_integration:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'No WordPress integration found',
|
||||
'error': 'no_integration'
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Check if already published (unless force is true)
|
||||
if not force and content.wordpress_sync_status == 'success':
|
||||
return Response(
|
||||
{
|
||||
'success': True,
|
||||
'message': 'Content already published to WordPress',
|
||||
'data': {
|
||||
'content_id': content.id,
|
||||
'wordpress_post_id': content.wordpress_post_id,
|
||||
'wordpress_post_url': content.wordpress_post_url,
|
||||
'status': 'already_published'
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
# Check if currently syncing
|
||||
if content.wordpress_sync_status == 'syncing':
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Content is currently being published to WordPress',
|
||||
'error': 'sync_in_progress'
|
||||
},
|
||||
status=status.HTTP_409_CONFLICT
|
||||
)
|
||||
|
||||
# Validate content is ready for publishing
|
||||
if not content.title or not (content.content_html or content.content):
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Content is incomplete - missing title or content',
|
||||
'error': 'incomplete_content'
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Set status to pending and queue the task
|
||||
content.wordpress_sync_status = 'pending'
|
||||
content.save(update_fields=['wordpress_sync_status'])
|
||||
|
||||
# Get task_id if content is associated with a writer task
|
||||
task_id = None
|
||||
if hasattr(content, 'writer_task'):
|
||||
task_id = content.writer_task.id
|
||||
|
||||
# Queue the publishing task
|
||||
task_result = publish_content_to_wordpress.delay(
|
||||
content.id,
|
||||
site_integration.id,
|
||||
task_id
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'success': True,
|
||||
'message': 'Content queued for WordPress publishing',
|
||||
'data': {
|
||||
'content_id': content.id,
|
||||
'site_integration_id': site_integration.id,
|
||||
'task_id': task_result.id,
|
||||
'status': 'queued'
|
||||
}
|
||||
},
|
||||
status=status.HTTP_202_ACCEPTED
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': f'Error queuing content for WordPress publishing: {str(e)}',
|
||||
'error': 'server_error'
|
||||
},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def bulk_publish_content(request) -> Response:
|
||||
"""
|
||||
Bulk publish multiple content items to WordPress
|
||||
|
||||
POST /api/v1/content/bulk-publish-to-wordpress/
|
||||
|
||||
Body:
|
||||
{
|
||||
"content_ids": [1, 2, 3, 4],
|
||||
"site_integration_id": 123, // Optional
|
||||
"force": false // Optional
|
||||
}
|
||||
"""
|
||||
try:
|
||||
content_ids = request.data.get('content_ids', [])
|
||||
site_integration_id = request.data.get('site_integration_id')
|
||||
force = request.data.get('force', False)
|
||||
|
||||
if not content_ids:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'No content IDs provided',
|
||||
'error': 'missing_content_ids'
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Check permissions
|
||||
if not request.user.has_perm('content.change_contentpost'):
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Permission denied',
|
||||
'error': 'insufficient_permissions'
|
||||
},
|
||||
status=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
# Get site integration
|
||||
if site_integration_id:
|
||||
site_integration = get_object_or_404(SiteIntegration, id=site_integration_id)
|
||||
else:
|
||||
site_integration = SiteIntegration.objects.filter(
|
||||
platform='wordpress',
|
||||
is_active=True,
|
||||
).first()
|
||||
|
||||
if not site_integration:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'No WordPress integration found',
|
||||
'error': 'no_integration'
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Validate content items
|
||||
content_items = ContentPost.objects.filter(id__in=content_ids)
|
||||
|
||||
if content_items.count() != len(content_ids):
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Some content items not found',
|
||||
'error': 'content_not_found'
|
||||
},
|
||||
status=status.HTTP_404_NOT_FOUND
|
||||
)
|
||||
|
||||
# Queue bulk publishing task
|
||||
task_result = bulk_publish_content_to_wordpress.delay(
|
||||
content_ids,
|
||||
site_integration.id
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'success': True,
|
||||
'message': f'{len(content_ids)} content items queued for WordPress publishing',
|
||||
'data': {
|
||||
'content_count': len(content_ids),
|
||||
'site_integration_id': site_integration.id,
|
||||
'task_id': task_result.id,
|
||||
'status': 'queued'
|
||||
}
|
||||
},
|
||||
status=status.HTTP_202_ACCEPTED
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': f'Error queuing bulk WordPress publishing: {str(e)}',
|
||||
'error': 'server_error'
|
||||
},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def get_wordpress_status(request, content_id: int) -> Response:
|
||||
"""
|
||||
Get WordPress publishing status for a content item
|
||||
|
||||
GET /api/v1/content/{content_id}/wordpress-status/
|
||||
"""
|
||||
try:
|
||||
content = get_object_or_404(ContentPost, id=content_id)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'success': True,
|
||||
'data': {
|
||||
'content_id': content.id,
|
||||
'wordpress_sync_status': content.wordpress_sync_status,
|
||||
'wordpress_post_id': content.wordpress_post_id,
|
||||
'wordpress_post_url': content.wordpress_post_url,
|
||||
'wordpress_sync_attempts': content.wordpress_sync_attempts,
|
||||
'last_wordpress_sync': content.last_wordpress_sync.isoformat() if content.last_wordpress_sync else None,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': f'Error getting WordPress status: {str(e)}',
|
||||
'error': 'server_error'
|
||||
},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def get_wordpress_integrations(request) -> Response:
|
||||
"""
|
||||
Get available WordPress integrations for publishing
|
||||
|
||||
GET /api/v1/wordpress-integrations/
|
||||
"""
|
||||
try:
|
||||
integrations = SiteIntegration.objects.filter(
|
||||
platform='wordpress',
|
||||
is_active=True,
|
||||
# Add organization filter if applicable
|
||||
).values(
|
||||
'id', 'site_name', 'site_url', 'is_active',
|
||||
'created_at', 'last_sync_at'
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'success': True,
|
||||
'data': list(integrations)
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': f'Error getting WordPress integrations: {str(e)}',
|
||||
'error': 'server_error'
|
||||
},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
|
||||
|
||||
@api_view(['POST'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def retry_failed_wordpress_sync(request, content_id: int) -> Response:
|
||||
"""
|
||||
Retry a failed WordPress sync
|
||||
|
||||
POST /api/v1/content/{content_id}/retry-wordpress-sync/
|
||||
"""
|
||||
try:
|
||||
content = get_object_or_404(ContentPost, id=content_id)
|
||||
|
||||
if content.wordpress_sync_status != 'failed':
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Content is not in failed status',
|
||||
'error': 'invalid_status'
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Get default WordPress integration
|
||||
site_integration = SiteIntegration.objects.filter(
|
||||
platform='wordpress',
|
||||
is_active=True,
|
||||
).first()
|
||||
|
||||
if not site_integration:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'No WordPress integration found',
|
||||
'error': 'no_integration'
|
||||
},
|
||||
status=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
# Reset status and retry
|
||||
content.wordpress_sync_status = 'pending'
|
||||
content.save(update_fields=['wordpress_sync_status'])
|
||||
|
||||
# Get task_id if available
|
||||
task_id = None
|
||||
if hasattr(content, 'writer_task'):
|
||||
task_id = content.writer_task.id
|
||||
|
||||
# Queue the publishing task
|
||||
task_result = publish_content_to_wordpress.delay(
|
||||
content.id,
|
||||
site_integration.id,
|
||||
task_id
|
||||
)
|
||||
|
||||
return Response(
|
||||
{
|
||||
'success': True,
|
||||
'message': 'WordPress sync retry queued',
|
||||
'data': {
|
||||
'content_id': content.id,
|
||||
'task_id': task_result.id,
|
||||
'status': 'queued'
|
||||
}
|
||||
},
|
||||
status=status.HTTP_202_ACCEPTED
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': f'Error retrying WordPress sync: {str(e)}',
|
||||
'error': 'server_error'
|
||||
},
|
||||
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||
)
|
||||
Reference in New Issue
Block a user