This commit is contained in:
lfirmin
2026-05-10 18:07:51 +02:00
parent 50af2452b1
commit a5f888b3c1
59 changed files with 6682 additions and 108 deletions
+91
View File
@@ -0,0 +1,91 @@
package handlers
import (
"html/template"
"net/http"
"github.com/leolionad58/ticketbot/internal/db"
panelauth "github.com/leolionad58/ticketbot/internal/panel/auth"
)
// ParseFunc is the signature of panel.ParseTemplates — injected to avoid import cycles.
type ParseFunc func(names ...string) (*template.Template, error)
// Renderer provides renderAuth and renderPage to handlers without importing the panel package.
type Renderer struct {
parse ParseFunc
getBotStatus func() BotStatus
}
// NewRenderer creates a Renderer backed by the given parse function.
func NewRenderer(f ParseFunc) *Renderer { return &Renderer{parse: f} }
// SetBotStatus wires a live bot-status function so BotOnline is set on every page.
func (rnd *Renderer) SetBotStatus(fn func() BotStatus) { rnd.getBotStatus = fn }
// base builds baseData with BotOnline populated from the live bot status.
func (rnd *Renderer) base(r *http.Request, active string) baseData {
b := newBase(r, active)
if rnd.getBotStatus != nil {
b.BotOnline = rnd.getBotStatus().Online
}
return b
}
func (rnd *Renderer) Auth(w http.ResponseWriter, page string, data any) {
t, err := rnd.parse("auth_layout.html", page+".html")
if err != nil {
http.Error(w, "template error: "+err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := t.ExecuteTemplate(w, "auth_layout", data); err != nil {
http.Error(w, "render error: "+err.Error(), http.StatusInternalServerError)
}
}
func (rnd *Renderer) Page(w http.ResponseWriter, page string, data any) {
t, err := rnd.parse("layout.html", page+".html")
if err != nil {
http.Error(w, "template error: "+err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := t.ExecuteTemplate(w, "layout", data); err != nil {
http.Error(w, "render error: "+err.Error(), http.StatusInternalServerError)
}
}
type baseData struct {
CSRFToken string
Admin *db.PanelAdmin
ActivePage string
BotOnline bool
Flash string
Error string
}
func newBase(r *http.Request, active string) baseData {
sess := panelauth.SessionFromContext(r.Context())
admin := panelauth.AdminFromContext(r.Context())
csrf := ""
if sess != nil {
csrf = sess.CSRFToken
}
return baseData{
CSRFToken: csrf,
Admin: admin,
ActivePage: active,
Flash: r.URL.Query().Get("flash"),
}
}
func clientIP(r *http.Request) string {
if ip := r.Header.Get("X-Real-IP"); ip != "" {
return ip
}
if ip := r.Header.Get("X-Forwarded-For"); ip != "" {
return ip
}
return r.RemoteAddr
}