Phase 1-3 Implemented - PUBLISHING-PROGRESS-AND-SCHEDULING-UX-PLAN
This commit is contained in:
@@ -1589,6 +1589,207 @@ class ContentViewSet(SiteSectorModelViewSet):
|
||||
request=request
|
||||
)
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='bulk_schedule_preview', url_name='bulk_schedule_preview', permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove])
|
||||
def bulk_schedule_preview(self, request):
|
||||
"""
|
||||
Preview bulk scheduling with site default settings.
|
||||
Shows what the schedule would look like before confirming.
|
||||
|
||||
POST /api/v1/writer/content/bulk_schedule_preview/
|
||||
{
|
||||
"content_ids": [123, 124, 125],
|
||||
"site_id": 45
|
||||
}
|
||||
"""
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from igny8_core.business.integration.models import Site, SitePublishingSettings
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
content_ids = request.data.get('content_ids', [])
|
||||
site_id = request.data.get('site_id')
|
||||
|
||||
if not content_ids:
|
||||
return error_response(
|
||||
error='content_ids is required',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
if not site_id:
|
||||
return error_response(
|
||||
error='site_id is required',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
# Get site and publishing settings
|
||||
try:
|
||||
site = Site.objects.get(id=site_id)
|
||||
pub_settings = SitePublishingSettings.objects.filter(site=site).first()
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
error=f'Site {site_id} not found',
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
request=request
|
||||
)
|
||||
|
||||
# Default settings if none exist
|
||||
base_time_str = '09:00 AM'
|
||||
stagger_interval = 15 # minutes
|
||||
timezone_str = 'America/New_York'
|
||||
|
||||
if pub_settings:
|
||||
base_time_str = pub_settings.auto_publish_time or base_time_str
|
||||
stagger_interval = pub_settings.stagger_interval_minutes or stagger_interval
|
||||
timezone_str = pub_settings.timezone or timezone_str
|
||||
|
||||
# Get content items
|
||||
content_qs = self.get_queryset().filter(id__in=content_ids)
|
||||
|
||||
# Generate schedule preview
|
||||
schedule_preview = []
|
||||
now = timezone.now()
|
||||
|
||||
# Parse base time (format: "09:00 AM" or "14:30")
|
||||
try:
|
||||
from datetime import datetime
|
||||
if 'AM' in base_time_str or 'PM' in base_time_str:
|
||||
time_obj = datetime.strptime(base_time_str, '%I:%M %p').time()
|
||||
else:
|
||||
time_obj = datetime.strptime(base_time_str, '%H:%M').time()
|
||||
except ValueError:
|
||||
time_obj = datetime.strptime('09:00', '%H:%M').time()
|
||||
|
||||
# Start from tomorrow at base time
|
||||
start_date = now.replace(hour=time_obj.hour, minute=time_obj.minute, second=0, microsecond=0)
|
||||
if start_date <= now:
|
||||
start_date += timedelta(days=1)
|
||||
|
||||
# Create schedule for each content item
|
||||
for index, content in enumerate(content_qs):
|
||||
scheduled_at = start_date + timedelta(minutes=stagger_interval * index)
|
||||
schedule_preview.append({
|
||||
'content_id': content.id,
|
||||
'title': content.title,
|
||||
'scheduled_at': scheduled_at.isoformat(),
|
||||
})
|
||||
|
||||
logger.info(f"[bulk_schedule_preview] Generated preview for {len(schedule_preview)} items")
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
'scheduled_count': len(schedule_preview),
|
||||
'schedule_preview': schedule_preview,
|
||||
'site_settings': {
|
||||
'base_time': base_time_str,
|
||||
'stagger_interval': stagger_interval,
|
||||
'timezone': timezone_str,
|
||||
},
|
||||
},
|
||||
message=f'Preview generated for {len(schedule_preview)} items',
|
||||
request=request
|
||||
)
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='bulk_schedule', url_name='bulk_schedule', permission_classes=[IsAuthenticatedAndActive, IsEditorOrAbove])
|
||||
def bulk_schedule(self, request):
|
||||
"""
|
||||
Bulk schedule multiple content items using site default settings.
|
||||
|
||||
POST /api/v1/writer/content/bulk_schedule/
|
||||
{
|
||||
"content_ids": [123, 124, 125],
|
||||
"use_site_defaults": true,
|
||||
"site_id": 45
|
||||
}
|
||||
"""
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from igny8_core.business.integration.models import Site, SitePublishingSettings
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
content_ids = request.data.get('content_ids', [])
|
||||
use_site_defaults = request.data.get('use_site_defaults', True)
|
||||
site_id = request.data.get('site_id')
|
||||
|
||||
if not content_ids:
|
||||
return error_response(
|
||||
error='content_ids is required',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
if not site_id:
|
||||
return error_response(
|
||||
error='site_id is required',
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
request=request
|
||||
)
|
||||
|
||||
# Get site and publishing settings
|
||||
try:
|
||||
site = Site.objects.get(id=site_id)
|
||||
pub_settings = SitePublishingSettings.objects.filter(site=site).first()
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
error=f'Site {site_id} not found',
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
request=request
|
||||
)
|
||||
|
||||
# Default settings if none exist
|
||||
base_time_str = '09:00 AM'
|
||||
stagger_interval = 15 # minutes
|
||||
|
||||
if pub_settings and use_site_defaults:
|
||||
base_time_str = pub_settings.auto_publish_time or base_time_str
|
||||
stagger_interval = pub_settings.stagger_interval_minutes or stagger_interval
|
||||
|
||||
# Get content items
|
||||
content_qs = self.get_queryset().filter(id__in=content_ids)
|
||||
|
||||
# Generate schedule and apply
|
||||
now = timezone.now()
|
||||
|
||||
# Parse base time
|
||||
try:
|
||||
from datetime import datetime
|
||||
if 'AM' in base_time_str or 'PM' in base_time_str:
|
||||
time_obj = datetime.strptime(base_time_str, '%I:%M %p').time()
|
||||
else:
|
||||
time_obj = datetime.strptime(base_time_str, '%H:%M').time()
|
||||
except ValueError:
|
||||
time_obj = datetime.strptime('09:00', '%H:%M').time()
|
||||
|
||||
# Start from tomorrow at base time
|
||||
start_date = now.replace(hour=time_obj.hour, minute=time_obj.minute, second=0, microsecond=0)
|
||||
if start_date <= now:
|
||||
start_date += timedelta(days=1)
|
||||
|
||||
# Schedule each content item
|
||||
scheduled_count = 0
|
||||
for index, content in enumerate(content_qs):
|
||||
scheduled_at = start_date + timedelta(minutes=stagger_interval * index)
|
||||
content.site_status = 'scheduled'
|
||||
content.scheduled_publish_at = scheduled_at
|
||||
content.site_status_updated_at = now
|
||||
content.save(update_fields=['site_status', 'scheduled_publish_at', 'site_status_updated_at', 'updated_at'])
|
||||
scheduled_count += 1
|
||||
|
||||
logger.info(f"[bulk_schedule] Scheduled {scheduled_count} content items")
|
||||
|
||||
return success_response(
|
||||
data={
|
||||
'scheduled_count': scheduled_count,
|
||||
},
|
||||
message=f'Successfully scheduled {scheduled_count} items',
|
||||
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