package api import ( "context" "net/http" "strconv" "git.brettb.xyz/goinv/server/internal/types" "github.com/go-chi/chi/v5" "github.com/go-chi/render" ) func (s *APIServer) setupAssetRoutes() func(r chi.Router) { return func(r chi.Router) { r.Get("/", makeHandler(s.getAssets)) r.Post("/", makeHandler(s.createAsset)) r.Route("/{assetID}", func(r chi.Router) { r.Use(s.AssetCtx) r.Get("/", makeHandler(s.getAsset)) r.Delete("/", makeHandler(s.deleteAsset)) r.Put("/", makeHandler(s.updateAsset)) }) } } func (s *APIServer) AssetCtx(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assetIdStr := chi.URLParam(r, "assetID") assetId, err := strconv.Atoi(assetIdStr) if err != nil { render.Render(w, r, errNotFound) return } asset, err := s.db.GetAssetByID(uint64(assetId)) if err != nil { render.Render(w, r, errNotFound) return } ctx := context.WithValue(r.Context(), "asset", asset) next.ServeHTTP(w, r.WithContext(ctx)) }) } func (s *APIServer) getAssets(w http.ResponseWriter, r *http.Request) error { assets, err := s.db.GetAssets(0, 1000) // TODO: Proper Pagination if err != nil { return err } total, err := s.db.TotalAssets() if err != nil { return err } return render.Render(w, r, &types.MultipleAssetsResponse{ Response: &types.Response{ HTTPStatusCode: http.StatusOK, }, Assets: assets, Total: total, }) } func (s *APIServer) getAsset(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() asset, ok := ctx.Value("asset").(*types.Asset) if !ok { return render.Render(w, r, errUnprocessable) } return render.Render(w, r, &types.AssetResponse{ Response: &types.Response{ HTTPStatusCode: http.StatusOK, }, Asset: asset, }) } func (s *APIServer) deleteAsset(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() asset, ok := ctx.Value("asset").(*types.Asset) if !ok { return render.Render(w, r, errUnprocessable) } if ok, _ := s.db.DeleteAssetByID(asset.ID); !ok { return render.Render(w, r, errUnprocessable) } return render.Render(w, r, &types.AssetResponse{Response: &types.Response{HTTPStatusCode: http.StatusOK}, Asset: asset}) } func (s *APIServer) createAsset(w http.ResponseWriter, r *http.Request) error { data := &types.CreateAssetRequest{} if err := render.Bind(r, data); err != nil { return render.Render(w, r, errBadRequest(err)) } asset := &types.Asset{ Name: data.Name, Quantity: data.Quantity, Length: data.Length, Manufacturer: data.Manufacturer, ModelName: data.ModelName, Price: data.Price, Comments: data.Comments, ShelfLocationID: data.ShelfLocationID, CategoryID: data.CategoryID, } err := s.db.CreateAsset(asset) if err != nil { return err } return render.Render(w, r, &types.AssetResponse{ Response: &types.Response{ HTTPStatusCode: http.StatusOK, }, Asset: asset, }) } func (s *APIServer) updateAsset(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() eAsset, ok := ctx.Value("asset").(*types.Asset) if !ok { return render.Render(w, r, errUnprocessable) } data := &types.CreateAssetRequest{} if err := render.Bind(r, data); err != nil { return render.Render(w, r, errBadRequest(err)) } asset := &types.Asset{ ID: eAsset.ID, Name: data.Name, Quantity: data.Quantity, Length: data.Length, Manufacturer: data.Manufacturer, ModelName: data.ModelName, Price: data.Price, Comments: data.Comments, ShelfLocationID: data.ShelfLocationID, CategoryID: data.CategoryID, } err := s.db.UpdateAsset(eAsset.ID, asset) if err != nil { return err } return render.Render(w, r, &types.AssetResponse{ Response: &types.Response{ HTTPStatusCode: http.StatusOK, }, Asset: asset, }) }