/* * SPDX-FileCopyrightText: 2023 jordi fita mas * SPDX-License-Identifier: AGPL-3.0-only */ package app import ( "net/http" "strings" "golang.org/x/text/language" "dev.tandem.ws/tandem/camper/pkg/auth" "dev.tandem.ws/tandem/camper/pkg/campsite" "dev.tandem.ws/tandem/camper/pkg/database" httplib "dev.tandem.ws/tandem/camper/pkg/http" "dev.tandem.ws/tandem/camper/pkg/locale" "dev.tandem.ws/tandem/camper/pkg/template" ) func methodNotAllowed(w http.ResponseWriter, _ *http.Request, allowed ...string) { w.Header().Set("Allow", strings.Join(allowed, ", ")) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } type App struct { db *database.DB fileHandler http.Handler profile *profileHandler campsite *campsite.Handler locales locale.Locales defaultLocale *locale.Locale languageMatcher language.Matcher } func New(db *database.DB, avatarsDir string) (http.Handler, error) { locales := locale.MustGetAll(db) static := http.FileServer(http.Dir("web/static")) profile, err := newProfileHandler(static, avatarsDir) if err != nil { return nil, err } app := &App{ db: db, fileHandler: static, profile: profile, campsite: campsite.NewHandler(), locales: locales, defaultLocale: locales[language.Catalan], languageMatcher: language.NewMatcher(locales.Tags()), } var handler http.Handler = app handler = httplib.RecoverPanic(handler) handler = httplib.LogRequest(handler) return handler, nil } func (h *App) ServeHTTP(w http.ResponseWriter, r *http.Request) { requestPath := r.URL.Path var head string head, r.URL.Path = httplib.ShiftPath(r.URL.Path) switch head { case "static": h.fileHandler.ServeHTTP(w, r) case "favicon.ico": r.URL.Path = requestPath h.fileHandler.ServeHTTP(w, r) default: conn, err := h.db.Acquire(r.Context()) if err != nil { panic(err) } defer conn.Release() user, err := h.getUser(r, conn) if err != nil { panic(err) } if head == "login" { switch r.Method { case http.MethodGet: serveLoginForm(w, r, user, "/") case http.MethodPost: handleLogin(w, r, user, conn) default: methodNotAllowed(w, r, http.MethodPost, http.MethodGet) } } else { if !user.LoggedIn { w.WriteHeader(http.StatusUnauthorized) serveLoginForm(w, r, user, requestPath) return } switch head { case "me": h.profile.Handler(user, conn).ServeHTTP(w, r) case "campsites": h.campsite.Handler(user, conn).ServeHTTP(w, r) case "": switch r.Method { case http.MethodGet: h.serveDashboard(w, r, user) default: methodNotAllowed(w, r, http.MethodGet) } default: http.NotFound(w, r) } } } } func (h *App) serveDashboard(w http.ResponseWriter, r *http.Request, user *auth.User) { template.MustRender(w, r, user, "dashboard.gohtml", nil) }