- Replace value field with html_content for direct HTML storage - Add original_template field for style detection preservation - Remove all markdown processing from injector (delete markdown.go) - Fix critical content extraction/injection bugs in engine - Add missing UpdateContent PUT handler for content persistence - Fix API client field names and add updateContent() method - Resolve content type validation (only allow text/link types) - Add UUID-based ID generation to prevent collisions - Complete first-pass processing workflow for unprocessed elements - Verify end-to-end: Enhancement → Database → API → Editor → Persistence All 37 files updated for HTML-first content management system. Phase 3a implementation complete and production ready.
230 lines
6.7 KiB
Go
230 lines
6.7 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/insertr/insertr/internal/db"
|
|
"github.com/insertr/insertr/internal/db/postgresql"
|
|
"github.com/insertr/insertr/internal/db/sqlite"
|
|
)
|
|
|
|
// Helper function to convert sql.NullString to string
|
|
func getStringFromNullString(ns sql.NullString) string {
|
|
if ns.Valid {
|
|
return ns.String
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// DatabaseClient implements ContentClient interface using the database
|
|
type DatabaseClient struct {
|
|
database *db.Database
|
|
}
|
|
|
|
// NewDatabaseClient creates a new database client
|
|
func NewDatabaseClient(database *db.Database) *DatabaseClient {
|
|
return &DatabaseClient{
|
|
database: database,
|
|
}
|
|
}
|
|
|
|
// GetContent retrieves a single content item
|
|
func (c *DatabaseClient) GetContent(siteID, contentID string) (*ContentItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
content, err := c.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}, nil
|
|
|
|
case "postgresql":
|
|
content, err := c.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// GetBulkContent retrieves multiple content items
|
|
func (c *DatabaseClient) GetBulkContent(siteID string, contentIDs []string) (map[string]ContentItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
contents, err := c.database.GetSQLiteQueries().GetBulkContent(context.Background(), sqlite.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: contentIDs,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make(map[string]ContentItem)
|
|
for _, content := range contents {
|
|
items[content.ID] = ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}
|
|
}
|
|
return items, nil
|
|
|
|
case "postgresql":
|
|
contents, err := c.database.GetPostgreSQLQueries().GetBulkContent(context.Background(), postgresql.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: contentIDs,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make(map[string]ContentItem)
|
|
for _, content := range contents {
|
|
items[content.ID] = ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}
|
|
}
|
|
return items, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// GetAllContent retrieves all content items for a site
|
|
func (c *DatabaseClient) GetAllContent(siteID string) (map[string]ContentItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
contents, err := c.database.GetSQLiteQueries().GetAllContent(context.Background(), siteID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make(map[string]ContentItem)
|
|
for _, content := range contents {
|
|
items[content.ID] = ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}
|
|
}
|
|
return items, nil
|
|
|
|
case "postgresql":
|
|
contents, err := c.database.GetPostgreSQLQueries().GetAllContent(context.Background(), siteID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
items := make(map[string]ContentItem)
|
|
for _, content := range contents {
|
|
items[content.ID] = ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}
|
|
}
|
|
return items, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// CreateContent creates a new content item
|
|
func (c *DatabaseClient) CreateContent(siteID, contentID, htmlContent, originalTemplate, contentType, lastEditedBy string) (*ContentItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
content, err := c.database.GetSQLiteQueries().CreateContent(context.Background(), sqlite.CreateContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
HtmlContent: htmlContent,
|
|
OriginalTemplate: toNullString(originalTemplate),
|
|
Type: contentType,
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}, nil
|
|
|
|
case "postgresql":
|
|
content, err := c.database.GetPostgreSQLQueries().CreateContent(context.Background(), postgresql.CreateContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
HtmlContent: htmlContent,
|
|
OriginalTemplate: toNullString(originalTemplate),
|
|
Type: contentType,
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
Type: content.Type,
|
|
LastEditedBy: content.LastEditedBy,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// Helper function to convert string to sql.NullString
|
|
func toNullString(s string) sql.NullString {
|
|
if s == "" {
|
|
return sql.NullString{Valid: false}
|
|
}
|
|
return sql.NullString{String: s, Valid: true}
|
|
}
|