Files
kls/handler.go
Kyle Isom 131924520d Remove unused template init (fix startup crash)
The global template.Must parse at init time was left over from the
basic auth version. web.RenderTemplate handles parsing per-request.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 18:15:46 -07:00

137 lines
3.3 KiB
Go

package main
import (
"context"
"database/sql"
"embed"
"net/http"
"strings"
"git.wntrmute.dev/mc/mcdsl/auth"
"git.wntrmute.dev/mc/mcdsl/csrf"
"git.wntrmute.dev/mc/mcdsl/web"
"git.wntrmute.dev/kyle/kls/links"
"github.com/go-chi/chi/v5"
)
type server struct {
db *sql.DB
auth *auth.Authenticator
csrf *csrf.Protect
}
//go:embed templates/*.html
var templateFiles embed.FS
//go:embed static
var staticFiles embed.FS
type page struct {
Username string
Short string
URLs []*links.URL
}
func (srv *server) handleLoginPage(w http.ResponseWriter, r *http.Request) {
web.RenderTemplate(w, templateFiles, "login.html", page{}, srv.csrf.TemplateFunc(w))
}
func (srv *server) handleLogin(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("username")
password := r.FormValue("password")
totpCode := r.FormValue("totp_code")
token, _, err := srv.auth.Login(username, password, totpCode)
if err != nil {
web.RenderTemplate(w, templateFiles, "login.html", page{Short: "Invalid credentials"}, srv.csrf.TemplateFunc(w))
return
}
web.SetSessionCookie(w, cookieName, token)
http.Redirect(w, r, "/", http.StatusFound)
}
func (srv *server) handleLogout(w http.ResponseWriter, r *http.Request) {
token := web.GetSessionToken(r, cookieName)
if token != "" {
_ = srv.auth.Logout(token)
}
web.ClearSessionCookie(w, cookieName)
http.Redirect(w, r, "/login", http.StatusFound)
}
func (srv *server) handleIndex(w http.ResponseWriter, r *http.Request) {
info := auth.TokenInfoFromContext(r.Context())
web.RenderTemplate(w, templateFiles, "index.html", page{Username: info.Username}, srv.csrf.TemplateFunc(w))
}
func (srv *server) postURL(w http.ResponseWriter, r *http.Request) {
info := auth.TokenInfoFromContext(r.Context())
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
stripQuery := boolean(r.FormValue("strip"))
url := r.FormValue("value")
if len(url) == 0 {
http.Error(w, "invalid URL", http.StatusBadRequest)
return
}
url, err = links.CleanString(url, stripQuery)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
ctx := context.Background()
short, err := links.StoreURL(ctx, srv.db, url)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
web.RenderTemplate(w, templateFiles, "index.html", page{Username: info.Username, Short: short}, srv.csrf.TemplateFunc(w))
}
func (srv *server) redirect(w http.ResponseWriter, r *http.Request) {
short := chi.URLParam(r, "short")
if short == "" {
short = strings.TrimPrefix(r.URL.Path, "/")
}
u, err := links.RetrieveURL(context.Background(), srv.db, short)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
http.Redirect(w, r, u, http.StatusFound)
}
func (srv *server) listAll(w http.ResponseWriter, r *http.Request) {
info := auth.TokenInfoFromContext(r.Context())
allPosts, err := links.FetchAll(context.Background(), srv.db)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
web.RenderTemplate(w, templateFiles, "list.html", page{
Username: info.Username,
URLs: allPosts,
}, srv.csrf.TemplateFunc(w))
}
func boolean(s string) bool {
switch s {
case "on", "true", "True", "yes", "Yes":
return true
default:
return false
}
}