from rest_framework import serializers from django.db import models from django.core.exceptions import ObjectDoesNotExist from .models import Tasks, Images, Content from igny8_core.business.planning.models import Clusters, ContentIdeas class TasksSerializer(serializers.ModelSerializer): """Serializer for Tasks model""" cluster_name = serializers.SerializerMethodField() sector_name = serializers.SerializerMethodField() idea_title = serializers.SerializerMethodField() site_id = serializers.IntegerField(write_only=True, required=False) sector_id = serializers.IntegerField(write_only=True, required=False) content_html = serializers.SerializerMethodField() content_primary_keyword = serializers.SerializerMethodField() content_secondary_keywords = serializers.SerializerMethodField() content_tags = serializers.SerializerMethodField() content_categories = serializers.SerializerMethodField() class Meta: model = Tasks fields = [ 'id', 'title', 'description', 'keywords', 'cluster_id', 'cluster_name', 'sector_name', 'idea_id', 'idea_title', 'content_structure', 'content_type', 'status', 'content', 'word_count', 'meta_title', 'meta_description', 'content_html', 'content_primary_keyword', 'content_secondary_keywords', 'content_tags', 'content_categories', 'assigned_post_id', 'post_url', 'created_at', 'updated_at', 'site_id', 'sector_id', 'account_id', ] read_only_fields = ['id', 'created_at', 'updated_at', 'account_id'] def get_cluster_name(self, obj): """Get cluster name from Clusters model""" if obj.cluster_id: try: cluster = Clusters.objects.get(id=obj.cluster_id) return cluster.name except Clusters.DoesNotExist: return None return None def get_sector_name(self, obj): """Get sector name from Sector model""" if obj.sector_id: try: from igny8_core.auth.models import Sector sector = Sector.objects.get(id=obj.sector_id) return sector.name except Sector.DoesNotExist: return None return None def get_idea_title(self, obj): """Get idea title from ContentIdeas model""" if obj.idea_id: try: idea = ContentIdeas.objects.get(id=obj.idea_id) return idea.idea_title except ContentIdeas.DoesNotExist: return None return None def _get_content_record(self, obj): try: return obj.content_record except (AttributeError, ObjectDoesNotExist): return None def get_content_html(self, obj): record = self._get_content_record(obj) return record.html_content if record else None def get_content_primary_keyword(self, obj): record = self._get_content_record(obj) return record.primary_keyword if record else None def get_content_secondary_keywords(self, obj): record = self._get_content_record(obj) return record.secondary_keywords if record else [] def get_content_tags(self, obj): record = self._get_content_record(obj) return record.tags if record else [] def get_content_categories(self, obj): record = self._get_content_record(obj) return record.categories if record else [] class ImagesSerializer(serializers.ModelSerializer): """Serializer for Images model""" task_title = serializers.SerializerMethodField() content_title = serializers.SerializerMethodField() class Meta: model = Images fields = [ 'id', 'task_id', 'task_title', 'content_id', 'content_title', 'image_type', 'image_url', 'image_path', 'prompt', 'status', 'position', 'created_at', 'updated_at', 'account_id', ] read_only_fields = ['id', 'created_at', 'updated_at', 'account_id'] def get_task_title(self, obj): """Get task title""" if obj.task_id: try: task = Tasks.objects.get(id=obj.task_id) return task.title except Tasks.DoesNotExist: return None return None def get_content_title(self, obj): """Get content title""" if obj.content: return obj.content.title or obj.content.meta_title return None class ContentImageSerializer(serializers.ModelSerializer): """Serializer for individual image in grouped content images""" image_url = serializers.SerializerMethodField() class Meta: model = Images fields = [ 'id', 'image_type', 'image_url', 'image_path', 'prompt', 'status', 'position', 'created_at', 'updated_at', ] def get_image_url(self, obj): """ Return original image_url from database (Runware/OpenAI URL). No transformation - returns the exact value stored in image_url field. """ return obj.image_url class ContentImagesGroupSerializer(serializers.Serializer): """Serializer for grouped content images - one row per content""" content_id = serializers.IntegerField() content_title = serializers.CharField() featured_image = ContentImageSerializer(allow_null=True) in_article_images = ContentImageSerializer(many=True) overall_status = serializers.CharField() # 'pending', 'partial', 'complete', 'failed' class ContentSerializer(serializers.ModelSerializer): """Serializer for Content model""" task_title = serializers.SerializerMethodField() sector_name = serializers.SerializerMethodField() has_image_prompts = serializers.SerializerMethodField() has_generated_images = serializers.SerializerMethodField() class Meta: model = Content fields = [ 'id', 'task_id', 'task_title', 'sector_name', 'html_content', 'word_count', 'metadata', 'title', 'meta_title', 'meta_description', 'primary_keyword', 'secondary_keywords', 'tags', 'categories', 'status', 'generated_at', 'updated_at', 'account_id', 'has_image_prompts', 'has_generated_images', # Phase 8: Universal Content Types 'entity_type', 'json_blocks', 'structure_data', ] read_only_fields = ['id', 'generated_at', 'updated_at', 'account_id'] def get_task_title(self, obj): """Get task title""" if obj.task_id: try: task = Tasks.objects.get(id=obj.task_id) return task.title except Tasks.DoesNotExist: return None return None def get_sector_name(self, obj): """Get sector name from Sector model""" if obj.sector_id: try: from igny8_core.auth.models import Sector sector = Sector.objects.get(id=obj.sector_id) return sector.name except Sector.DoesNotExist: return None return None def get_has_image_prompts(self, obj): """Check if content has any image prompts generated""" # Check if any images exist with prompts for this content return Images.objects.filter( models.Q(content=obj) | models.Q(task=obj.task) ).exclude(prompt__isnull=True).exclude(prompt='').exists() def get_has_generated_images(self, obj): """Check if content has any generated images (status='generated' and has URL)""" # Check if any images are generated (have status='generated' and image_url) return Images.objects.filter( models.Q(content=obj) | models.Q(task=obj.task), status='generated', image_url__isnull=False ).exclude(image_url='').exists()