igny8-wp int

This commit is contained in:
alorig
2025-11-30 18:35:46 +05:00
parent 1c939acad5
commit 87fdbce0e9
2 changed files with 156 additions and 8 deletions

View File

@@ -818,6 +818,11 @@ class ContentViewSet(SiteSectorModelViewSet):
request=request
)
# OPTIMISTIC UPDATE: Set status to published immediately for better UX
# The Celery task will update external_id and external_url when WordPress responds
content.status = 'published'
content.save(update_fields=['status', 'updated_at'])
# Queue publishing task (same as automated flow)
try:
result = publish_content_to_wordpress.delay(
@@ -825,28 +830,123 @@ class ContentViewSet(SiteSectorModelViewSet):
site_integration_id=site_integration.id
)
logger.info(f"[ContentViewSet.publish] Queued Celery task {result.id} for content {content.id}")
logger.info(f"[ContentViewSet.publish] Queued Celery task {result.id} for content {content.id}, status set to 'published'")
return success_response(
data={
'content_id': content.id,
'task_id': result.id,
'status': 'queued',
'status': 'published',
'message': 'Publishing queued - content will be published to WordPress shortly'
},
message='Content publishing queued successfully',
message='Content status updated to published and queued for WordPress',
request=request,
status_code=status.HTTP_202_ACCEPTED
)
except Exception as e:
logger.error(f"[ContentViewSet.publish] Error queuing publish task: {str(e)}", exc_info=True)
# Revert status on error
content.status = 'review'
content.save(update_fields=['status', 'updated_at'])
return error_response(
error=f"Failed to queue publishing task: {str(e)}",
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
request=request
)
@action(detail=True, methods=['get'], url_path='wordpress_status', url_name='wordpress_status')
def wordpress_status(self, request, pk=None):
"""
Get WordPress post status for published content.
Calls WordPress REST API to get current status.
GET /api/v1/writer/content/{id}/wordpress_status/
Returns: {
'wordpress_status': 'publish'|'draft'|'pending'|null,
'external_id': 123,
'external_url': 'https://...',
'last_checked': '2025-11-30T...'
}
"""
import requests
from django.utils import timezone
from igny8_core.business.integration.models import SiteIntegration
import logging
logger = logging.getLogger(__name__)
content = self.get_object()
if not content.external_id:
return success_response(
data={
'wordpress_status': None,
'external_id': None,
'external_url': None,
'message': 'Content not published to WordPress yet'
},
request=request
)
# Get WordPress integration for this content's site
try:
site_integration = SiteIntegration.objects.filter(
site=content.site,
platform='wordpress',
is_active=True
).first()
if not site_integration:
return error_response(
error='No active WordPress integration found',
status_code=status.HTTP_404_NOT_FOUND,
request=request
)
# Call WordPress REST API to get post status
wordpress_url = f"{site_integration.site_url}/wp-json/igny8/v1/post-status/{content.external_id}/"
headers = {
'X-IGNY8-API-KEY': site_integration.api_key,
}
response = requests.get(wordpress_url, headers=headers, timeout=10)
if response.status_code == 200:
wp_data = response.json().get('data', {})
return success_response(
data={
'wordpress_status': wp_data.get('post_status'),
'external_id': content.external_id,
'external_url': content.external_url,
'post_title': wp_data.get('post_title'),
'post_modified': wp_data.get('post_modified'),
'last_checked': timezone.now().isoformat()
},
request=request
)
else:
logger.error(f"WordPress API error: {response.status_code} - {response.text}")
return error_response(
error=f'Failed to get WordPress status: {response.status_code}',
status_code=status.HTTP_502_BAD_GATEWAY,
request=request
)
except requests.RequestException as e:
logger.error(f"Request to WordPress failed: {str(e)}")
return error_response(
error=f'Connection to WordPress failed: {str(e)}',
status_code=status.HTTP_502_BAD_GATEWAY,
request=request
)
except Exception as e:
logger.error(f"Error getting WordPress status: {str(e)}", exc_info=True)
return error_response(
error=str(e),
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
request=request
)
@action(detail=True, methods=['post'], url_path='unpublish', url_name='unpublish', permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove])
def unpublish(self, request, pk=None):
"""

View File

@@ -58,6 +58,51 @@ def publish_content_to_wordpress(self, content_id: int, site_integration_id: int
if len(content.content_html) > 150:
excerpt += '...'
# Get taxonomy terms from ContentTaxonomyMap
from igny8_core.business.content.models import ContentTaxonomyMap
taxonomy_maps = ContentTaxonomyMap.objects.filter(content=content).select_related('taxonomy')
# Build categories and tags arrays from taxonomy mappings
categories = []
tags = []
for mapping in taxonomy_maps:
tax = mapping.taxonomy
if tax:
# Add taxonomy term name to categories (will be mapped in WordPress)
categories.append(tax.name)
# Get images from Images model
from igny8_core.modules.writer.models import Images
featured_image_url = None
gallery_images = []
images = Images.objects.filter(content=content).order_by('position')
for image in images:
if image.image_type == 'featured' and image.image_url:
featured_image_url = image.image_url
elif image.image_type == 'in_article' and image.image_url:
gallery_images.append({
'url': image.image_url,
'alt': image.alt_text or '',
'position': image.position
})
# Add primary and secondary keywords as tags
if content.primary_keyword:
tags.append(content.primary_keyword)
if content.secondary_keywords:
if isinstance(content.secondary_keywords, list):
tags.extend(content.secondary_keywords)
elif isinstance(content.secondary_keywords, str):
import json
try:
keywords = json.loads(content.secondary_keywords)
if isinstance(keywords, list):
tags.extend(keywords)
except (json.JSONDecodeError, TypeError):
pass
content_data = {
'content_id': content.id,
'task_id': task_id,
@@ -75,15 +120,18 @@ def publish_content_to_wordpress(self, content_id: int, site_integration_id: int
'seo_description': content.meta_description or '',
'primary_keyword': content.primary_keyword or '',
'secondary_keywords': content.secondary_keywords or [],
# Content model has no featured_image field
'featured_image_url': None,
# Send featured image URL from Images model
'featured_image_url': featured_image_url,
'gallery_images': gallery_images,
# Send cluster and sector IDs (Content has ForeignKey to cluster, not many-to-many)
'cluster_id': content.cluster.id if content.cluster else None,
'sector_id': content.sector.id if content.sector else None,
# Content model has no direct sectors/clusters array or tags
# Send categories and tags from taxonomy mappings and keywords
'categories': categories,
'tags': tags,
# Keep for backward compatibility
'sectors': [],
'clusters': [],
'tags': []
'clusters': []
}
# Call WordPress REST API