HN-like selfhosted forums
package appimport ( "embed" "html/template" "io/fs" "net/http" "github.com/nxrmqlly/district/auth" "github.com/nxrmqlly/district/store")// Router handles routes and templates. It implements http.Handlertype Router struct { mux *http.ServeMux queries *store.Queries templates *template.Template auth *auth.Service GlobalMws []Middleware}func NewRouter(queries *store.Queries) (*Router, error) { tmpl, err := parseTemplates() if err != nil { return nil, err } ro := Router{ mux: http.NewServeMux(), queries: queries, templates: tmpl, auth: auth.New(queries), } err = ro.routes() if err != nil { return nil, err } return &ro, nil}//go:embed staticvar staticFS embed.FSfunc (ro *Router) routes() error { csrf := http.NewCrossOriginProtection() ro.GlobalMws = append(ro.GlobalMws, ro.Logging, // the csrf handler should ideally go after logging, csrf.Handler, // so caught 403s are logged. ro.Authentication, // generic auth ) staticFS, err := fs.Sub(staticFS, "static") if err != nil { return err } ro.mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServerFS(staticFS))) ro.Handle("GET /{$}", ro.handleHome) ro.Handle("GET /submit", ro.handleSubmitView, ro.RequireAuthRedirect) ro.Handle("POST /submit", ro.handleSubmitCreate, ro.RequireAuth) ro.Handle("GET /p/{id}", ro.handlePostGet) ro.Handle("POST /p/{id}/comment", ro.handleCommentCreate, ro.RequireAuth) ro.Handle("GET /login", ro.handleLoginView) ro.Handle("POST /login", ro.handleLogin) ro.Handle("GET /register", ro.handleRegisterView) ro.Handle("POST /register", ro.handleRegister) ro.Handle("POST /logout", ro.handleLogout, ro.RequireAuth) return nil}func (ro *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) { ro.mux.ServeHTTP(w, r)}func (ro *Router) Handle(pattern string, f http.HandlerFunc, mws ...Middleware) { ro.mux.Handle(pattern, Chain(f, append(ro.GlobalMws, mws...)...))}