Files
bds/modules/web/templates/templates.go
Matheus Sampaio Queiroga ad65c0a9b0 Refactor user management and server templates
- Removed old SQLite user schema and replaced it with a new structure that includes password handling and cookie management.
- Updated user.go to implement password encryption and user creation logic.
- Modified web templates to reflect the new server management system, including the removal of outdated templates and the addition of new server creation and listing functionalities.
- Introduced error handling templates for better user feedback on bad requests and server errors.
- Added a makefile for easier database setup and management with Docker.

Signed-off-by: Matheus Sampaio Queiroga <srherobrine20@gmail.com>
2025-05-09 22:03:06 -03:00

145 lines
3.4 KiB
Go

package templates
import (
"embed"
"fmt"
"html/template"
"io"
"io/fs"
"maps"
"net/http"
"path/filepath"
"runtime"
"slices"
"sirherobrine23.com.br/go-bds/bds/modules/datas/user"
)
// Templates files
//
//go:embed */*
var TemplatesFiles embed.FS
// Base to base/{head, footer and head_navbar}
type RenderData struct {
Title string
Lang string
PageIsInstall bool
User *user.User
External map[string]any
}
func (b RenderData) toRender(t *TemplateRender, stack []byte) map[string]any {
newData := map[string]any{}
maps.Insert(newData, maps.All(b.External))
newData["Title"] = b.Title
newData["Lang"] = b.Lang
newData["PageIsInstall"] = b.PageIsInstall
newData["User"] = b.User
newData["ShowTrace"] = t.ShowTrace
newData["Trace"] = string(stack)
return newData
}
// Struct with templates
type TemplateRender struct {
Root *template.Template
ShowTrace bool
}
// Load all templates and return [*TemplateRender] to process html templates
func Templates() (WebTemplate *TemplateRender, err error) {
WebTemplate = &TemplateRender{Root: template.New("root")}
err = fs.WalkDir(TemplatesFiles, ".", func(path string, d fs.DirEntry, err error) error {
if err == nil && !d.IsDir() {
var templateBody []byte
if templateBody, err = TemplatesFiles.ReadFile(path); err == nil {
tmpl := WebTemplate.Root.New(filepath.ToSlash(path))
_, err = tmpl.Parse(string(templateBody))
}
}
return err
})
return
}
// List all templates loaded into [*template.Template]
func (t *TemplateRender) Templates() (names []string) {
for _, tmpl := range t.Root.Templates() {
if tmpl.Name() == "root" {
continue
}
names = append(names, tmpl.Name())
}
slices.Sort(names)
return
}
// Render template
func (t *TemplateRender) Render(name string, w io.Writer, data *RenderData) error {
if !slices.Contains(t.Templates(), name) {
return fmt.Errorf("template not exists: %q", name)
} else if data == nil {
data = &RenderData{External: map[string]any{}}
}
return t.Root.Lookup(name).Execute(w, data.toRender(t, nil))
}
func (t *TemplateRender) Render400(w io.Writer, data *RenderData) {
if data == nil {
data = &RenderData{
Title: "Bad request",
Lang: "en-us",
PageIsInstall: false,
User: nil,
External: map[string]any{
"Error": "Bad request",
},
}
}
if httpWrite, ok := w.(http.ResponseWriter); ok {
httpWrite.WriteHeader(http.StatusBadRequest)
}
t.Root.Lookup("status/400.tmpl").Execute(w, data.toRender(t, nil))
}
// Render 404 page
func (t *TemplateRender) Render404(w io.Writer, data *RenderData) {
if data == nil {
data = &RenderData{
Title: "page not found",
Lang: "en-us",
PageIsInstall: false,
User: nil,
External: map[string]any{},
}
}
if httpWrite, ok := w.(http.ResponseWriter); ok {
httpWrite.WriteHeader(http.StatusNotFound)
}
t.Root.Lookup("status/404.tmpl").Execute(w, data.toRender(t, nil))
}
// Render Backend error with caller stack
func (t *TemplateRender) Render5xx(w io.Writer, data *RenderData) {
stackBuff := make([]byte, 1024)
for {
if n := runtime.Stack(stackBuff, false); n < len(stackBuff) {
stackBuff = stackBuff[:n]
break
}
stackBuff = make([]byte, 2*len(stackBuff))
}
if httpWrite, ok := w.(http.ResponseWriter); ok {
httpWrite.WriteHeader(http.StatusInternalServerError)
}
t.Root.Lookup("status/500.tmpl").Execute(w, data.toRender(t, stackBuff))
}