/* * SPDX-FileCopyrightText: 2023 jordi fita mas * SPDX-License-Identifier: AGPL-3.0-only */ package app import ( "context" "dev.tandem.ws/tandem/camper/pkg/media" "net/http" "golang.org/x/text/language" "dev.tandem.ws/tandem/camper/pkg/auth" "dev.tandem.ws/tandem/camper/pkg/database" httplib "dev.tandem.ws/tandem/camper/pkg/http" "dev.tandem.ws/tandem/camper/pkg/locale" ) type App struct { db *database.DB fileHandler http.Handler profile *profileHandler admin *adminHandler public *publicHandler media *media.PublicHandler locales locale.Locales defaultLocale *locale.Locale languageMatcher language.Matcher } func New(db *database.DB, avatarsDir string, mediaDir string) (http.Handler, error) { locales, err := locale.GetAll(context.Background(), db) if err != nil { return nil, err } static := http.FileServer(http.Dir("web/static")) profile, err := newProfileHandler(static, avatarsDir) if err != nil { return nil, err } mediaHandler, err := media.NewPublicHandler(mediaDir) if err != nil { return nil, err } app := &App{ db: db, fileHandler: static, profile: profile, admin: newAdminHandler(locales, mediaDir), public: newPublicHandler(), media: mediaHandler, 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) { 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 = head 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) } company, err := auth.CompanyByHost(r.Context(), conn, r.Host, h.locales) if database.ErrorIsNotFound(err) { http.NotFound(w, r) return } else if err != nil { panic(err) } switch head { case "": http.Redirect(w, r, "/"+user.Locale.Language.String()+"/", http.StatusFound) case "admin": h.admin.Handle(user, company, conn).ServeHTTP(w, r) case "login": switch r.Method { case http.MethodGet: if user.LoggedIn { httplib.Redirect(w, r, "/admin", http.StatusFound) } else { serveLoginForm(w, r, user, company, "/admin") } case http.MethodPost: handleLogin(w, r, user, company, conn) default: httplib.MethodNotAllowed(w, r, http.MethodPost, http.MethodGet) } case "me": h.profile.Handler(user, company, conn).ServeHTTP(w, r) case "media": h.media.Handler(user, company, conn).ServeHTTP(w, r) default: langTag, err := language.Parse(head) if err != nil { http.NotFound(w, r) return } urlLocale := h.locales[langTag] if urlLocale == nil { http.NotFound(w, r) return } user.Locale = urlLocale h.public.Handler(user, company, conn).ServeHTTP(w, r) } } }