- Move all ContentItem, ContentClient, ContentResponse types to engine/types.go as single source of truth - Remove duplicate type definitions from content/types.go - Update all imports across codebase to use engine types - Enhance engine to extract existing data-content-id from HTML markup - Simplify frontend to always send html_markup, let server handle ID extraction/generation - Fix contentId reference errors in frontend error handling - Add getAttribute helper method to engine for ID extraction - Add GetAllContent method to engine.DatabaseClient - Update enhancer to use engine.ContentClient interface - All builds and API endpoints verified working This resolves the 400 Bad Request errors and creates a unified architecture where the server is the single source of truth for all ID generation and content type management.
174 lines
4.6 KiB
Go
174 lines
4.6 KiB
Go
package content
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"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"
|
|
)
|
|
|
|
// DatabaseClient implements ContentClient for direct database access
|
|
type DatabaseClient struct {
|
|
db *db.Database
|
|
}
|
|
|
|
// NewDatabaseClient creates a new database content client
|
|
func NewDatabaseClient(database *db.Database) *DatabaseClient {
|
|
return &DatabaseClient{
|
|
db: database,
|
|
}
|
|
}
|
|
|
|
// GetContent fetches a single content item by ID
|
|
func (d *DatabaseClient) GetContent(siteID, contentID string) (*engine.ContentItem, error) {
|
|
ctx := context.Background()
|
|
var content interface{}
|
|
var err error
|
|
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
content, err = d.db.GetSQLiteQueries().GetContent(ctx, sqlite.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
case "postgresql":
|
|
content, err = d.db.GetPostgreSQLQueries().GetContent(ctx, postgresql.GetContentParams{
|
|
ID: contentID,
|
|
SiteID: siteID,
|
|
})
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
|
|
}
|
|
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil // Content not found, return nil without error
|
|
}
|
|
return nil, fmt.Errorf("database error: %w", err)
|
|
}
|
|
|
|
item := d.convertToContentItem(content)
|
|
return &item, nil
|
|
}
|
|
|
|
// GetBulkContent fetches multiple content items by IDs
|
|
func (d *DatabaseClient) GetBulkContent(siteID string, contentIDs []string) (map[string]engine.ContentItem, error) {
|
|
if len(contentIDs) == 0 {
|
|
return make(map[string]engine.ContentItem), nil
|
|
}
|
|
|
|
ctx := context.Background()
|
|
var dbContent interface{}
|
|
var err error
|
|
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
dbContent, err = d.db.GetSQLiteQueries().GetBulkContent(ctx, sqlite.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: contentIDs,
|
|
})
|
|
case "postgresql":
|
|
dbContent, err = d.db.GetPostgreSQLQueries().GetBulkContent(ctx, postgresql.GetBulkContentParams{
|
|
SiteID: siteID,
|
|
Ids: contentIDs,
|
|
})
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("database error: %w", err)
|
|
}
|
|
|
|
items := d.convertToContentItemList(dbContent)
|
|
|
|
// Convert slice to map for easy lookup
|
|
result := make(map[string]engine.ContentItem)
|
|
for _, item := range items {
|
|
result[item.ID] = item
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetAllContent fetches all content for a site
|
|
func (d *DatabaseClient) GetAllContent(siteID string) (map[string]engine.ContentItem, error) {
|
|
ctx := context.Background()
|
|
var dbContent interface{}
|
|
var err error
|
|
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
dbContent, err = d.db.GetSQLiteQueries().GetAllContent(ctx, siteID)
|
|
case "postgresql":
|
|
dbContent, err = d.db.GetPostgreSQLQueries().GetAllContent(ctx, siteID)
|
|
default:
|
|
return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
|
|
}
|
|
|
|
if err != nil {
|
|
return nil, fmt.Errorf("database error: %w", err)
|
|
}
|
|
|
|
items := d.convertToContentItemList(dbContent)
|
|
|
|
// Convert slice to map for easy lookup
|
|
result := make(map[string]engine.ContentItem)
|
|
for _, item := range items {
|
|
result[item.ID] = item
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// convertToContentItem converts database models to engine.ContentItem
|
|
func (d *DatabaseClient) convertToContentItem(content interface{}) engine.ContentItem {
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
c := content.(sqlite.Content)
|
|
return engine.ContentItem{
|
|
ID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
UpdatedAt: time.Unix(c.UpdatedAt, 0).Format(time.RFC3339),
|
|
}
|
|
case "postgresql":
|
|
c := content.(postgresql.Content)
|
|
return engine.ContentItem{
|
|
ID: c.ID,
|
|
SiteID: c.SiteID,
|
|
Value: c.Value,
|
|
Type: c.Type,
|
|
UpdatedAt: time.Unix(c.UpdatedAt, 0).Format(time.RFC3339),
|
|
}
|
|
}
|
|
return engine.ContentItem{} // Should never happen
|
|
}
|
|
|
|
// convertToContentItemList converts database model lists to engine.ContentItem slice
|
|
func (d *DatabaseClient) convertToContentItemList(contentList interface{}) []engine.ContentItem {
|
|
switch d.db.GetDBType() {
|
|
case "sqlite3":
|
|
list := contentList.([]sqlite.Content)
|
|
items := make([]engine.ContentItem, len(list))
|
|
for i, content := range list {
|
|
items[i] = d.convertToContentItem(content)
|
|
}
|
|
return items
|
|
case "postgresql":
|
|
list := contentList.([]postgresql.Content)
|
|
items := make([]engine.ContentItem, len(list))
|
|
for i, content := range list {
|
|
items[i] = d.convertToContentItem(content)
|
|
}
|
|
return items
|
|
}
|
|
return []engine.ContentItem{} // Should never happen
|
|
}
|