Changed the templating engine to a custom one. First bugged working example

This commit is contained in:
Jonas Hahn
2025-08-23 10:43:06 +02:00
parent 19e4834a9e
commit c9a3196ccb
15 changed files with 215 additions and 125 deletions

View File

@@ -10,8 +10,6 @@ import (
"gorm.io/gorm"
)
type ctxData map[string]any
func getIndex(c *gin.Context) {
if getSessionUser(c) != nil {
c.Redirect(302, "/enter")
@@ -21,7 +19,7 @@ func getIndex(c *gin.Context) {
}
func getLogin(c *gin.Context) {
render(c, "login", ctxData{})
tm.Render(c, "login", gin.H{})
}
func postLogin(c *gin.Context) {
@@ -54,7 +52,7 @@ func postLogin(c *gin.Context) {
link := strings.TrimRight(baseURL, "/") + "/magic?token=" + token
log.Printf("[MAGIC LINK] %s for %s (valid until %s)\n", link, email, lt.ExpiresAt.Format(time.RFC3339))
render(c, "sent", ctxData{"Email": email})
tm.Render(c, "sent", gin.H{"Email": email})
}
func getMagic(c *gin.Context) {
@@ -98,7 +96,7 @@ func getEnter(c *gin.Context) {
if table != nil {
post = "/t/" + table.Slug + "/enter"
}
render(c, "enter", ctxData{"PostAction": post, "Table": table})
tm.Render(c, "enter", gin.H{"PostAction": post, "Table": table})
}
func postEnter(c *gin.Context) {
@@ -199,7 +197,7 @@ func getHistory(c *gin.Context) {
}
rows = append(rows, GRow{Game: g, PlayersA: a, PlayersB: b})
}
render(c, "history", ctxData{"Games": rows})
tm.Render(c, "history", gin.H{"Games": rows})
}
func getLeaderboard(c *gin.Context) {
@@ -265,7 +263,7 @@ func getLeaderboard(c *gin.Context) {
rows = rows[:100]
}
render(c, "leaderboard", ctxData{"Rows": rows})
tm.Render(c, "leaderboard", gin.H{"Rows": rows})
}
func getUserView(c *gin.Context) {
@@ -313,7 +311,7 @@ func getUserView(c *gin.Context) {
own = true
}
render(c, "user", ctxData{"Viewed": u, "Stats": st, "Own": own})
tm.Render(c, "user", gin.H{"Viewed": u, "Stats": st, "Own": own})
}
func getMe(c *gin.Context) {
@@ -322,7 +320,7 @@ func getMe(c *gin.Context) {
c.Redirect(302, "/login")
return
}
render(c, "user", ctxData{"Viewed": cu, "Stats": struct{ Games, Wins, Losses int }{0, 0, 0}, "Own": true})
tm.Render(c, "user", gin.H{"Viewed": cu, "Stats": struct{ Games, Wins, Losses int }{0, 0, 0}, "Own": true})
}
func postMe(c *gin.Context) {

View File

@@ -1,10 +1,8 @@
package main
import (
"html/template"
"log"
"os"
"time"
"github.com/gin-gonic/gin"
"gorm.io/driver/postgres"
@@ -24,11 +22,7 @@ const (
PORT = "18765"
)
// ===================== Templates =====================
var tpl = template.Must(template.New("").Funcs(template.FuncMap{
"fmtTime": func(t time.Time) string { return t.Local().Format("1000-01-01 10:10") },
}).ParseGlob("templates/*.html"))
var logger = log.Default()
// ===================== Main =====================

94
src/templates.go Normal file
View File

@@ -0,0 +1,94 @@
package main
import (
"fmt"
"html/template"
"log"
"os"
"path/filepath"
"time"
"github.com/gin-gonic/gin"
)
var tm *TemplateManager
func init() {
tm = NewTemplateManager("templates", "base", "html")
}
type TemplateManager struct {
templates map[string]*template.Template
funcs template.FuncMap
base string
ext string
dir string
}
// NewTemplateManager initializes the manager and loads templates
func NewTemplateManager(dir string, base string, ext string) *TemplateManager {
tm := &TemplateManager{
templates: make(map[string]*template.Template),
funcs: template.FuncMap{
"fmtTime": func(t time.Time) string {
return t.Local().Format("2006-01-02 15:04") // Gos reference time
},
},
base: base,
dir: dir,
ext: ext,
}
tm.LoadTemplates()
return tm
}
// LoadTemplates parses the base template with each view template in the directory
func (tm *TemplateManager) LoadTemplates() {
pattern := filepath.Join(tm.dir, "*."+tm.ext)
files, err := filepath.Glob(pattern)
if err != nil {
panic(err)
}
base := filepath.Join(tm.dir, tm.base+"."+tm.ext)
for _, file := range files {
if filepath.Base(file) == tm.base {
continue
}
name := stripAfterDot(filepath.Base(file))
logger.Println(name)
// Parse base + view template together
tpl, err := template.New(name).
Funcs(tm.funcs).
ParseFiles(base, file)
if err != nil {
panic(err)
}
tm.templates[name] = tpl
}
}
// Render executes a template by name into the given context
func (tm *TemplateManager) Render(c *gin.Context, name string, data gin.H) error {
print("\nRendering template:", name, "\n")
u := getSessionUser(c)
data["CurrentUser"] = u
tpl, ok := tm.templates[name]
if !ok {
return os.ErrNotExist
}
fmt.Print(tm.templates[name])
if err := tpl.ExecuteTemplate(c.Writer, tm.base, data); err != nil {
log.Println("tpl error:", err)
c.Status(500)
return err
}
return nil
}

View File

@@ -4,11 +4,8 @@ import (
"crypto/rand"
"encoding/hex"
"errors"
"log"
"strings"
"time"
"github.com/gin-gonic/gin"
)
func mustRandToken(n int) string {
@@ -118,15 +115,9 @@ func fmtSscanf(s, _ string, a *int) (int, error) {
return 1, nil
}
func render(c *gin.Context, name string, data ctxData) {
u := getSessionUser(c)
if data == nil {
data = ctxData{}
}
log.Println("tpl error:", name)
data["CurrentUser"] = u
if err := tpl.ExecuteTemplate(c.Writer, name, data); err != nil {
log.Println("tpl error:", err)
c.Status(500)
func stripAfterDot(s string) string {
if idx := strings.Index(s, "."); idx != -1 {
return s[:idx]
}
return s
}