Files
member-console/internal/server/render.go
Christian Galo 675a4d93a3 Buffer template rendering and fix FedWiki sync
Introduce SafeTemplates.Render to execute templates into a buffer and
prevent partial HTML on errors. Replace direct ExecuteTemplate calls in
partial handlers and add a make lint-templates target to catch bypasses.
Update operator sites template/view model to use OwnerOrgName. Guard the
FedWiki sync by skipping inserts when DefaultWorkspaceID is empty and
scope deletes to the configured default workspace only.
2026-03-29 04:58:02 -05:00

45 lines
1.7 KiB
Go

package server
import (
"bytes"
"html/template"
"log/slog"
"net/http"
)
// SafeTemplates wraps *html/template.Template to ensure all rendering goes
// through a buffer. This prevents partial HTML from being written to the
// response if template execution fails mid-way — the stdlib streams directly
// to the writer and cannot roll back a partial write.
//
// Handlers hold a *SafeTemplates instead of *template.Template. The underlying
// template set is unexported, so callers cannot bypass the buffer by calling
// ExecuteTemplate on the ResponseWriter directly — the compiler prevents it.
type SafeTemplates struct {
tmpl *template.Template
logger *slog.Logger
}
// NewSafeTemplates wraps tmpl and logger for safe buffered rendering.
func NewSafeTemplates(tmpl *template.Template, logger *slog.Logger) *SafeTemplates {
return &SafeTemplates{tmpl: tmpl, logger: logger}
}
// Render executes the named template into a buffer and writes it to w only on
// success. On failure it logs the error and writes a 500 error fragment,
// guaranteeing the response is never partial or truncated.
func (s *SafeTemplates) Render(w http.ResponseWriter, name string, data any) {
var buf bytes.Buffer
if err := s.tmpl.ExecuteTemplate(&buf, name, data); err != nil {
s.logger.Error("template execution failed",
slog.String("template", name),
slog.Any("error", err))
w.Header().Set("Content-Type", "text/html")
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(`<div class="alert alert-danger" role="alert"><strong>Error:</strong> Failed to render content. Please try again.</div>`))
return
}
w.Header().Set("Content-Type", "text/html")
w.Write(buf.Bytes())
}