- Remove complex style preservation system from editor - Simplify markdown conversion back to straightforward approach - Remove StyleContext class and style-aware conversion methods - Switch content type from 'html' back to 'markdown' for consistency - Clean up editor workflow to focus on core markdown editing - Remove ~500 lines of unnecessary style complexity This completes the UI unification cleanup by removing the overly complex style preservation system that was making the editor harder to maintain.
761 lines
22 KiB
Go
761 lines
22 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/insertr/insertr/internal/auth"
|
|
"github.com/insertr/insertr/internal/content"
|
|
"github.com/insertr/insertr/internal/db"
|
|
"github.com/insertr/insertr/internal/db/postgresql"
|
|
"github.com/insertr/insertr/internal/db/sqlite"
|
|
"github.com/insertr/insertr/internal/engine"
|
|
)
|
|
|
|
// ContentHandler handles all content-related HTTP requests
|
|
type ContentHandler struct {
|
|
database *db.Database
|
|
authService *auth.AuthService
|
|
siteManager *content.SiteManager
|
|
engine *engine.ContentEngine
|
|
}
|
|
|
|
// NewContentHandler creates a new content handler
|
|
func NewContentHandler(database *db.Database, authService *auth.AuthService) *ContentHandler {
|
|
// Create database client for engine
|
|
dbClient := engine.NewDatabaseClient(database)
|
|
|
|
return &ContentHandler{
|
|
database: database,
|
|
authService: authService,
|
|
siteManager: nil, // Will be set via SetSiteManager
|
|
engine: engine.NewContentEngine(dbClient),
|
|
}
|
|
}
|
|
|
|
// SetSiteManager sets the site manager for file enhancement
|
|
func (h *ContentHandler) SetSiteManager(siteManager *content.SiteManager) {
|
|
h.siteManager = siteManager
|
|
}
|
|
|
|
// EnhanceSite handles POST /api/enhance - manual site enhancement trigger
|
|
func (h *ContentHandler) EnhanceSite(w http.ResponseWriter, r *http.Request) {
|
|
siteID := r.URL.Query().Get("site_id")
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if h.siteManager == nil {
|
|
http.Error(w, "Site manager not available", http.StatusServiceUnavailable)
|
|
return
|
|
}
|
|
|
|
// Check if site is registered
|
|
site, exists := h.siteManager.GetSite(siteID)
|
|
if !exists {
|
|
http.Error(w, fmt.Sprintf("Site %s is not registered", siteID), http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Perform enhancement
|
|
err := h.siteManager.EnhanceSite(siteID)
|
|
if err != nil {
|
|
log.Printf("❌ Manual enhancement failed for site %s: %v", siteID, err)
|
|
http.Error(w, fmt.Sprintf("Enhancement failed: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Get enhancement statistics
|
|
stats := h.siteManager.GetStats()
|
|
|
|
// Return success response with details
|
|
response := map[string]interface{}{
|
|
"success": true,
|
|
"site_id": siteID,
|
|
"site_path": site.Path,
|
|
"message": fmt.Sprintf("Successfully enhanced site %s", siteID),
|
|
"stats": stats,
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
|
|
log.Printf("✅ Manual enhancement completed for site %s", siteID)
|
|
}
|
|
|
|
// GetContent handles GET /api/content/{id}
|
|
func (h *ContentHandler) GetContent(w http.ResponseWriter, r *http.Request) {
|
|
contentID := chi.URLParam(r, "id")
|
|
siteID := r.URL.Query().Get("site_id")
|
|
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var content interface{}
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
content, err = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
case "postgresql":
|
|
content, err = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
http.Error(w, "Content not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
item := h.convertToAPIContent(content)
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(item)
|
|
}
|
|
|
|
// GetAllContent handles GET /api/content
|
|
func (h *ContentHandler) GetAllContent(w http.ResponseWriter, r *http.Request) {
|
|
siteID := r.URL.Query().Get("site_id")
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var dbContent interface{}
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
dbContent, err = h.database.GetSQLiteQueries().GetAllContent(context.Background(), siteID)
|
|
case "postgresql":
|
|
dbContent, err = h.database.GetPostgreSQLQueries().GetAllContent(context.Background(), siteID)
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
items := h.convertToAPIContentList(dbContent)
|
|
response := ContentResponse{Content: items}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
// GetBulkContent handles GET /api/content/bulk
|
|
func (h *ContentHandler) GetBulkContent(w http.ResponseWriter, r *http.Request) {
|
|
siteID := r.URL.Query().Get("site_id")
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Parse ids parameter
|
|
idsParam := r.URL.Query()["ids[]"]
|
|
if len(idsParam) == 0 {
|
|
// Try single ids parameter
|
|
idsStr := r.URL.Query().Get("ids")
|
|
if idsStr == "" {
|
|
http.Error(w, "ids parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
idsParam = strings.Split(idsStr, ",")
|
|
}
|
|
|
|
var dbContent interface{}
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
dbContent, err = h.database.GetSQLiteQueries().GetBulkContent(context.Background(), sqlite.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: idsParam,
|
|
})
|
|
case "postgresql":
|
|
dbContent, err = h.database.GetPostgreSQLQueries().GetBulkContent(context.Background(), postgresql.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: idsParam,
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
items := h.convertToAPIContentList(dbContent)
|
|
response := ContentResponse{Content: items}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
// CreateContent handles POST /api/content
|
|
func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request) {
|
|
var req CreateContentRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
siteID := r.URL.Query().Get("site_id")
|
|
if siteID == "" {
|
|
siteID = req.SiteID // fallback to request body
|
|
}
|
|
if siteID == "" {
|
|
siteID = "default" // final fallback
|
|
}
|
|
|
|
// Generate content ID using the unified engine
|
|
if req.HTMLMarkup == "" {
|
|
http.Error(w, "html_markup is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
result, engineErr := h.engine.ProcessContent(engine.ContentInput{
|
|
HTML: []byte(req.HTMLMarkup),
|
|
FilePath: req.FilePath,
|
|
SiteID: siteID,
|
|
Mode: engine.IDGeneration,
|
|
})
|
|
if engineErr != nil {
|
|
http.Error(w, fmt.Sprintf("ID generation failed: %v", engineErr), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if len(result.Elements) == 0 {
|
|
http.Error(w, "No insertr elements found in HTML markup", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Use the ID generated by the engine for the first element
|
|
contentID := result.Elements[0].ID
|
|
|
|
// Extract user from request using authentication service
|
|
userInfo, authErr := h.authService.ExtractUserFromRequest(r)
|
|
if authErr != nil {
|
|
http.Error(w, fmt.Sprintf("Authentication error: %v", authErr), http.StatusUnauthorized)
|
|
return
|
|
}
|
|
userID := userInfo.ID
|
|
|
|
// Check if content exists for version history (non-blocking)
|
|
var existingContent interface{}
|
|
var contentExists bool
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
existingContent, _ = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
contentExists = existingContent != nil
|
|
case "postgresql":
|
|
existingContent, _ = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
contentExists = existingContent != nil
|
|
}
|
|
|
|
// Archive existing version before upsert (only if content already exists)
|
|
if contentExists {
|
|
if err := h.createContentVersion(existingContent); err != nil {
|
|
// Log error but don't fail the request - version history is non-critical
|
|
fmt.Printf("Warning: Failed to create content version: %v\n", err)
|
|
}
|
|
}
|
|
|
|
// Determine content type: use provided type, fallback to existing type, default to "text"
|
|
contentType := req.Type
|
|
if contentType == "" && contentExists {
|
|
contentType = h.getContentType(existingContent)
|
|
}
|
|
if contentType == "" {
|
|
contentType = "text" // default type for new content
|
|
}
|
|
|
|
var content interface{}
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
content, err = h.database.GetSQLiteQueries().UpsertContent(context.Background(), sqlite.UpsertContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
Value: req.Value,
|
|
Type: contentType,
|
|
LastEditedBy: userID,
|
|
})
|
|
case "postgresql":
|
|
content, err = h.database.GetPostgreSQLQueries().UpsertContent(context.Background(), postgresql.UpsertContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
Value: req.Value,
|
|
Type: contentType,
|
|
LastEditedBy: userID,
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to upsert content: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
item := h.convertToAPIContent(content)
|
|
|
|
// Trigger file enhancement if site is registered for auto-enhancement
|
|
log.Printf("🔍 Checking auto-enhancement for site: %s", siteID)
|
|
if h.siteManager == nil {
|
|
log.Printf("❌ No site manager configured")
|
|
} else if !h.siteManager.IsAutoEnhanceEnabled(siteID) {
|
|
log.Printf("❌ Auto-enhancement not enabled for site: %s", siteID)
|
|
} else {
|
|
log.Printf("✅ Triggering auto-enhancement for site: %s", siteID)
|
|
go func() {
|
|
log.Printf("🔄 Starting enhancement for site: %s", siteID)
|
|
if err := h.siteManager.EnhanceSite(siteID); err != nil {
|
|
log.Printf("⚠️ Failed to enhance site %s: %v", siteID, err)
|
|
} else {
|
|
log.Printf("✅ Enhanced files for site %s", siteID)
|
|
}
|
|
}()
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(item)
|
|
}
|
|
|
|
// DeleteContent handles DELETE /api/content/{id}
|
|
func (h *ContentHandler) DeleteContent(w http.ResponseWriter, r *http.Request) {
|
|
contentID := chi.URLParam(r, "id")
|
|
siteID := r.URL.Query().Get("site_id")
|
|
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
err = h.database.GetSQLiteQueries().DeleteContent(context.Background(), sqlite.DeleteContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
case "postgresql":
|
|
err = h.database.GetPostgreSQLQueries().DeleteContent(context.Background(), postgresql.DeleteContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to delete content: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// GetContentVersions handles GET /api/content/{id}/versions
|
|
func (h *ContentHandler) GetContentVersions(w http.ResponseWriter, r *http.Request) {
|
|
contentID := chi.URLParam(r, "id")
|
|
siteID := r.URL.Query().Get("site_id")
|
|
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Parse limit parameter (default to 10)
|
|
limit := int64(10)
|
|
if limitStr := r.URL.Query().Get("limit"); limitStr != "" {
|
|
if parsedLimit, err := strconv.ParseInt(limitStr, 10, 64); err == nil {
|
|
limit = parsedLimit
|
|
}
|
|
}
|
|
|
|
var dbVersions interface{}
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
dbVersions, err = h.database.GetSQLiteQueries().GetContentVersionHistory(context.Background(), sqlite.GetContentVersionHistoryParams{
|
|
ContentID: contentID,
|
|
SiteID: siteID,
|
|
LimitCount: limit,
|
|
})
|
|
case "postgresql":
|
|
// Note: PostgreSQL uses different parameter names due to int32 vs int64
|
|
dbVersions, err = h.database.GetPostgreSQLQueries().GetContentVersionHistory(context.Background(), postgresql.GetContentVersionHistoryParams{
|
|
ContentID: contentID,
|
|
SiteID: siteID,
|
|
LimitCount: int32(limit),
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
versions := h.convertToAPIVersionList(dbVersions)
|
|
response := ContentVersionsResponse{Versions: versions}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
}
|
|
|
|
// RollbackContent handles POST /api/content/{id}/rollback
|
|
func (h *ContentHandler) RollbackContent(w http.ResponseWriter, r *http.Request) {
|
|
contentID := chi.URLParam(r, "id")
|
|
siteID := r.URL.Query().Get("site_id")
|
|
|
|
if siteID == "" {
|
|
http.Error(w, "site_id parameter is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req RollbackContentRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Get the target version
|
|
var targetVersion interface{}
|
|
var err error
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
targetVersion, err = h.database.GetSQLiteQueries().GetContentVersion(context.Background(), req.VersionID)
|
|
case "postgresql":
|
|
targetVersion, err = h.database.GetPostgreSQLQueries().GetContentVersion(context.Background(), int32(req.VersionID))
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
http.Error(w, "Version not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
http.Error(w, fmt.Sprintf("Database error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Verify the version belongs to the correct content
|
|
if !h.versionMatches(targetVersion, contentID, siteID) {
|
|
http.Error(w, "Version does not match content", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Extract user from request using authentication service
|
|
userInfo, authErr := h.authService.ExtractUserFromRequest(r)
|
|
if authErr != nil {
|
|
http.Error(w, fmt.Sprintf("Authentication error: %v", authErr), http.StatusUnauthorized)
|
|
return
|
|
}
|
|
userID := userInfo.ID
|
|
|
|
// Archive current version before rollback
|
|
var currentContent interface{}
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
currentContent, err = h.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
case "postgresql":
|
|
currentContent, err = h.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to get current content: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
err = h.createContentVersion(currentContent)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to create version: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Rollback to target version
|
|
var updatedContent interface{}
|
|
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
sqliteVersion := targetVersion.(sqlite.ContentVersion)
|
|
updatedContent, err = h.database.GetSQLiteQueries().UpdateContent(context.Background(), sqlite.UpdateContentParams{
|
|
Value: sqliteVersion.Value,
|
|
Type: sqliteVersion.Type,
|
|
LastEditedBy: userID,
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
case "postgresql":
|
|
pgVersion := targetVersion.(postgresql.ContentVersion)
|
|
updatedContent, err = h.database.GetPostgreSQLQueries().UpdateContent(context.Background(), postgresql.UpdateContentParams{
|
|
Value: pgVersion.Value,
|
|
Type: pgVersion.Type,
|
|
LastEditedBy: userID,
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
default:
|
|
http.Error(w, "Unsupported database type", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to rollback content: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
item := h.convertToAPIContent(updatedContent)
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(item)
|
|
}
|
|
|
|
// Helper functions for type conversion
|
|
func (h *ContentHandler) convertToAPIContent(content interface{}) ContentItem {
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
c := content.(sqlite.Content)
|
|
return ContentItem{
|
|
ID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
CreatedAt: time.Unix(c.CreatedAt, 0),
|
|
UpdatedAt: time.Unix(c.UpdatedAt, 0),
|
|
LastEditedBy: c.LastEditedBy,
|
|
}
|
|
case "postgresql":
|
|
c := content.(postgresql.Content)
|
|
return ContentItem{
|
|
ID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
CreatedAt: time.Unix(c.CreatedAt, 0),
|
|
UpdatedAt: time.Unix(c.UpdatedAt, 0),
|
|
LastEditedBy: c.LastEditedBy,
|
|
}
|
|
}
|
|
return ContentItem{} // Should never happen
|
|
}
|
|
|
|
func (h *ContentHandler) convertToAPIContentList(contentList interface{}) []ContentItem {
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
list := contentList.([]sqlite.Content)
|
|
items := make([]ContentItem, len(list))
|
|
for i, content := range list {
|
|
items[i] = h.convertToAPIContent(content)
|
|
}
|
|
return items
|
|
case "postgresql":
|
|
list := contentList.([]postgresql.Content)
|
|
items := make([]ContentItem, len(list))
|
|
for i, content := range list {
|
|
items[i] = h.convertToAPIContent(content)
|
|
}
|
|
return items
|
|
}
|
|
return []ContentItem{} // Should never happen
|
|
}
|
|
|
|
func (h *ContentHandler) convertToAPIVersionList(versionList interface{}) []ContentVersion {
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
list := versionList.([]sqlite.ContentVersion)
|
|
versions := make([]ContentVersion, len(list))
|
|
for i, version := range list {
|
|
versions[i] = ContentVersion{
|
|
VersionID: version.VersionID,
|
|
ContentID: version.ContentID,
|
|
SiteID: version.SiteID,
|
|
Value: version.Value,
|
|
Type: version.Type,
|
|
CreatedAt: time.Unix(version.CreatedAt, 0),
|
|
CreatedBy: version.CreatedBy,
|
|
}
|
|
}
|
|
return versions
|
|
case "postgresql":
|
|
list := versionList.([]postgresql.ContentVersion)
|
|
versions := make([]ContentVersion, len(list))
|
|
for i, version := range list {
|
|
versions[i] = ContentVersion{
|
|
VersionID: int64(version.VersionID),
|
|
ContentID: version.ContentID,
|
|
SiteID: version.SiteID,
|
|
Value: version.Value,
|
|
Type: version.Type,
|
|
CreatedAt: time.Unix(version.CreatedAt, 0),
|
|
CreatedBy: version.CreatedBy,
|
|
}
|
|
}
|
|
return versions
|
|
}
|
|
return []ContentVersion{} // Should never happen
|
|
}
|
|
|
|
func (h *ContentHandler) createContentVersion(content interface{}) error {
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
c := content.(sqlite.Content)
|
|
return h.database.GetSQLiteQueries().CreateContentVersion(context.Background(), sqlite.CreateContentVersionParams{
|
|
ContentID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
CreatedBy: c.LastEditedBy,
|
|
})
|
|
case "postgresql":
|
|
c := content.(postgresql.Content)
|
|
return h.database.GetPostgreSQLQueries().CreateContentVersion(context.Background(), postgresql.CreateContentVersionParams{
|
|
ContentID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
CreatedBy: c.LastEditedBy,
|
|
})
|
|
}
|
|
return fmt.Errorf("unsupported database type")
|
|
}
|
|
|
|
func (h *ContentHandler) getContentType(content interface{}) string {
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
return content.(sqlite.Content).Type
|
|
case "postgresql":
|
|
return content.(postgresql.Content).Type
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (h *ContentHandler) versionMatches(version interface{}, contentID, siteID string) bool {
|
|
switch h.database.GetDBType() {
|
|
case "sqlite3":
|
|
v := version.(sqlite.ContentVersion)
|
|
return v.ContentID == contentID && v.SiteID == siteID
|
|
case "postgresql":
|
|
v := version.(postgresql.ContentVersion)
|
|
return v.ContentID == contentID && v.SiteID == siteID
|
|
}
|
|
return false
|
|
}
|
|
|
|
// generateContentID function removed - using unified ContentEngine instead
|
|
|
|
// ServeInsertrJS handles GET /insertr.js - serves the insertr JavaScript library
|
|
func (h *ContentHandler) ServeInsertrJS(w http.ResponseWriter, r *http.Request) {
|
|
// Path to the built insertr.js file
|
|
jsPath := "lib/dist/insertr.js"
|
|
|
|
// Check if file exists
|
|
if _, err := os.Stat(jsPath); os.IsNotExist(err) {
|
|
http.Error(w, "insertr.js not found - run 'just build-lib' to build the library", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Open and serve the file
|
|
file, err := os.Open(jsPath)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to open insertr.js: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
// Set appropriate headers
|
|
w.Header().Set("Content-Type", "application/javascript")
|
|
w.Header().Set("Cache-Control", "no-cache") // For development
|
|
|
|
// Copy file contents to response
|
|
io.Copy(w, file)
|
|
}
|
|
|
|
// ServeInsertrCSS handles GET /insertr.css - serves the insertr CSS stylesheet
|
|
func (h *ContentHandler) ServeInsertrCSS(w http.ResponseWriter, r *http.Request) {
|
|
// Path to the built insertr.css file
|
|
cssPath := "lib/dist/insertr.css"
|
|
|
|
// Check if file exists
|
|
if _, err := os.Stat(cssPath); os.IsNotExist(err) {
|
|
http.Error(w, "insertr.css not found - run 'just build-lib' to build the library", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Open and serve the file
|
|
file, err := os.Open(cssPath)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to open insertr.css: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
// Set appropriate headers
|
|
w.Header().Set("Content-Type", "text/css")
|
|
w.Header().Set("Cache-Control", "no-cache") // For development
|
|
|
|
// Copy file contents to response
|
|
io.Copy(w, file)
|
|
}
|