base dashboard and login
This commit is contained in:
@@ -5,12 +5,14 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"crowdsec-dashy/internal/crowdsec"
|
||||
"crowdsec-dashy/internal/middleware"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -23,33 +25,46 @@ type Renderer struct {
|
||||
funcMap template.FuncMap
|
||||
}
|
||||
|
||||
// NewRenderer parses all page templates against the base layout.
|
||||
func NewRenderer(templateDir string) (*Renderer, error) {
|
||||
// bareLayoutPages lists page names that use base_bare.html instead of base.html.
|
||||
var bareLayoutPages = map[string]bool{
|
||||
"login": true,
|
||||
}
|
||||
|
||||
// NewRenderer parses all page templates. Most pages use the sidebar layout
|
||||
// (base.html); pages listed in bareLayoutPages use the bare layout (base_bare.html).
|
||||
func NewRenderer(fsys fs.FS) (*Renderer, error) {
|
||||
r := &Renderer{
|
||||
templates: make(map[string]*template.Template),
|
||||
funcMap: buildFuncMap(),
|
||||
}
|
||||
|
||||
basePath := filepath.Join(templateDir, "layouts", "base.html")
|
||||
const (
|
||||
basePath = "templates/layouts/base.html"
|
||||
barePath = "templates/layouts/base_bare.html"
|
||||
)
|
||||
|
||||
pages, err := filepath.Glob(filepath.Join(templateDir, "pages", "*.html"))
|
||||
pages, err := fs.Glob(fsys, "templates/pages/*.html")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("renderer: glob pages: %w", err)
|
||||
}
|
||||
if len(pages) == 0 {
|
||||
return nil, fmt.Errorf("renderer: no page templates found in %s/pages/", templateDir)
|
||||
return nil, fmt.Errorf("renderer: no page templates found")
|
||||
}
|
||||
|
||||
for _, page := range pages {
|
||||
name := templateName(page)
|
||||
tmpl, err := template.New("base").
|
||||
layout := basePath
|
||||
if bareLayoutPages[name] {
|
||||
layout = barePath
|
||||
}
|
||||
tmpl, err := template.New(path.Base(page)).
|
||||
Funcs(r.funcMap).
|
||||
ParseFiles(basePath, page)
|
||||
ParseFS(fsys, layout, page)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("renderer: parse %s: %w", name, err)
|
||||
}
|
||||
r.templates[name] = tmpl
|
||||
log.Printf("renderer: registered template %q", name)
|
||||
log.Printf("renderer: registered template %q (layout: %s)", name, path.Base(layout))
|
||||
}
|
||||
|
||||
return r, nil
|
||||
@@ -64,7 +79,7 @@ func (r *Renderer) Render(w http.ResponseWriter, name string, data any) {
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.ExecuteTemplate(&buf, "base", data); err != nil {
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
log.Printf("renderer: execute %q: %v", name, err)
|
||||
http.Error(w, "internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
@@ -84,9 +99,9 @@ func (r *Renderer) RenderError(w http.ResponseWriter, code int, msg string) {
|
||||
})
|
||||
}
|
||||
|
||||
func templateName(path string) string {
|
||||
base := filepath.Base(path)
|
||||
return base[:len(base)-len(filepath.Ext(base))]
|
||||
func templateName(p string) string {
|
||||
base := path.Base(p)
|
||||
return base[:len(base)-len(path.Ext(base))]
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -206,6 +221,7 @@ type PageData struct {
|
||||
Flash FlashMessage
|
||||
CLIAvailable bool
|
||||
PollInterval int
|
||||
CSRFToken string
|
||||
}
|
||||
|
||||
// FlashMessage is a one-shot notification shown on the next page load.
|
||||
@@ -229,6 +245,7 @@ func NewPageData(r *http.Request, title string, cliAvail bool, pollSec int) Page
|
||||
Nav: SidebarNav,
|
||||
CLIAvailable: cliAvail,
|
||||
PollInterval: pollSec,
|
||||
CSRFToken: middleware.CSRFFromContext(r),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user