mirror of
https://github.com/btouchard/ackify-ce.git
synced 2026-02-07 22:39:46 -06:00
feat: migrate templates to embedded filesystem
- Move templates from web/templates/ to webtemplates/templates/ - Replace file-based template loading with Go embed - Remove external template directory dependency from Dockerfile - Add webtemplates package with embedded template functionality - Include comprehensive tests for embedded templates - Update server initialization to use new embedded template system This change makes the application self-contained by embedding templates directly in the binary, eliminating the need for external template files at runtime.
This commit is contained in:
@@ -51,7 +51,6 @@ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
# Set working directory and copy application files
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/ackify-ce /app/ackify-ce
|
||||
COPY --from=builder /app/web /app/web
|
||||
|
||||
# Use non-root user (already set in distroless image)
|
||||
# USER 65532:65532
|
||||
|
||||
@@ -6,11 +6,11 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"database/sql"
|
||||
"github.com/golang-migrate/migrate/v4"
|
||||
"github.com/golang-migrate/migrate/v4/database/postgres"
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
_ "github.com/lib/pq"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -101,4 +101,4 @@ func printUsage() {
|
||||
fmt.Println(" go run cmd/migrate/main.go up")
|
||||
fmt.Println(" go run cmd/migrate/main.go down 2")
|
||||
fmt.Println(" go run cmd/migrate/main.go version")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,4 +31,3 @@ func InitDB(ctx context.Context, config Config) (*sql.DB, error) {
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package templates
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// InitTemplates initializes the HTML templates from files
|
||||
func InitTemplates() (*template.Template, error) {
|
||||
// Get the templates directory path relative to the binary
|
||||
templatesDir := "web/templates"
|
||||
|
||||
// Parse the base template first
|
||||
tmpl, err := template.New("base").ParseFiles(filepath.Join(templatesDir, "base.html.tpl"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse base template: %w", err)
|
||||
}
|
||||
|
||||
// Parse the additional templates
|
||||
additionalTemplates := []string{"index.html.tpl", "sign.html.tpl", "signatures.html.tpl", "embed.html.tpl"}
|
||||
for _, templateFile := range additionalTemplates {
|
||||
_, err = tmpl.ParseFiles(filepath.Join(templatesDir, templateFile))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse template %s: %w", templateFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
return tmpl, nil
|
||||
}
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"github.com/btouchard/ackify-ce/internal/infrastructure/config"
|
||||
"github.com/btouchard/ackify-ce/internal/infrastructure/database"
|
||||
"github.com/btouchard/ackify-ce/internal/presentation/handlers"
|
||||
"github.com/btouchard/ackify-ce/internal/presentation/templates"
|
||||
"github.com/btouchard/ackify-ce/pkg/crypto"
|
||||
"github.com/btouchard/ackify-ce/webtemplates"
|
||||
)
|
||||
|
||||
// Server represents the Ackify CE web server
|
||||
@@ -123,7 +123,7 @@ func initInfrastructure(ctx context.Context) (*config.Config, *sql.DB, *template
|
||||
}
|
||||
|
||||
// Initialize templates
|
||||
tmpl, err := templates.InitTemplates()
|
||||
tmpl, err := webtemplates.InitTemplates()
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, fmt.Errorf("failed to initialize templates: %w", err)
|
||||
}
|
||||
|
||||
30
webtemplates/embed.go
Normal file
30
webtemplates/embed.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package webtemplates
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
//go:embed templates/*.tpl
|
||||
var TemplatesFS embed.FS
|
||||
|
||||
// InitTemplates initializes the HTML templates from embedded files
|
||||
func InitTemplates() (*template.Template, error) {
|
||||
// Parse the base template first
|
||||
tmpl, err := template.New("base").ParseFS(TemplatesFS, "templates/base.html.tpl")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse base template: %w", err)
|
||||
}
|
||||
|
||||
// Parse the additional templates
|
||||
additionalTemplates := []string{"templates/index.html.tpl", "templates/sign.html.tpl", "templates/signatures.html.tpl", "templates/embed.html.tpl"}
|
||||
for _, templateFile := range additionalTemplates {
|
||||
_, err = tmpl.ParseFS(TemplatesFS, templateFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse template %s: %w", templateFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
return tmpl, nil
|
||||
}
|
||||
54
webtemplates/embed_test.go
Normal file
54
webtemplates/embed_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package webtemplates
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTemplatesFS(t *testing.T) {
|
||||
// Test that the embedded filesystem contains the expected files
|
||||
expectedFiles := []string{
|
||||
"templates/base.html.tpl",
|
||||
"templates/index.html.tpl",
|
||||
"templates/sign.html.tpl",
|
||||
"templates/signatures.html.tpl",
|
||||
"templates/embed.html.tpl",
|
||||
}
|
||||
|
||||
for _, file := range expectedFiles {
|
||||
data, err := TemplatesFS.ReadFile(file)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to read embedded file %s: %v", file, err)
|
||||
}
|
||||
if len(data) == 0 {
|
||||
t.Errorf("Embedded file %s is empty", file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitTemplates(t *testing.T) {
|
||||
// Test that InitTemplates works correctly
|
||||
tmpl, err := InitTemplates()
|
||||
if err != nil {
|
||||
t.Fatalf("InitTemplates failed: %v", err)
|
||||
}
|
||||
|
||||
if tmpl == nil {
|
||||
t.Fatal("InitTemplates returned nil template")
|
||||
}
|
||||
|
||||
// Test that all expected templates are parsed
|
||||
expectedTemplateNames := []string{
|
||||
"base",
|
||||
"base.html.tpl",
|
||||
"index.html.tpl",
|
||||
"sign.html.tpl",
|
||||
"signatures.html.tpl",
|
||||
"embed.html.tpl",
|
||||
}
|
||||
|
||||
for _, name := range expectedTemplateNames {
|
||||
if tmpl.Lookup(name) == nil {
|
||||
t.Errorf("Template %s not found in parsed templates", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user