Complete API handlers refactoring to eliminate type switching and use repository pattern consistently
This commit is contained in:
@@ -6,8 +6,10 @@ import (
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/insertr/insertr/internal/config"
|
||||
"github.com/insertr/insertr/internal/db"
|
||||
"golang.org/x/net/html"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// Injector handles content injection into HTML elements
|
||||
@@ -15,19 +17,21 @@ type Injector struct {
|
||||
client db.ContentRepository
|
||||
siteID string
|
||||
authProvider *AuthProvider
|
||||
config *config.Config
|
||||
}
|
||||
|
||||
// NewInjector creates a new content injector
|
||||
func NewInjector(client db.ContentRepository, siteID string) *Injector {
|
||||
func NewInjector(client db.ContentRepository, siteID string, cfg *config.Config) *Injector {
|
||||
return &Injector{
|
||||
client: client,
|
||||
siteID: siteID,
|
||||
authProvider: &AuthProvider{Type: "mock"}, // default
|
||||
config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInjectorWithAuth creates a new content injector with auth provider
|
||||
func NewInjectorWithAuth(client db.ContentRepository, siteID string, authProvider *AuthProvider) *Injector {
|
||||
func NewInjectorWithAuth(client db.ContentRepository, siteID string, authProvider *AuthProvider, cfg *config.Config) *Injector {
|
||||
if authProvider == nil {
|
||||
authProvider = &AuthProvider{Type: "mock"}
|
||||
}
|
||||
@@ -35,6 +39,7 @@ func NewInjectorWithAuth(client db.ContentRepository, siteID string, authProvide
|
||||
client: client,
|
||||
siteID: siteID,
|
||||
authProvider: authProvider,
|
||||
config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +205,7 @@ func (i *Injector) setAttribute(node *html.Node, key, value string) {
|
||||
// Remove existing attribute if present
|
||||
for idx, attr := range node.Attr {
|
||||
if attr.Key == key {
|
||||
node.Attr = append(node.Attr[:idx], node.Attr[idx+1:]...)
|
||||
node.Attr = slices.Delete(node.Attr, idx, idx+1)
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -232,10 +237,8 @@ func (i *Injector) addClass(node *html.Node, className string) {
|
||||
}
|
||||
|
||||
// Check if class already exists
|
||||
for _, class := range classes {
|
||||
if class == className {
|
||||
return // Class already exists
|
||||
}
|
||||
if slices.Contains(classes, className) {
|
||||
return // Class already exists
|
||||
}
|
||||
|
||||
// Add new class
|
||||
@@ -327,8 +330,15 @@ func (i *Injector) InjectEditorScript(doc *html.Node) {
|
||||
if i.authProvider != nil {
|
||||
authProvider = i.authProvider.Type
|
||||
}
|
||||
insertrHTML := fmt.Sprintf(`<link rel="stylesheet" href="http://localhost:8080/insertr.css" data-insertr-injected="true">
|
||||
<script src="http://localhost:8080/insertr.js" data-insertr-injected="true" data-site-id="%s" data-api-endpoint="http://localhost:8080/api/content" data-auth-provider="%s" data-debug="true"></script>`, i.siteID, authProvider)
|
||||
|
||||
// Generate configurable URLs for library assets
|
||||
cssURL := i.getLibraryURL("insertr.css")
|
||||
jsURL := i.getLibraryURL("insertr.js")
|
||||
apiURL := i.getAPIURL()
|
||||
|
||||
insertrHTML := fmt.Sprintf(`<link rel="stylesheet" href="%s" data-insertr-injected="true">
|
||||
<script src="%s" data-insertr-injected="true" data-site-id="%s" data-api-endpoint="%s" data-auth-provider="%s" data-debug="%t"></script>`,
|
||||
cssURL, jsURL, i.siteID, apiURL, authProvider, i.isDebugMode())
|
||||
|
||||
// Parse and inject the CSS and script elements
|
||||
insertrDoc, err := html.Parse(strings.NewReader(insertrHTML))
|
||||
@@ -346,38 +356,6 @@ func (i *Injector) InjectEditorScript(doc *html.Node) {
|
||||
log.Printf("✅ Insertr.js library injected with site configuration")
|
||||
}
|
||||
|
||||
// injectAllScriptElements finds and injects all script elements from parsed HTML
|
||||
func (i *Injector) injectAllScriptElements(doc *html.Node, targetNode *html.Node) error {
|
||||
scripts := i.findAllScriptElements(doc)
|
||||
|
||||
for _, script := range scripts {
|
||||
// Remove from original parent
|
||||
if script.Parent != nil {
|
||||
script.Parent.RemoveChild(script)
|
||||
}
|
||||
// Add to target node
|
||||
targetNode.AppendChild(script)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findAllScriptElements recursively finds all script elements
|
||||
func (i *Injector) findAllScriptElements(node *html.Node) []*html.Node {
|
||||
var scripts []*html.Node
|
||||
|
||||
if node.Type == html.ElementNode && node.Data == "script" {
|
||||
scripts = append(scripts, node)
|
||||
}
|
||||
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
childScripts := i.findAllScriptElements(child)
|
||||
scripts = append(scripts, childScripts...)
|
||||
}
|
||||
|
||||
return scripts
|
||||
}
|
||||
|
||||
// injectAllHeadElements finds and injects all head elements (link, script) from parsed HTML
|
||||
func (i *Injector) injectAllHeadElements(doc *html.Node, targetNode *html.Node) error {
|
||||
elements := i.findAllHeadElements(doc)
|
||||
@@ -479,15 +457,69 @@ func (i *Injector) extractElementByClass(node *html.Node, className string) *htm
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractElementByTag finds element with specific tag
|
||||
func (i *Injector) extractElementByTag(node *html.Node, tagName string) *html.Node {
|
||||
if node.Type == html.ElementNode && node.Data == tagName {
|
||||
return node
|
||||
// getLibraryURL returns the appropriate URL for library assets (CSS/JS)
|
||||
func (i *Injector) getLibraryURL(filename string) string {
|
||||
if i.config == nil {
|
||||
// Fallback to localhost if no config
|
||||
return fmt.Sprintf("http://localhost:8080/%s", filename)
|
||||
}
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
if result := i.extractElementByTag(child, tagName); result != nil {
|
||||
return result
|
||||
|
||||
// Check if we should use CDN
|
||||
if i.config.Library.UseCDN && i.config.Library.CDNBaseURL != "" {
|
||||
// Production: Use CDN
|
||||
suffix := ""
|
||||
if i.config.Library.Minified && filename == "insertr.js" {
|
||||
suffix = ".min"
|
||||
}
|
||||
baseName := strings.TrimSuffix(filename, ".js")
|
||||
baseName = strings.TrimSuffix(baseName, ".css")
|
||||
return fmt.Sprintf("%s@%s/dist/%s%s", i.config.Library.CDNBaseURL, i.config.Library.Version, baseName, suffix+getFileExtension(filename))
|
||||
}
|
||||
return nil
|
||||
|
||||
// Development: Use local server
|
||||
baseURL := i.config.Library.BaseURL
|
||||
if baseURL == "" {
|
||||
baseURL = fmt.Sprintf("http://localhost:%d", i.config.Server.Port)
|
||||
}
|
||||
|
||||
suffix := ""
|
||||
if i.config.Library.Minified && filename == "insertr.js" {
|
||||
suffix = ".min"
|
||||
}
|
||||
baseName := strings.TrimSuffix(filename, ".js")
|
||||
baseName = strings.TrimSuffix(baseName, ".css")
|
||||
return fmt.Sprintf("%s/%s%s", baseURL, baseName, suffix+getFileExtension(filename))
|
||||
}
|
||||
|
||||
// getAPIURL returns the API endpoint URL
|
||||
func (i *Injector) getAPIURL() string {
|
||||
if i.config == nil {
|
||||
return "http://localhost:8080/api/content"
|
||||
}
|
||||
|
||||
baseURL := i.config.Library.BaseURL
|
||||
if baseURL == "" {
|
||||
baseURL = fmt.Sprintf("http://localhost:%d", i.config.Server.Port)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s/api/content", baseURL)
|
||||
}
|
||||
|
||||
// isDebugMode returns true if in development mode
|
||||
func (i *Injector) isDebugMode() bool {
|
||||
if i.config == nil {
|
||||
return true
|
||||
}
|
||||
return i.config.Auth.DevMode
|
||||
}
|
||||
|
||||
// getFileExtension returns the file extension including the dot
|
||||
func getFileExtension(filename string) string {
|
||||
if strings.HasSuffix(filename, ".js") {
|
||||
return ".js"
|
||||
}
|
||||
if strings.HasSuffix(filename, ".css") {
|
||||
return ".css"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user