package api import ( "embed" "html/template" "net/http" "github.com/justinas/nosurf" "github.com/kindredsystems/silo/internal/auth" "github.com/rs/zerolog" ) //go:embed templates/*.html var templatesFS embed.FS // WebHandler serves HTML pages. type WebHandler struct { templates *template.Template logger zerolog.Logger server *Server } // NewWebHandler creates a new web handler. func NewWebHandler(logger zerolog.Logger, server *Server) (*WebHandler, error) { tmpl, err := template.ParseFS(templatesFS, "templates/*.html") if err != nil { return nil, err } wh := &WebHandler{ templates: tmpl, logger: logger, server: server, } // Store reference on server for auth handlers to use templates server.webHandler = wh return wh, nil } // PageData holds data for page rendering. type PageData struct { Title string Page string Data any User *auth.User CSRFToken string } // HandleIndex serves the main items page. func (h *WebHandler) HandleIndex(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } data := PageData{ Title: "Items", Page: "items", User: auth.UserFromContext(r.Context()), CSRFToken: nosurf.Token(r), } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := h.templates.ExecuteTemplate(w, "base.html", data); err != nil { h.logger.Error().Err(err).Msg("failed to render template") http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } // HandleProjectsPage serves the projects page. func (h *WebHandler) HandleProjectsPage(w http.ResponseWriter, r *http.Request) { data := PageData{ Title: "Projects", Page: "projects", User: auth.UserFromContext(r.Context()), CSRFToken: nosurf.Token(r), } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := h.templates.ExecuteTemplate(w, "base.html", data); err != nil { h.logger.Error().Err(err).Msg("failed to render template") http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } // HandleSchemasPage serves the schemas page. func (h *WebHandler) HandleSchemasPage(w http.ResponseWriter, r *http.Request) { data := PageData{ Title: "Schemas", Page: "schemas", User: auth.UserFromContext(r.Context()), CSRFToken: nosurf.Token(r), } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := h.templates.ExecuteTemplate(w, "base.html", data); err != nil { h.logger.Error().Err(err).Msg("failed to render template") http.Error(w, "Internal Server Error", http.StatusInternalServerError) } } // HandleAuditPage serves the component audit page. func (h *WebHandler) HandleAuditPage(w http.ResponseWriter, r *http.Request) { data := PageData{ Title: "Audit", Page: "audit", User: auth.UserFromContext(r.Context()), CSRFToken: nosurf.Token(r), } w.Header().Set("Content-Type", "text/html; charset=utf-8") if err := h.templates.ExecuteTemplate(w, "base.html", data); err != nil { h.logger.Error().Err(err).Msg("failed to render template") http.Error(w, "Internal Server Error", http.StatusInternalServerError) } }