• Add full multi-table schema for collections with normalized design (collections, collection_templates, collection_items, collection_item_versions) • Implement collection detection and processing in enhancement pipeline for .insertr-add elements • Add template extraction and storage from existing HTML children with multi-variant support • Enable collection reconstruction from database on server restart with proper DOM rebuilding • Extend ContentClient interface with collection operations and full database integration • Update enhance command to use engine.DatabaseClient for collection persistence support
191 lines
5.2 KiB
Go
191 lines
5.2 KiB
Go
package content
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/insertr/insertr/internal/engine"
|
|
)
|
|
|
|
// HTTPClient implements ContentClient for HTTP API access
|
|
type HTTPClient struct {
|
|
BaseURL string
|
|
APIKey string
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
// NewHTTPClient creates a new HTTP content client
|
|
func NewHTTPClient(baseURL, apiKey string) *HTTPClient {
|
|
return &HTTPClient{
|
|
BaseURL: strings.TrimSuffix(baseURL, "/"),
|
|
APIKey: apiKey,
|
|
HTTPClient: &http.Client{
|
|
Timeout: 30 * time.Second,
|
|
},
|
|
}
|
|
}
|
|
|
|
// GetContent fetches a single content item by ID
|
|
func (c *HTTPClient) GetContent(siteID, contentID string) (*engine.ContentItem, error) {
|
|
url := fmt.Sprintf("%s/api/content/%s?site_id=%s", c.BaseURL, contentID, siteID)
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating request: %w", err)
|
|
}
|
|
|
|
if c.APIKey != "" {
|
|
req.Header.Set("Authorization", "Bearer "+c.APIKey)
|
|
}
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("making request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode == 404 {
|
|
return nil, nil // Content not found, return nil without error
|
|
}
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, fmt.Errorf("API error: %s", resp.Status)
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading response: %w", err)
|
|
}
|
|
|
|
var item engine.ContentItem
|
|
if err := json.Unmarshal(body, &item); err != nil {
|
|
return nil, fmt.Errorf("parsing response: %w", err)
|
|
}
|
|
|
|
return &item, nil
|
|
}
|
|
|
|
// GetBulkContent fetches multiple content items by IDs
|
|
func (c *HTTPClient) GetBulkContent(siteID string, contentIDs []string) (map[string]engine.ContentItem, error) {
|
|
if len(contentIDs) == 0 {
|
|
return make(map[string]engine.ContentItem), nil
|
|
}
|
|
|
|
// Build query parameters
|
|
params := url.Values{}
|
|
params.Set("site_id", siteID)
|
|
for _, id := range contentIDs {
|
|
params.Add("ids", id)
|
|
}
|
|
|
|
url := fmt.Sprintf("%s/api/content/bulk?%s", c.BaseURL, params.Encode())
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating request: %w", err)
|
|
}
|
|
|
|
if c.APIKey != "" {
|
|
req.Header.Set("Authorization", "Bearer "+c.APIKey)
|
|
}
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("making request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, fmt.Errorf("API error: %s", resp.Status)
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading response: %w", err)
|
|
}
|
|
|
|
var response engine.ContentResponse
|
|
if err := json.Unmarshal(body, &response); err != nil {
|
|
return nil, fmt.Errorf("parsing response: %w", err)
|
|
}
|
|
|
|
// Convert slice to map for easy lookup
|
|
result := make(map[string]engine.ContentItem)
|
|
for _, item := range response.Content {
|
|
result[item.ID] = item
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetAllContent fetches all content for a site
|
|
func (c *HTTPClient) GetAllContent(siteID string) (map[string]engine.ContentItem, error) {
|
|
url := fmt.Sprintf("%s/api/content?site_id=%s", c.BaseURL, siteID)
|
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("creating request: %w", err)
|
|
}
|
|
|
|
if c.APIKey != "" {
|
|
req.Header.Set("Authorization", "Bearer "+c.APIKey)
|
|
}
|
|
|
|
resp, err := c.HTTPClient.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("making request: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, fmt.Errorf("API error: %s", resp.Status)
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading response: %w", err)
|
|
}
|
|
|
|
var response engine.ContentResponse
|
|
if err := json.Unmarshal(body, &response); err != nil {
|
|
return nil, fmt.Errorf("parsing response: %w", err)
|
|
}
|
|
|
|
// Convert slice to map for easy lookup
|
|
result := make(map[string]engine.ContentItem)
|
|
for _, item := range response.Content {
|
|
result[item.ID] = item
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// CreateContent creates a new content item via HTTP API
|
|
func (c *HTTPClient) CreateContent(siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*engine.ContentItem, error) {
|
|
// For now, HTTPClient CreateContent is not implemented for enhancer use
|
|
// This would typically be used in API-driven enhancement scenarios
|
|
return nil, fmt.Errorf("CreateContent not implemented for HTTPClient - use DatabaseClient for enhancement")
|
|
}
|
|
|
|
// Collection method stubs - TODO: Implement these for HTTP API
|
|
func (c *HTTPClient) GetCollection(siteID, collectionID string) (*engine.CollectionItem, error) {
|
|
return nil, fmt.Errorf("collection operations not implemented in HTTPClient")
|
|
}
|
|
|
|
func (c *HTTPClient) CreateCollection(siteID, collectionID, containerHTML, lastEditedBy string) (*engine.CollectionItem, error) {
|
|
return nil, fmt.Errorf("collection operations not implemented in HTTPClient")
|
|
}
|
|
|
|
func (c *HTTPClient) GetCollectionItems(siteID, collectionID string) ([]engine.CollectionItemWithTemplate, error) {
|
|
return nil, fmt.Errorf("collection operations not implemented in HTTPClient")
|
|
}
|
|
|
|
func (c *HTTPClient) CreateCollectionTemplate(siteID, collectionID, name, htmlTemplate string, isDefault bool) (*engine.CollectionTemplateItem, error) {
|
|
return nil, fmt.Errorf("collection operations not implemented in HTTPClient")
|
|
}
|