Add Sites Renderer service to Docker Compose and implement public endpoint for site definitions
- Introduced `igny8_sites` service in `docker-compose.app.yml` for serving deployed public sites. - Updated `SitesRendererAdapter` to construct deployment URLs dynamically based on environment variables. - Added `SiteDefinitionView` to provide a public API endpoint for retrieving deployed site definitions. - Enhanced `loadSiteDefinition` function to prioritize API calls for site definitions over filesystem access. - Updated frontend to utilize the new API endpoint for loading site definitions.
This commit is contained in:
Binary file not shown.
@@ -198,10 +198,16 @@ class SitesRendererAdapter(BaseAdapter):
|
||||
Returns:
|
||||
str: Deployment URL
|
||||
"""
|
||||
# TODO: Implement URL generation based on site configuration
|
||||
# For now, return placeholder
|
||||
site_id = site_blueprint.site.id
|
||||
return f"https://{site_id}.igny8.com" # Placeholder
|
||||
|
||||
# Get Sites Renderer URL from environment or use default
|
||||
sites_renderer_host = os.getenv('SITES_RENDERER_HOST', '31.97.144.105')
|
||||
sites_renderer_port = os.getenv('SITES_RENDERER_PORT', '8024')
|
||||
sites_renderer_protocol = os.getenv('SITES_RENDERER_PROTOCOL', 'http')
|
||||
|
||||
# Construct URL: http://31.97.144.105:8024/{site_id}
|
||||
# Sites Renderer routes: /:siteId/* -> SiteRenderer component
|
||||
return f"{sites_renderer_protocol}://{sites_renderer_host}:{sites_renderer_port}/{site_id}"
|
||||
|
||||
# BaseAdapter interface implementation
|
||||
def publish(
|
||||
|
||||
@@ -9,6 +9,7 @@ from igny8_core.modules.publisher.views import (
|
||||
PublishingRecordViewSet,
|
||||
DeploymentRecordViewSet,
|
||||
PublisherViewSet,
|
||||
SiteDefinitionView,
|
||||
)
|
||||
|
||||
router = DefaultRouter()
|
||||
@@ -19,5 +20,7 @@ router.register(r'', PublisherViewSet, basename='publisher')
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
# Public endpoint for Sites Renderer
|
||||
path('sites/<int:site_id>/definition/', SiteDefinitionView.as_view(), name='site-definition'),
|
||||
]
|
||||
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
Publisher ViewSet
|
||||
Phase 5: Sites Renderer & Publishing
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from rest_framework import status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from igny8_core.api.base import SiteSectorModelViewSet
|
||||
from igny8_core.api.permissions import IsAuthenticatedAndActive, IsEditorOrAbove
|
||||
@@ -196,3 +200,76 @@ class PublisherViewSet(viewsets.ViewSet):
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
class SiteDefinitionView(APIView):
|
||||
"""
|
||||
Public endpoint to serve deployed site definitions.
|
||||
Used by Sites Renderer to load site definitions.
|
||||
No authentication required for public sites.
|
||||
"""
|
||||
permission_classes = [] # Public endpoint
|
||||
|
||||
def get(self, request, site_id):
|
||||
"""
|
||||
Get deployed site definition.
|
||||
|
||||
GET /api/v1/publisher/sites/{site_id}/definition/
|
||||
"""
|
||||
sites_data_path = os.getenv('SITES_DATA_PATH', '/data/app/sites-data')
|
||||
|
||||
# Try to find latest deployed version
|
||||
site_dir = Path(sites_data_path) / 'clients' / str(site_id)
|
||||
|
||||
if not site_dir.exists():
|
||||
return error_response(
|
||||
f'Site {site_id} not found',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
# Look for latest version (check for 'latest' symlink or highest version number)
|
||||
latest_path = site_dir / 'latest' / 'site.json'
|
||||
if latest_path.exists():
|
||||
try:
|
||||
with open(latest_path, 'r', encoding='utf-8') as f:
|
||||
definition = json.load(f)
|
||||
return Response(definition, status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
f'Failed to load site definition: {str(e)}',
|
||||
status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
request
|
||||
)
|
||||
|
||||
# Fallback: find highest version number
|
||||
version_dirs = [d for d in site_dir.iterdir() if d.is_dir() and d.name.startswith('v')]
|
||||
if not version_dirs:
|
||||
return error_response(
|
||||
f'No deployed versions found for site {site_id}',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
# Sort by version number (extract number from 'v1', 'v2', etc.)
|
||||
try:
|
||||
version_dirs.sort(key=lambda d: int(d.name[1:]) if d.name[1:].isdigit() else 0, reverse=True)
|
||||
latest_version_dir = version_dirs[0]
|
||||
site_json_path = latest_version_dir / 'site.json'
|
||||
|
||||
if site_json_path.exists():
|
||||
with open(site_json_path, 'r', encoding='utf-8') as f:
|
||||
definition = json.load(f)
|
||||
return Response(definition, status=status.HTTP_200_OK)
|
||||
except Exception as e:
|
||||
return error_response(
|
||||
f'Failed to load site definition: {str(e)}',
|
||||
status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
request
|
||||
)
|
||||
|
||||
return error_response(
|
||||
f'Site definition not found for site {site_id}',
|
||||
status.HTTP_404_NOT_FOUND,
|
||||
request
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user