Browse Source

feat: better API returns, asset update

master
Brett Bender 2 years ago
parent
commit
b2c8c2915f
7 changed files with 93 additions and 10 deletions
  1. +1
    -0
      internal/api/api.go
  2. +40
    -1
      internal/api/assets.go
  3. +26
    -2
      internal/api/shelves.go
  4. +19
    -5
      internal/storage/datastore.go
  5. +5
    -0
      internal/types/api.go
  6. +1
    -1
      internal/types/buildings.go
  7. +1
    -1
      internal/types/shelves.go

+ 1
- 0
internal/api/api.go View File

@ -67,6 +67,7 @@ func (s *APIServer) handleIndex(w http.ResponseWriter, r *http.Request) error {
func makeHandler(f APIFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := f(w, r); err != nil {
log.Printf("Err: %v", err)
render.Render(w, r, errBadRequest(err))
}
}


+ 40
- 1
internal/api/assets.go View File

@ -19,6 +19,7 @@ func (s *APIServer) setupAssetRoutes() func(r chi.Router) {
r.Use(s.AssetCtx)
r.Get("/", makeHandler(s.getAsset))
r.Delete("/", makeHandler(s.deleteAsset))
r.Put("/", makeHandler(s.updateAsset))
})
}
}
@ -42,7 +43,7 @@ func (s *APIServer) AssetCtx(next http.Handler) http.Handler {
}
func (s *APIServer) getAssets(w http.ResponseWriter, r *http.Request) error {
assets, err := s.db.GetAssets(0, 50) // TODO: Proper Pagination
assets, err := s.db.GetAssets(0, 1000) // TODO: Proper Pagination
if err != nil {
return err
}
@ -120,3 +121,41 @@ func (s *APIServer) createAsset(w http.ResponseWriter, r *http.Request) error {
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,
})
}

+ 26
- 2
internal/api/shelves.go View File

@ -2,6 +2,7 @@ package api
import (
"context"
"log"
"net/http"
"strconv"
@ -15,24 +16,27 @@ func (s *APIServer) setupShelfRoutes() func(chi.Router) {
r.Get("/", makeHandler(s.getShelves))
r.Post("/", makeHandler(s.createShelf))
r.Route("/{shelfID}", func(r chi.Router) {
r.Route("/{shelfId}", func(r chi.Router) {
r.Use(s.ShelfCtx)
r.Get("/", makeHandler(s.getShelf))
r.Delete("/", makeHandler(s.deleteShelf))
r.Get("/count", makeHandler(s.getShelfAssetCount))
})
}
}
func (s *APIServer) ShelfCtx(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
shelfIdStr := chi.URLParam(r, "shelfID")
shelfIdStr := chi.URLParam(r, "shelfId")
shelfId, err := strconv.ParseUint(shelfIdStr, 10, 64)
if err != nil {
log.Println("Test")
render.Render(w, r, errNotFound)
return
}
shelf, err := s.db.GetShelfByID(shelfId)
if err != nil {
log.Printf("Test 2: %v\n", err)
render.Render(w, r, errNotFound)
return
}
@ -120,3 +124,23 @@ func (s *APIServer) createShelf(w http.ResponseWriter, r *http.Request) error {
ShelfLocation: shelf,
})
}
func (s *APIServer) getShelfAssetCount(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context()
shelf, ok := ctx.Value("shelf").(*types.ShelfLocation)
if !ok {
return render.Render(w, r, errUnprocessable)
}
count, err := s.db.AssetCountInLocation(shelf.ID)
if err != nil {
return err
}
return render.Render(w, r, &types.CountResponse{
Response: &types.Response{
HTTPStatusCode: http.StatusOK,
},
Count: count,
})
}

+ 19
- 5
internal/storage/datastore.go View File

@ -7,6 +7,7 @@ import (
"git.brettb.xyz/goinv/server/internal/types"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/logger"
)
@ -47,6 +48,11 @@ func (s *DataStore) CreateAsset(asset *types.Asset) error {
return result.Error
}
func (s *DataStore) UpdateAsset(id uint64, update *types.Asset) error {
result := s.db.Model(&types.Asset{}).Where("id = ?", id).Select("*").Updates(update)
return result.Error
}
func (s *DataStore) CreateBuilding(building *types.Building) error {
result := s.db.Create(building)
return result.Error
@ -64,7 +70,7 @@ func (s *DataStore) CreateShelfLocation(shelf *types.ShelfLocation) error {
func (s *DataStore) GetAssetByID(id uint64) (*types.Asset, error) {
var result types.Asset
tx := s.db.Model(&types.Asset{}).Where("id = ?", id).First(&result)
tx := s.db.Model(&types.Asset{}).Where("id = ?", id).Preload(clause.Associations).First(&result)
if tx.Error != nil {
return nil, fmt.Errorf("asset %d not found", id)
}
@ -88,6 +94,14 @@ func (s *DataStore) TotalAssets() (int64, error) {
return count, nil
}
func (s *DataStore) AssetCountInLocation(shelfId uint64) (int64, error) {
var count int64
if tx := s.db.Model(&types.Asset{}).Where("shelf_location_id = ?", shelfId).Find(&types.Asset{}).Count(&count); tx.Error != nil {
return 0, tx.Error
}
return count, nil
}
func (s *DataStore) DeleteAssetByID(id uint64) (bool, error) {
tx := s.db.Delete(&types.Asset{}, id)
if tx.Error != nil {
@ -98,16 +112,16 @@ func (s *DataStore) DeleteAssetByID(id uint64) (bool, error) {
func (s *DataStore) GetShelfByID(id uint64) (*types.ShelfLocation, error) {
var result types.ShelfLocation
tx := s.db.Model(&types.ShelfLocation{}).Where("id = ?", id).First(&result)
tx := s.db.Joins("Building").Where(&types.ShelfLocation{ID: id}).First(&result)
if tx.Error != nil {
return nil, fmt.Errorf("shelf %d not found", id)
return nil, fmt.Errorf("shelf %d not found: %v", id, tx.Error)
}
return &result, nil
}
func (s *DataStore) GetShelves(offset, limit int) ([]*types.ShelfLocation, error) {
func (s *DataStore) GetShelves(offset, limit uint64) ([]*types.ShelfLocation, error) {
var shelves []*types.ShelfLocation
s.db.Offset(offset).Limit(limit).Find(&shelves)
s.db.Joins("Building").Order("id asc").Offset(int(offset)).Limit(int(limit)).Find(&shelves)
if len(shelves) == 0 {
return nil, fmt.Errorf("no shelves found")
}


+ 5
- 0
internal/types/api.go View File

@ -26,6 +26,11 @@ type IndexResponse struct {
Version APIVersion `json:"version"`
}
type CountResponse struct {
*Response
Count int64 `json:"count"`
}
type APIError struct {
*Response
Err error `json:"-"`


+ 1
- 1
internal/types/buildings.go View File

@ -14,7 +14,7 @@ import (
type Building struct {
ID uint64 `gorm:"primarykey" json:"id"`
Name string `json:"name"`
ShelfLocations []ShelfLocation `json:"shelves"`
ShelfLocations []ShelfLocation `json:"shelves,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at,omitempty"`


+ 1
- 1
internal/types/shelves.go View File

@ -17,7 +17,7 @@ type ShelfLocation struct {
RoomNumber string `json:"room_number,omitempty"`
Description string `json:"description,omitempty"`
BuildingID uint64 `json:"-"`
Building Building `json:"building"`
Building Building `json:"building",omitempty`
Assets []Asset `json:"assets,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`


Loading…
Cancel
Save