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 }