homebox/backend/app/api/routes.go

172 lines
5.4 KiB
Go
Raw Normal View History

2022-08-30 02:30:36 +00:00
package main
import (
2022-09-04 02:42:03 +00:00
"embed"
"errors"
2022-08-30 02:30:36 +00:00
"fmt"
2022-09-04 02:42:03 +00:00
"io"
"mime"
2022-08-30 02:30:36 +00:00
"net/http"
2022-09-04 02:42:03 +00:00
"path"
"path/filepath"
2022-08-30 02:30:36 +00:00
"github.com/go-chi/chi/v5"
_ "github.com/hay-kot/homebox/backend/app/api/docs"
v1 "github.com/hay-kot/homebox/backend/app/api/v1"
"github.com/hay-kot/homebox/backend/internal/repo"
2022-09-04 02:42:03 +00:00
"github.com/rs/zerolog/log"
2022-08-30 02:30:36 +00:00
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
)
const prefix = "/api"
2022-09-04 03:11:37 +00:00
var (
ErrDir = errors.New("path is dir")
//go:embed all:public/*
public embed.FS
)
2022-08-30 02:30:36 +00:00
// registerRoutes registers all the routes for the API
func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
2022-09-04 03:10:42 +00:00
registerMimes()
2022-08-30 02:30:36 +00:00
r := chi.NewRouter()
a.setGlobalMiddleware(r)
r.Get("/swagger/*", httpSwagger.Handler(
httpSwagger.URL(fmt.Sprintf("%s://%s/swagger/doc.json", a.conf.Swagger.Scheme, a.conf.Swagger.Host)),
))
// =========================================================================
// API Version 1
2022-08-30 18:05:11 +00:00
v1Base := v1.BaseUrlFunc(prefix)
v1Ctrl := v1.NewControllerV1(a.services,
v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize),
2022-10-14 22:02:16 +00:00
v1.WithRegistration(a.conf.AllowRegistration),
v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode
)
r.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{
2022-10-14 01:01:01 +00:00
Version: version,
Commit: commit,
BuildTime: buildTime,
}))
r.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration())
r.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin())
// Attachment download URl needs a `token` query param to be passed in the request.
// and also needs to be outside of the `auth` middleware.
r.Get(v1Base("/items/{id}/attachments/download"), v1Ctrl.HandleItemAttachmentDownload())
r.Group(func(r chi.Router) {
r.Use(a.mwAuthToken)
r.Get(v1Base("/users/self"), v1Ctrl.HandleUserSelf())
r.Put(v1Base("/users/self"), v1Ctrl.HandleUserSelfUpdate())
r.Delete(v1Base("/users/self"), v1Ctrl.HandleUserSelfDelete())
r.Put(v1Base("/users/self/password"), v1Ctrl.HandleUserUpdatePassword())
r.Post(v1Base("/users/logout"), v1Ctrl.HandleAuthLogout())
r.Get(v1Base("/users/refresh"), v1Ctrl.HandleAuthRefresh())
r.Put(v1Base("/users/self/change-password"), v1Ctrl.HandleUserSelfChangePassword())
r.Post(v1Base("/groups/invitations"), v1Ctrl.HandleGroupInvitationsCreate())
r.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll())
r.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate())
r.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet())
r.Put(v1Base("/locations/{id}"), v1Ctrl.HandleLocationUpdate())
r.Delete(v1Base("/locations/{id}"), v1Ctrl.HandleLocationDelete())
r.Get(v1Base("/labels"), v1Ctrl.HandleLabelsGetAll())
r.Post(v1Base("/labels"), v1Ctrl.HandleLabelsCreate())
r.Get(v1Base("/labels/{id}"), v1Ctrl.HandleLabelGet())
r.Put(v1Base("/labels/{id}"), v1Ctrl.HandleLabelUpdate())
r.Delete(v1Base("/labels/{id}"), v1Ctrl.HandleLabelDelete())
r.Get(v1Base("/items"), v1Ctrl.HandleItemsGetAll())
r.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport())
r.Post(v1Base("/items"), v1Ctrl.HandleItemsCreate())
r.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet())
r.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate())
r.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete())
r.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate())
r.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken())
r.Put(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentUpdate())
r.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete())
})
2022-08-30 02:30:36 +00:00
2022-09-04 03:10:42 +00:00
r.NotFound(notFoundHandler())
2022-08-30 02:30:36 +00:00
return r
}
2022-09-04 03:27:02 +00:00
// logRoutes logs the routes of the server that are registered within Server.registerRoutes(). This is useful for debugging.
2022-08-30 02:30:36 +00:00
// See https://github.com/go-chi/chi/issues/332 for details and inspiration.
2022-09-04 03:27:02 +00:00
func (a *app) logRoutes(r *chi.Mux) {
2022-08-30 02:30:36 +00:00
desiredSpaces := 10
2022-09-04 02:42:03 +00:00
walkFunc := func(method string, route string, handler http.Handler, middleware ...func(http.Handler) http.Handler) error {
2022-08-30 02:30:36 +00:00
text := "[" + method + "]"
for len(text) < desiredSpaces {
text = text + " "
}
fmt.Printf("Registered Route: %s%s\n", text, route)
return nil
}
if err := chi.Walk(r, walkFunc); err != nil {
fmt.Printf("Logging err: %s\n", err.Error())
}
}
2022-09-04 02:42:03 +00:00
2022-09-04 03:10:42 +00:00
func registerMimes() {
err := mime.AddExtensionType(".js", "application/javascript")
if err != nil {
panic(err)
}
err = mime.AddExtensionType(".mjs", "application/javascript")
if err != nil {
panic(err)
}
2022-09-04 02:42:03 +00:00
}
2022-09-04 03:27:02 +00:00
// notFoundHandler perform the main logic around handling the internal SPA embed and ensuring that
// the client side routing is handled correctly.
2022-09-04 03:10:42 +00:00
func notFoundHandler() http.HandlerFunc {
tryRead := func(fs embed.FS, prefix, requestedPath string, w http.ResponseWriter) error {
f, err := fs.Open(path.Join(prefix, requestedPath))
if err != nil {
return err
}
defer f.Close()
2022-09-04 02:42:03 +00:00
2022-09-04 03:10:42 +00:00
stat, _ := f.Stat()
if stat.IsDir() {
return ErrDir
}
2022-09-04 02:42:03 +00:00
2022-09-04 03:10:42 +00:00
contentType := mime.TypeByExtension(filepath.Ext(requestedPath))
w.Header().Set("Content-Type", contentType)
_, err = io.Copy(w, f)
return err
2022-09-04 02:42:03 +00:00
}
2022-09-04 03:10:42 +00:00
return func(w http.ResponseWriter, r *http.Request) {
err := tryRead(public, "public", r.URL.Path, w)
if err == nil {
return
}
log.Debug().
Str("path", r.URL.Path).
Msg("served from embed not found - serving index.html")
err = tryRead(public, "public", "index.html", w)
2022-09-04 02:42:03 +00:00
if err != nil {
2022-09-04 03:10:42 +00:00
panic(err)
2022-09-04 02:42:03 +00:00
}
}
}