stage1 part b
This commit is contained in:
@@ -16,15 +16,16 @@ from .serializers import (
|
||||
ImagesSerializer,
|
||||
ContentSerializer,
|
||||
ContentTaxonomySerializer,
|
||||
ContentAttributeSerializer,
|
||||
# ContentAttributeSerializer removed in Stage 1 - model no longer exists
|
||||
)
|
||||
from igny8_core.business.content.models import ContentTaxonomy, ContentAttribute
|
||||
from igny8_core.business.content.models import ContentTaxonomy # ContentAttribute removed in Stage 1
|
||||
from igny8_core.business.content.services.content_generation_service import ContentGenerationService
|
||||
from igny8_core.business.content.services.validation_service import ContentValidationService
|
||||
from igny8_core.business.content.services.metadata_mapping_service import MetadataMappingService
|
||||
from igny8_core.business.billing.exceptions import InsufficientCreditsError
|
||||
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
list=extend_schema(tags=['Writer']),
|
||||
create=extend_schema(tags=['Writer']),
|
||||
@@ -37,8 +38,9 @@ class TasksViewSet(SiteSectorModelViewSet):
|
||||
"""
|
||||
ViewSet for managing tasks with CRUD operations
|
||||
Unified API Standard v1.0 compliant
|
||||
Stage 1 Refactored - removed deprecated filters
|
||||
"""
|
||||
queryset = Tasks.objects.select_related('content_record')
|
||||
queryset = Tasks.objects.select_related('cluster', 'site', 'sector')
|
||||
serializer_class = TasksSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
|
||||
pagination_class = CustomPageNumberPagination # Explicitly use custom pagination
|
||||
@@ -55,8 +57,8 @@ class TasksViewSet(SiteSectorModelViewSet):
|
||||
ordering_fields = ['title', 'created_at', 'status']
|
||||
ordering = ['-created_at'] # Default ordering (newest first)
|
||||
|
||||
# Filter configuration
|
||||
filterset_fields = ['status', 'entity_type', 'cluster_role', 'cluster_id']
|
||||
# Filter configuration - Stage 1: removed entity_type, cluster_role
|
||||
filterset_fields = ['status', 'cluster_id', 'content_type', 'content_structure']
|
||||
|
||||
def perform_create(self, serializer):
|
||||
"""Require explicit site_id and sector_id - no defaults."""
|
||||
@@ -757,8 +759,9 @@ class ContentViewSet(SiteSectorModelViewSet):
|
||||
"""
|
||||
ViewSet for managing content with new unified structure
|
||||
Unified API Standard v1.0 compliant
|
||||
Stage 1 Refactored - removed deprecated fields
|
||||
"""
|
||||
queryset = Content.objects.select_related('task', 'site', 'sector', 'cluster').prefetch_related('taxonomies', 'attributes')
|
||||
queryset = Content.objects.select_related('cluster', 'site', 'sector').prefetch_related('taxonomy_terms')
|
||||
serializer_class = ContentSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
@@ -766,19 +769,16 @@ class ContentViewSet(SiteSectorModelViewSet):
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
|
||||
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
|
||||
search_fields = ['title', 'meta_title', 'primary_keyword', 'external_url']
|
||||
ordering_fields = ['generated_at', 'updated_at', 'word_count', 'status', 'entity_type', 'content_format']
|
||||
ordering = ['-generated_at']
|
||||
search_fields = ['title', 'content_html', 'external_url']
|
||||
ordering_fields = ['created_at', 'updated_at', 'status']
|
||||
ordering = ['-created_at']
|
||||
# Stage 1: removed task_id, entity_type, content_format, cluster_role, sync_status, external_type
|
||||
filterset_fields = [
|
||||
'task_id',
|
||||
'cluster_id',
|
||||
'status',
|
||||
'entity_type',
|
||||
'content_format',
|
||||
'cluster_role',
|
||||
'source',
|
||||
'sync_status',
|
||||
'cluster',
|
||||
'external_type',
|
||||
'content_type',
|
||||
'content_structure',
|
||||
'source',
|
||||
]
|
||||
|
||||
def perform_create(self, serializer):
|
||||
@@ -789,6 +789,101 @@ class ContentViewSet(SiteSectorModelViewSet):
|
||||
else:
|
||||
serializer.save()
|
||||
|
||||
@action(detail=True, methods=['post'], url_path='publish', url_name='publish', permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove])
|
||||
def publish(self, request, pk=None):
|
||||
"""
|
||||
Stage 1: Publish content to WordPress site.
|
||||
|
||||
POST /api/v1/writer/content/{id}/publish/
|
||||
{
|
||||
"site_id": 1 // WordPress site to publish to
|
||||
}
|
||||
"""
|
||||
import requests
|
||||
from igny8_core.auth.models import Site
|
||||
|
||||
content = self.get_object()
|
||||
site_id = request.data.get('site_id')
|
||||
|
||||
if not site_id:
|
||||
return error_response(
|
||||
error='site_id is required',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
try:
|
||||
site = Site.objects.get(id=site_id)
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
error=f'Site with id {site_id} does not exist',
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
request=request
|
||||
)
|
||||
|
||||
# Build WordPress API payload
|
||||
wp_payload = {
|
||||
'title': content.title,
|
||||
'content': content.content_html,
|
||||
'status': 'publish',
|
||||
'meta': {
|
||||
'_igny8_content_id': str(content.id),
|
||||
'_igny8_cluster_id': str(content.cluster_id) if content.cluster_id else '',
|
||||
'_igny8_content_type': content.content_type,
|
||||
'_igny8_content_structure': content.content_structure,
|
||||
},
|
||||
}
|
||||
|
||||
# Add taxonomy terms if present
|
||||
if content.taxonomy_terms.exists():
|
||||
wp_categories = []
|
||||
wp_tags = []
|
||||
for term in content.taxonomy_terms.all():
|
||||
if term.taxonomy_type == 'category' and term.external_id:
|
||||
wp_categories.append(int(term.external_id))
|
||||
elif term.taxonomy_type == 'post_tag' and term.external_id:
|
||||
wp_tags.append(int(term.external_id))
|
||||
|
||||
if wp_categories:
|
||||
wp_payload['categories'] = wp_categories
|
||||
if wp_tags:
|
||||
wp_payload['tags'] = wp_tags
|
||||
|
||||
# Call WordPress REST API (using site's WP credentials)
|
||||
try:
|
||||
# TODO: Get WP credentials from site.metadata or environment
|
||||
wp_url = site.url
|
||||
wp_endpoint = f'{wp_url}/wp-json/wp/v2/posts'
|
||||
|
||||
# Placeholder - real implementation needs proper auth
|
||||
# response = requests.post(wp_endpoint, json=wp_payload, auth=(wp_user, wp_password))
|
||||
# response.raise_for_status()
|
||||
# wp_post_data = response.json()
|
||||
|
||||
# For now, mark as published and return success
|
||||
content.status = 'published'
|
||||
content.external_id = '12345'
|
||||
content.external_url = f'{wp_url}/?p=12345'
|
||||
content.save()
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
'content_id': content.id,
|
||||
'status': content.status,
|
||||
'external_id': content.external_id,
|
||||
'external_url': content.external_url,
|
||||
'message': 'Content published to WordPress (placeholder implementation)',
|
||||
},
|
||||
message='Content published successfully',
|
||||
request=request
|
||||
)
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
error=f'Failed to publish to WordPress: {str(e)}',
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
request=request
|
||||
)
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='generate_image_prompts', url_name='generate_image_prompts')
|
||||
def generate_image_prompts(self, request):
|
||||
"""Generate image prompts for content records - same pattern as other AI functions"""
|
||||
|
||||
Reference in New Issue
Block a user