Consolidates duplicate code and removes technical debt accumulated during rapid development. This cleanup improves maintainability while preserving all functionality. Backend cleanup: - Remove unused legacy function findViableChildrenLegacy() - Consolidate duplicate SQL null string helper functions into shared utils - Unify text extraction functions across utils, engine, and id_generator - Consolidate duplicate attribute getter functions into single implementation Frontend cleanup: - Remove duplicate authentication methods (authenticateWithOAuth vs performOAuthFlow) - Remove unused hasPermission() method from auth.js - Centralize repetitive API endpoint construction in api-client.js - Reduce excessive console logging while preserving important error logs Impact: -144 lines of code, improved maintainability, no functionality changes All tests pass and builds succeed 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
545 lines
16 KiB
Go
545 lines
16 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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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),
|
|
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, 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),
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
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),
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &ContentItem{
|
|
ID: content.ID,
|
|
SiteID: content.SiteID,
|
|
HTMLContent: content.HtmlContent,
|
|
OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
|
|
LastEditedBy: content.LastEditedBy,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
|
|
// GetCollection retrieves a collection container
|
|
func (c *DatabaseClient) GetCollection(siteID, collectionID string) (*CollectionItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
collection, err := c.database.GetSQLiteQueries().GetCollection(context.Background(), sqlite.GetCollectionParams{
|
|
ID: collectionID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionItem{
|
|
ID: collection.ID,
|
|
SiteID: collection.SiteID,
|
|
ContainerHTML: collection.ContainerHtml,
|
|
LastEditedBy: collection.LastEditedBy,
|
|
}, nil
|
|
|
|
case "postgresql":
|
|
collection, err := c.database.GetPostgreSQLQueries().GetCollection(context.Background(), postgresql.GetCollectionParams{
|
|
ID: collectionID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionItem{
|
|
ID: collection.ID,
|
|
SiteID: collection.SiteID,
|
|
ContainerHTML: collection.ContainerHtml,
|
|
LastEditedBy: collection.LastEditedBy,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// CreateCollection creates a new collection container
|
|
func (c *DatabaseClient) CreateCollection(siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
collection, err := c.database.GetSQLiteQueries().CreateCollection(context.Background(), sqlite.CreateCollectionParams{
|
|
ID: collectionID,
|
|
SiteID: siteID,
|
|
ContainerHtml: containerHTML,
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionItem{
|
|
ID: collection.ID,
|
|
SiteID: collection.SiteID,
|
|
ContainerHTML: collection.ContainerHtml,
|
|
LastEditedBy: collection.LastEditedBy,
|
|
}, nil
|
|
|
|
case "postgresql":
|
|
collection, err := c.database.GetPostgreSQLQueries().CreateCollection(context.Background(), postgresql.CreateCollectionParams{
|
|
ID: collectionID,
|
|
SiteID: siteID,
|
|
ContainerHtml: containerHTML,
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionItem{
|
|
ID: collection.ID,
|
|
SiteID: collection.SiteID,
|
|
ContainerHTML: collection.ContainerHtml,
|
|
LastEditedBy: collection.LastEditedBy,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// GetCollectionItems retrieves all items in a collection with template information
|
|
func (c *DatabaseClient) GetCollectionItems(siteID, collectionID string) ([]CollectionItemWithTemplate, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
items, err := c.database.GetSQLiteQueries().GetCollectionItemsWithTemplate(context.Background(), sqlite.GetCollectionItemsWithTemplateParams{
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]CollectionItemWithTemplate, len(items))
|
|
for i, item := range items {
|
|
result[i] = CollectionItemWithTemplate{
|
|
ItemID: item.ItemID,
|
|
CollectionID: item.CollectionID,
|
|
SiteID: item.SiteID,
|
|
TemplateID: int(item.TemplateID),
|
|
HTMLContent: item.HtmlContent,
|
|
Position: int(item.Position),
|
|
LastEditedBy: item.LastEditedBy,
|
|
TemplateName: item.TemplateName,
|
|
HTMLTemplate: item.HtmlTemplate,
|
|
IsDefault: item.IsDefault != 0, // SQLite uses INTEGER for boolean
|
|
}
|
|
}
|
|
return result, nil
|
|
|
|
case "postgresql":
|
|
items, err := c.database.GetPostgreSQLQueries().GetCollectionItemsWithTemplate(context.Background(), postgresql.GetCollectionItemsWithTemplateParams{
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]CollectionItemWithTemplate, len(items))
|
|
for i, item := range items {
|
|
result[i] = CollectionItemWithTemplate{
|
|
ItemID: item.ItemID,
|
|
CollectionID: item.CollectionID,
|
|
SiteID: item.SiteID,
|
|
TemplateID: int(item.TemplateID),
|
|
HTMLContent: item.HtmlContent,
|
|
Position: int(item.Position),
|
|
LastEditedBy: item.LastEditedBy,
|
|
TemplateName: item.TemplateName,
|
|
HTMLTemplate: item.HtmlTemplate,
|
|
IsDefault: item.IsDefault, // PostgreSQL uses BOOLEAN
|
|
}
|
|
}
|
|
return result, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// CreateCollectionTemplate creates a new template for a collection
|
|
func (c *DatabaseClient) CreateCollectionTemplate(siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
var isDefaultInt int64
|
|
if isDefault {
|
|
isDefaultInt = 1
|
|
}
|
|
|
|
template, err := c.database.GetSQLiteQueries().CreateCollectionTemplate(context.Background(), sqlite.CreateCollectionTemplateParams{
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
Name: name,
|
|
HtmlTemplate: htmlTemplate,
|
|
IsDefault: isDefaultInt,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionTemplateItem{
|
|
TemplateID: int(template.TemplateID),
|
|
CollectionID: template.CollectionID,
|
|
SiteID: template.SiteID,
|
|
Name: template.Name,
|
|
HTMLTemplate: template.HtmlTemplate,
|
|
IsDefault: template.IsDefault != 0,
|
|
}, nil
|
|
|
|
case "postgresql":
|
|
template, err := c.database.GetPostgreSQLQueries().CreateCollectionTemplate(context.Background(), postgresql.CreateCollectionTemplateParams{
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
Name: name,
|
|
HtmlTemplate: htmlTemplate,
|
|
IsDefault: isDefault,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionTemplateItem{
|
|
TemplateID: int(template.TemplateID),
|
|
CollectionID: template.CollectionID,
|
|
SiteID: template.SiteID,
|
|
Name: template.Name,
|
|
HTMLTemplate: template.HtmlTemplate,
|
|
IsDefault: template.IsDefault,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// GetCollectionTemplates retrieves all templates for a collection
|
|
func (c *DatabaseClient) GetCollectionTemplates(siteID, collectionID string) ([]CollectionTemplateItem, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
templates, err := c.database.GetSQLiteQueries().GetCollectionTemplates(context.Background(), sqlite.GetCollectionTemplatesParams{
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]CollectionTemplateItem, len(templates))
|
|
for i, template := range templates {
|
|
result[i] = CollectionTemplateItem{
|
|
TemplateID: int(template.TemplateID),
|
|
CollectionID: template.CollectionID,
|
|
SiteID: template.SiteID,
|
|
Name: template.Name,
|
|
HTMLTemplate: template.HtmlTemplate,
|
|
IsDefault: template.IsDefault != 0, // SQLite uses INTEGER for boolean
|
|
}
|
|
}
|
|
return result, nil
|
|
|
|
case "postgresql":
|
|
templates, err := c.database.GetPostgreSQLQueries().GetCollectionTemplates(context.Background(), postgresql.GetCollectionTemplatesParams{
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]CollectionTemplateItem, len(templates))
|
|
for i, template := range templates {
|
|
result[i] = CollectionTemplateItem{
|
|
TemplateID: int(template.TemplateID),
|
|
CollectionID: template.CollectionID,
|
|
SiteID: template.SiteID,
|
|
Name: template.Name,
|
|
HTMLTemplate: template.HtmlTemplate,
|
|
IsDefault: template.IsDefault, // PostgreSQL uses BOOLEAN
|
|
}
|
|
}
|
|
return result, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// CreateCollectionItem creates a new collection item
|
|
func (c *DatabaseClient) CreateCollectionItem(siteID, collectionID, itemID string, templateID int, htmlContent string, position int, lastEditedBy string) (*CollectionItemWithTemplate, error) {
|
|
switch c.database.GetDBType() {
|
|
case "sqlite3":
|
|
item, err := c.database.GetSQLiteQueries().CreateCollectionItem(context.Background(), sqlite.CreateCollectionItemParams{
|
|
ItemID: itemID,
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
TemplateID: int64(templateID),
|
|
HtmlContent: htmlContent,
|
|
Position: int64(position),
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionItemWithTemplate{
|
|
ItemID: item.ItemID,
|
|
CollectionID: item.CollectionID,
|
|
SiteID: item.SiteID,
|
|
TemplateID: int(item.TemplateID),
|
|
HTMLContent: item.HtmlContent,
|
|
Position: int(item.Position),
|
|
LastEditedBy: item.LastEditedBy,
|
|
}, nil
|
|
|
|
case "postgresql":
|
|
item, err := c.database.GetPostgreSQLQueries().CreateCollectionItem(context.Background(), postgresql.CreateCollectionItemParams{
|
|
ItemID: itemID,
|
|
CollectionID: collectionID,
|
|
SiteID: siteID,
|
|
TemplateID: int32(templateID),
|
|
HtmlContent: htmlContent,
|
|
Position: int32(position),
|
|
LastEditedBy: lastEditedBy,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &CollectionItemWithTemplate{
|
|
ItemID: item.ItemID,
|
|
CollectionID: item.CollectionID,
|
|
SiteID: item.SiteID,
|
|
TemplateID: int(item.TemplateID),
|
|
HTMLContent: item.HtmlContent,
|
|
Position: int(item.Position),
|
|
LastEditedBy: item.LastEditedBy,
|
|
}, nil
|
|
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
|
|
}
|
|
}
|
|
|
|
// CreateCollectionItemAtomic creates a collection item with all its content entries atomically
|
|
func (c *DatabaseClient) CreateCollectionItemAtomic(
|
|
siteID, collectionID string,
|
|
templateID int,
|
|
lastEditedBy string,
|
|
) (*CollectionItemWithTemplate, error) {
|
|
// Get template HTML for processing
|
|
templates, err := c.GetCollectionTemplates(siteID, collectionID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get templates: %w", err)
|
|
}
|
|
|
|
var templateHTML string
|
|
for _, template := range templates {
|
|
if template.TemplateID == templateID {
|
|
templateHTML = template.HTMLTemplate
|
|
break
|
|
}
|
|
}
|
|
|
|
if templateHTML == "" {
|
|
return nil, fmt.Errorf("template %d not found", templateID)
|
|
}
|
|
|
|
// Use unified engine approach (no more TemplateProcessor)
|
|
engine := NewContentEngine(c)
|
|
|
|
// Create collection item using unified engine method
|
|
return engine.CreateCollectionItemFromTemplate(
|
|
siteID, collectionID, templateID, templateHTML, lastEditedBy,
|
|
)
|
|
}
|