stage 4-2
This commit is contained in:
@@ -13,6 +13,8 @@ from igny8_core.api.throttles import DebugScopedRateThrottle
|
||||
from igny8_core.business.integration.models import SiteIntegration
|
||||
from igny8_core.business.integration.services.integration_service import IntegrationService
|
||||
from igny8_core.business.integration.services.sync_service import SyncService
|
||||
from igny8_core.business.integration.services.sync_health_service import SyncHealthService
|
||||
from igny8_core.business.integration.services.content_sync_service import ContentSyncService
|
||||
|
||||
|
||||
class IntegrationViewSet(SiteSectorModelViewSet):
|
||||
@@ -93,4 +95,193 @@ class IntegrationViewSet(SiteSectorModelViewSet):
|
||||
status_data = sync_service.get_sync_status(integration)
|
||||
|
||||
return success_response(status_data, request=request)
|
||||
|
||||
# Stage 4: Site-level sync endpoints
|
||||
|
||||
@action(detail=False, methods=['get'], url_path='sites/(?P<site_id>[^/.]+)/sync/status')
|
||||
def sync_status_by_site(self, request, site_id=None):
|
||||
"""
|
||||
Get sync status for all integrations on a site.
|
||||
Stage 4: Site-level sync health endpoint.
|
||||
|
||||
GET /api/v1/integration/integrations/sites/{site_id}/sync/status/
|
||||
"""
|
||||
try:
|
||||
site_id_int = int(site_id)
|
||||
except (ValueError, TypeError):
|
||||
return error_response(
|
||||
'Invalid site_id',
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
request
|
||||
)
|
||||
|
||||
# Verify site belongs to user's account
|
||||
from igny8_core.auth.models import Site
|
||||
try:
|
||||
site = Site.objects.get(id=site_id_int, account=request.user.account)
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
'Site not found',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
sync_health_service = SyncHealthService()
|
||||
status_data = sync_health_service.get_sync_status(site_id_int)
|
||||
|
||||
return success_response(status_data, request=request)
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='sites/(?P<site_id>[^/.]+)/sync/run')
|
||||
def run_sync(self, request, site_id=None):
|
||||
"""
|
||||
Trigger sync for all integrations on a site.
|
||||
Stage 4: Site-level sync trigger endpoint.
|
||||
|
||||
POST /api/v1/integration/integrations/sites/{site_id}/sync/run/
|
||||
|
||||
Request body:
|
||||
{
|
||||
"direction": "both", # Optional: 'both', 'to_external', 'from_external'
|
||||
"content_types": ["blog_post", "product"] # Optional
|
||||
}
|
||||
"""
|
||||
try:
|
||||
site_id_int = int(site_id)
|
||||
except (ValueError, TypeError):
|
||||
return error_response(
|
||||
'Invalid site_id',
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
request
|
||||
)
|
||||
|
||||
# Verify site belongs to user's account
|
||||
from igny8_core.auth.models import Site
|
||||
try:
|
||||
site = Site.objects.get(id=site_id_int, account=request.user.account)
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
'Site not found',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
direction = request.data.get('direction', 'both')
|
||||
content_types = request.data.get('content_types')
|
||||
|
||||
# Get all active integrations for this site
|
||||
integrations = SiteIntegration.objects.filter(
|
||||
site_id=site_id_int,
|
||||
is_active=True,
|
||||
sync_enabled=True
|
||||
)
|
||||
|
||||
if not integrations.exists():
|
||||
return error_response(
|
||||
'No active integrations found for this site',
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
request
|
||||
)
|
||||
|
||||
sync_service = SyncService()
|
||||
sync_health_service = SyncHealthService()
|
||||
results = []
|
||||
|
||||
for integration in integrations:
|
||||
result = sync_service.sync(integration, direction=direction, content_types=content_types)
|
||||
|
||||
# Record sync run
|
||||
sync_health_service.record_sync_run(integration.id, result)
|
||||
|
||||
results.append({
|
||||
'integration_id': integration.id,
|
||||
'platform': integration.platform,
|
||||
'result': result
|
||||
})
|
||||
|
||||
return success_response({
|
||||
'site_id': site_id_int,
|
||||
'sync_results': results,
|
||||
'total_integrations': len(results)
|
||||
}, request=request)
|
||||
|
||||
@action(detail=False, methods=['get'], url_path='sites/(?P<site_id>[^/.]+)/sync/mismatches')
|
||||
def get_mismatches(self, request, site_id=None):
|
||||
"""
|
||||
Get sync mismatches for a site.
|
||||
Stage 4: Detailed mismatch information.
|
||||
|
||||
GET /api/v1/integration/integrations/sites/{site_id}/sync/mismatches/
|
||||
"""
|
||||
try:
|
||||
site_id_int = int(site_id)
|
||||
except (ValueError, TypeError):
|
||||
return error_response(
|
||||
'Invalid site_id',
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
request
|
||||
)
|
||||
|
||||
# Verify site belongs to user's account
|
||||
from igny8_core.auth.models import Site
|
||||
try:
|
||||
site = Site.objects.get(id=site_id_int, account=request.user.account)
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
'Site not found',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
sync_health_service = SyncHealthService()
|
||||
mismatches = sync_health_service.get_mismatches(site_id_int)
|
||||
|
||||
return success_response(mismatches, request=request)
|
||||
|
||||
@action(detail=False, methods=['get'], url_path='sites/(?P<site_id>[^/.]+)/sync/logs')
|
||||
def get_sync_logs(self, request, site_id=None):
|
||||
"""
|
||||
Get sync logs for a site.
|
||||
Stage 4: Sync history and logs.
|
||||
|
||||
GET /api/v1/integration/integrations/sites/{site_id}/sync/logs/
|
||||
|
||||
Query params:
|
||||
- limit: Number of logs to return (default: 100)
|
||||
- integration_id: Filter by specific integration
|
||||
"""
|
||||
try:
|
||||
site_id_int = int(site_id)
|
||||
except (ValueError, TypeError):
|
||||
return error_response(
|
||||
'Invalid site_id',
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
request
|
||||
)
|
||||
|
||||
# Verify site belongs to user's account
|
||||
from igny8_core.auth.models import Site
|
||||
try:
|
||||
site = Site.objects.get(id=site_id_int, account=request.user.account)
|
||||
except Site.DoesNotExist:
|
||||
return error_response(
|
||||
'Site not found',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
limit = int(request.query_params.get('limit', 100))
|
||||
integration_id = request.query_params.get('integration_id')
|
||||
|
||||
sync_health_service = SyncHealthService()
|
||||
logs = sync_health_service.get_sync_logs(
|
||||
site_id_int,
|
||||
integration_id=int(integration_id) if integration_id else None,
|
||||
limit=limit
|
||||
)
|
||||
|
||||
return success_response({
|
||||
'site_id': site_id_int,
|
||||
'logs': logs,
|
||||
'count': len(logs)
|
||||
}, request=request)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ from igny8_core.api.response import success_response, error_response
|
||||
from igny8_core.api.throttles import DebugScopedRateThrottle
|
||||
from igny8_core.business.publishing.models import PublishingRecord, DeploymentRecord
|
||||
from igny8_core.business.publishing.services.publisher_service import PublisherService
|
||||
from igny8_core.business.publishing.services.deployment_readiness_service import DeploymentReadinessService
|
||||
from igny8_core.business.site_building.models import SiteBlueprint
|
||||
|
||||
|
||||
@@ -74,6 +75,7 @@ class PublisherViewSet(viewsets.ViewSet):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.publisher_service = PublisherService()
|
||||
self.readiness_service = DeploymentReadinessService()
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='publish')
|
||||
def publish(self, request):
|
||||
@@ -137,12 +139,13 @@ class PublisherViewSet(viewsets.ViewSet):
|
||||
request
|
||||
)
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='deploy/(?P<blueprint_id>[^/.]+)')
|
||||
def deploy(self, request, blueprint_id):
|
||||
@action(detail=False, methods=['get'], url_path='blueprints/(?P<blueprint_id>[^/.]+)/readiness')
|
||||
def deployment_readiness(self, request, blueprint_id):
|
||||
"""
|
||||
Deploy site blueprint to Sites renderer.
|
||||
Check deployment readiness for a site blueprint.
|
||||
Stage 4: Pre-deployment validation checks.
|
||||
|
||||
POST /api/v1/publisher/deploy/{blueprint_id}/
|
||||
GET /api/v1/publisher/blueprints/{blueprint_id}/readiness/
|
||||
"""
|
||||
account = request.account
|
||||
|
||||
@@ -155,6 +158,48 @@ class PublisherViewSet(viewsets.ViewSet):
|
||||
request
|
||||
)
|
||||
|
||||
readiness = self.readiness_service.check_readiness(blueprint_id)
|
||||
|
||||
return success_response(readiness, request=request)
|
||||
|
||||
@action(detail=False, methods=['post'], url_path='deploy/(?P<blueprint_id>[^/.]+)')
|
||||
def deploy(self, request, blueprint_id):
|
||||
"""
|
||||
Deploy site blueprint to Sites renderer.
|
||||
Stage 4: Enhanced with readiness check (optional).
|
||||
|
||||
POST /api/v1/publisher/deploy/{blueprint_id}/
|
||||
|
||||
Request body (optional):
|
||||
{
|
||||
"skip_readiness_check": false # Set to true to skip readiness validation
|
||||
}
|
||||
"""
|
||||
account = request.account
|
||||
|
||||
try:
|
||||
blueprint = SiteBlueprint.objects.get(id=blueprint_id, account=account)
|
||||
except SiteBlueprint.DoesNotExist:
|
||||
return error_response(
|
||||
f'Site blueprint {blueprint_id} not found',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
# Stage 4: Optional readiness check
|
||||
skip_check = request.data.get('skip_readiness_check', False)
|
||||
if not skip_check:
|
||||
readiness = self.readiness_service.check_readiness(blueprint_id)
|
||||
if not readiness.get('ready'):
|
||||
return error_response(
|
||||
{
|
||||
'message': 'Site is not ready for deployment',
|
||||
'readiness': readiness
|
||||
},
|
||||
status.HTTP_400_BAD_REQUEST,
|
||||
request
|
||||
)
|
||||
|
||||
result = self.publisher_service.publish_to_sites(blueprint)
|
||||
|
||||
response_status = status.HTTP_202_ACCEPTED if result.get('success') else status.HTTP_400_BAD_REQUEST
|
||||
|
||||
Reference in New Issue
Block a user