- Introduced a new scheduled task for executing automation rules every 5 minutes in the Celery beat schedule. - Updated URL routing to include a new endpoint for automation-related functionalities. - Refactored imports in various modules to align with the new business layer structure, ensuring backward compatibility for billing models, exceptions, and services.
259 lines
8.3 KiB
Python
259 lines
8.3 KiB
Python
from rest_framework import serializers
|
|
from django.db import models
|
|
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:
|
|
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',
|
|
]
|
|
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()
|
|
|