I realized that locales should be company-dependent: we could have two companies that show pages in a different subset of the application locales. It is not the case now, because despite being a “multicompany application”, it is intended for a single customer, but still makes sense to include it in Company, even if the subset is the same set as the application’s.
123 lines
2.9 KiB
Go
123 lines
2.9 KiB
Go
/*
|
|
* SPDX-FileCopyrightText: 2023 jordi fita mas <jfita@peritasoft.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"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
|
|
locales locale.Locales
|
|
defaultLocale *locale.Locale
|
|
languageMatcher language.Matcher
|
|
}
|
|
|
|
func New(db *database.DB, avatarsDir 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
|
|
}
|
|
app := &App{
|
|
db: db,
|
|
fileHandler: static,
|
|
profile: profile,
|
|
admin: newAdminHandler(),
|
|
public: newPublicHandler(),
|
|
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)
|
|
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)
|
|
}
|
|
}
|
|
}
|