stage 4-2

This commit is contained in:
alorig
2025-11-20 04:00:51 +05:00
parent ec3ca2da5d
commit 584dce7b8e
13 changed files with 2424 additions and 15 deletions

View File

@@ -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)

View File

@@ -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