155 lines
4.1 KiB
Go
155 lines
4.1 KiB
Go
package router
|
|
|
|
import (
|
|
"errors"
|
|
"io/fs"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"code.capytal.cc/capytal/comicverse/service"
|
|
"code.capytal.cc/capytal/comicverse/templates"
|
|
"code.capytal.cc/loreddev/smalltrip"
|
|
"code.capytal.cc/loreddev/smalltrip/middleware"
|
|
"code.capytal.cc/loreddev/smalltrip/multiplexer"
|
|
"code.capytal.cc/loreddev/smalltrip/problem"
|
|
"code.capytal.cc/loreddev/x/tinyssert"
|
|
)
|
|
|
|
type router struct {
|
|
userService *service.User
|
|
tokenService *service.Token
|
|
publicationService *service.Publication
|
|
|
|
templates templates.ITemplate
|
|
assets fs.FS
|
|
cache bool
|
|
|
|
assert tinyssert.Assertions
|
|
log *slog.Logger
|
|
}
|
|
|
|
func New(cfg Config) (http.Handler, error) {
|
|
if cfg.UserService == nil {
|
|
return nil, errors.New("user service is nil")
|
|
}
|
|
if cfg.TokenService == nil {
|
|
return nil, errors.New("token service is nil")
|
|
}
|
|
if cfg.PublicationService == nil {
|
|
return nil, errors.New("publication service is nil")
|
|
}
|
|
if cfg.Templates == nil {
|
|
return nil, errors.New("templates is nil")
|
|
}
|
|
if cfg.Assets == nil {
|
|
return nil, errors.New("static files is nil")
|
|
}
|
|
if cfg.Assertions == nil {
|
|
return nil, errors.New("assertions is nil")
|
|
}
|
|
if cfg.Logger == nil {
|
|
return nil, errors.New("logger is nil")
|
|
}
|
|
|
|
r := &router{
|
|
userService: cfg.UserService,
|
|
tokenService: cfg.TokenService,
|
|
publicationService: cfg.PublicationService,
|
|
|
|
templates: cfg.Templates,
|
|
assets: cfg.Assets,
|
|
cache: !cfg.DisableCache,
|
|
|
|
assert: cfg.Assertions,
|
|
log: cfg.Logger,
|
|
}
|
|
|
|
return r.setup(), nil
|
|
}
|
|
|
|
type Config struct {
|
|
UserService *service.User
|
|
TokenService *service.Token
|
|
PublicationService *service.Publication
|
|
|
|
Templates templates.ITemplate
|
|
Assets fs.FS
|
|
DisableCache bool
|
|
|
|
Assertions tinyssert.Assertions
|
|
Logger *slog.Logger
|
|
}
|
|
|
|
func (router *router) setup() http.Handler {
|
|
router.assert.NotNil(router.log)
|
|
router.assert.NotNil(router.assets)
|
|
|
|
log := router.log
|
|
|
|
log.Debug("Initializing router")
|
|
|
|
mux := multiplexer.New()
|
|
mux = multiplexer.WithFormMethod(mux, "x-method")
|
|
mux = multiplexer.WithPatternRules(mux,
|
|
multiplexer.EnsureMethod(),
|
|
multiplexer.EnsureStrictEnd(),
|
|
multiplexer.EnsureTrailingSlash(),
|
|
)
|
|
|
|
r := smalltrip.NewRouter(
|
|
smalltrip.WithMultiplexer(mux),
|
|
smalltrip.WithLogger(log.WithGroup("smalltrip")),
|
|
)
|
|
|
|
r.Use(middleware.Logger(log.WithGroup("requests")))
|
|
if router.cache {
|
|
r.Use(middleware.Cache())
|
|
} else {
|
|
r.Use(middleware.DisableCache())
|
|
}
|
|
|
|
r.Use(problem.PanicMiddleware())
|
|
// TODO: when the HandlerDevpage is completed on the problem package, we
|
|
// will provide it a custom template here:
|
|
// r.Use(problem.Middleware())
|
|
|
|
userController := newUserController(userControllerCfg{
|
|
UserService: router.userService,
|
|
TokenService: router.tokenService,
|
|
LoginPath: "/login/",
|
|
RedirectPath: "/",
|
|
Templates: router.templates,
|
|
Assert: router.assert,
|
|
})
|
|
publicationController := newPublicationController(router.publicationService, router.templates, router.assert)
|
|
|
|
r.Handle("GET /assets/{_file...}", http.StripPrefix("/assets/", http.FileServerFS(router.assets)))
|
|
|
|
r.Use(userController.userMiddleware)
|
|
|
|
r.HandleFunc("GET /{$}", func(w http.ResponseWriter, r *http.Request) {
|
|
// TODO: Add a way to the user to bypass this check and see the landing page.
|
|
// Probably a query parameter to bypass like "?landing=true"
|
|
if _, ok := NewUserContext(r.Context()).GetUserID(); ok {
|
|
publicationController.dashboard(w, r)
|
|
return
|
|
}
|
|
|
|
err := router.templates.ExecuteTemplate(w, "landing", nil)
|
|
if err != nil {
|
|
problem.NewInternalServerError(err).ServeHTTP(w, r)
|
|
}
|
|
})
|
|
|
|
r.HandleFunc("GET /login/{$}", userController.login)
|
|
r.HandleFunc("POST /login/{$}", userController.login)
|
|
r.HandleFunc("GET /register/{$}", userController.register)
|
|
r.HandleFunc("POST /register/{$}", userController.register)
|
|
|
|
// TODO: Provide/redirect short publication-id paths to long paths with the publication title as URL /publications/title-of-the-publication-<start of uuid>
|
|
r.HandleFunc("GET /publication/{publicationID}/{$}", publicationController.getPublication)
|
|
r.HandleFunc("POST /publication/{$}", publicationController.createPublication)
|
|
|
|
return r
|
|
}
|