Fix site_id isolation for demo sites
- Auto-derive site_id from demo directory paths (demos/demo-site -> 'demo', demos/simple/test-simple -> 'simple') - Add validation requiring explicit site_id for non-demo paths with helpful error messages - Remove JavaScript 'demo' fallback and add proper error messaging for missing site_id - Ensure each demo site uses isolated content namespace to prevent content mixing Resolves issue where /sites/simple and /sites/demo both used site_id=demo
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
@@ -49,6 +50,30 @@ func runEnhance(cmd *cobra.Command, args []string) {
|
|||||||
siteID := viper.GetString("cli.site_id")
|
siteID := viper.GetString("cli.site_id")
|
||||||
outputDir := viper.GetString("cli.output")
|
outputDir := viper.GetString("cli.output")
|
||||||
|
|
||||||
|
// Auto-derive site_id for demo paths or validate for production
|
||||||
|
if strings.Contains(inputDir, "/demos/") {
|
||||||
|
// Auto-derive site_id from demo path
|
||||||
|
siteID = content.DeriveOrValidateSiteID(inputDir, siteID)
|
||||||
|
} else {
|
||||||
|
// Validate site_id for non-demo paths
|
||||||
|
if siteID == "" || siteID == "demo" {
|
||||||
|
log.Fatalf(`❌ site_id must be explicitly configured for non-demo sites.
|
||||||
|
|
||||||
|
💡 Examples:
|
||||||
|
# Set via command line:
|
||||||
|
insertr enhance --site-id mysite /path/to/site
|
||||||
|
|
||||||
|
# Set in insertr.yaml:
|
||||||
|
cli:
|
||||||
|
site_id: "mysite"
|
||||||
|
|
||||||
|
# Set via environment:
|
||||||
|
INSERTR_CLI_SITE_ID=mysite insertr enhance /path/to/site
|
||||||
|
|
||||||
|
🚀 For demo sites under demos/, site_id is auto-derived from the directory name.`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create content client
|
// Create content client
|
||||||
var client engine.ContentClient
|
var client engine.ContentClient
|
||||||
if apiURL != "" {
|
if apiURL != "" {
|
||||||
|
|||||||
@@ -194,13 +194,89 @@ func (e *Enhancer) enhanceWithEngine(htmlContent []byte, filePath string) ([]byt
|
|||||||
|
|
||||||
// EnhanceInPlace performs in-place enhancement of static site files
|
// EnhanceInPlace performs in-place enhancement of static site files
|
||||||
func (e *Enhancer) EnhanceInPlace(sitePath string, siteID string) error {
|
func (e *Enhancer) EnhanceInPlace(sitePath string, siteID string) error {
|
||||||
// Update the enhancer's site ID for this operation
|
// Use the provided siteID (derivation should happen at CLI level)
|
||||||
e.siteID = siteID
|
e.siteID = siteID
|
||||||
|
|
||||||
// Use EnhanceDirectory with same input and output (in-place)
|
// Use EnhanceDirectory with same input and output (in-place)
|
||||||
return e.EnhanceDirectory(sitePath, sitePath)
|
return e.EnhanceDirectory(sitePath, sitePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeriveOrValidateSiteID automatically derives site_id for demo paths or validates for production
|
||||||
|
func DeriveOrValidateSiteID(sitePath string, configSiteID string) string {
|
||||||
|
// Check if this is a demo path
|
||||||
|
if strings.Contains(sitePath, "/demos/") {
|
||||||
|
return deriveDemoSiteID(sitePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-demo paths, return the configured site_id
|
||||||
|
// Validation of non-demo site_id will be handled at the CLI level
|
||||||
|
return configSiteID
|
||||||
|
}
|
||||||
|
|
||||||
|
// deriveDemoSiteID extracts site_id from demo directory structure
|
||||||
|
func deriveDemoSiteID(sitePath string) string {
|
||||||
|
// Convert to absolute path and clean it
|
||||||
|
absPath, err := filepath.Abs(sitePath)
|
||||||
|
if err != nil {
|
||||||
|
absPath = sitePath
|
||||||
|
}
|
||||||
|
absPath = filepath.Clean(absPath)
|
||||||
|
|
||||||
|
// Look for patterns in demo paths:
|
||||||
|
// demos/demo-site_enhanced -> "demo"
|
||||||
|
// demos/simple/test-simple_enhanced -> "simple"
|
||||||
|
// demos/simple/dan-eden-portfolio -> "dan-eden"
|
||||||
|
|
||||||
|
parts := strings.Split(absPath, string(filepath.Separator))
|
||||||
|
|
||||||
|
// Find the demos directory index
|
||||||
|
demosIndex := -1
|
||||||
|
for i, part := range parts {
|
||||||
|
if part == "demos" {
|
||||||
|
demosIndex = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if demosIndex == -1 || demosIndex >= len(parts)-1 {
|
||||||
|
// Fallback if demos not found in path
|
||||||
|
return "demo"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the segment after demos/
|
||||||
|
nextSegment := parts[demosIndex+1]
|
||||||
|
|
||||||
|
// Handle different demo directory patterns:
|
||||||
|
if strings.HasPrefix(nextSegment, "demo-site") {
|
||||||
|
return "demo"
|
||||||
|
}
|
||||||
|
|
||||||
|
if nextSegment == "simple" && len(parts) > demosIndex+2 {
|
||||||
|
// For demos/simple/something, use the something part
|
||||||
|
finalSegment := parts[demosIndex+2]
|
||||||
|
|
||||||
|
// Extract meaningful name from directory
|
||||||
|
if strings.HasPrefix(finalSegment, "test-") {
|
||||||
|
// test-simple_enhanced -> simple
|
||||||
|
return "simple"
|
||||||
|
}
|
||||||
|
if strings.Contains(finalSegment, "dan-eden") {
|
||||||
|
return "dan-eden"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic case: use the directory name as-is
|
||||||
|
return strings.TrimSuffix(finalSegment, "_enhanced")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default case: use the immediate subdirectory of demos/
|
||||||
|
result := strings.TrimSuffix(nextSegment, "_enhanced")
|
||||||
|
|
||||||
|
// Clean up common suffixes
|
||||||
|
result = strings.TrimSuffix(result, "-site")
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// copyFile copies a file from src to dst
|
// copyFile copies a file from src to dst
|
||||||
func (e *Enhancer) copyFile(src, dst string) error {
|
func (e *Enhancer) copyFile(src, dst string) error {
|
||||||
// Create directory for destination
|
// Create directory for destination
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export class ApiClient {
|
|||||||
: '/api/content'; // Production: same-origin API
|
: '/api/content'; // Production: same-origin API
|
||||||
|
|
||||||
this.baseUrl = options.apiEndpoint || defaultEndpoint;
|
this.baseUrl = options.apiEndpoint || defaultEndpoint;
|
||||||
this.siteId = options.siteId || 'demo';
|
this.siteId = options.siteId || this.handleMissingSiteId();
|
||||||
|
|
||||||
// Log API configuration in development
|
// Log API configuration in development
|
||||||
if (isDevelopment && !options.apiEndpoint) {
|
if (isDevelopment && !options.apiEndpoint) {
|
||||||
@@ -276,6 +276,22 @@ export class ApiClient {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle missing site_id configuration
|
||||||
|
* @returns {string} Site ID or throws error
|
||||||
|
*/
|
||||||
|
handleMissingSiteId() {
|
||||||
|
console.error('❌ No site_id configured for Insertr.');
|
||||||
|
console.log('💡 Add data-site-id attribute to your script tag:');
|
||||||
|
console.log(' <script src="insertr.js" data-site-id="mysite"></script>');
|
||||||
|
console.log('');
|
||||||
|
console.log('🚀 For demos under demos/, site_id is auto-derived from directory name.');
|
||||||
|
console.log('🏭 For production sites, you must explicitly set your site_id.');
|
||||||
|
|
||||||
|
// Return a placeholder that will cause API calls to fail gracefully
|
||||||
|
return '__MISSING_SITE_ID__';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get current file path from URL for consistent ID generation
|
* Get current file path from URL for consistent ID generation
|
||||||
* @returns {string} File path like "index.html", "about.html"
|
* @returns {string} File path like "index.html", "about.html"
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ function autoInitialize() {
|
|||||||
const config = {};
|
const config = {};
|
||||||
|
|
||||||
if (insertrScript) {
|
if (insertrScript) {
|
||||||
config.siteId = insertrScript.getAttribute('data-site-id') || 'demo';
|
config.siteId = insertrScript.getAttribute('data-site-id'); // No fallback - let ApiClient handle missing values
|
||||||
config.apiEndpoint = insertrScript.getAttribute('data-api-endpoint') || '/api/content';
|
config.apiEndpoint = insertrScript.getAttribute('data-api-endpoint') || '/api/content';
|
||||||
config.mockAuth = insertrScript.getAttribute('data-mock-auth') === 'true';
|
config.mockAuth = insertrScript.getAttribute('data-mock-auth') === 'true';
|
||||||
config.debug = insertrScript.getAttribute('data-debug') === 'true';
|
config.debug = insertrScript.getAttribute('data-debug') === 'true';
|
||||||
|
|||||||
Reference in New Issue
Block a user