inventory/api/storage.go

264 lines
7.5 KiB
Go

package api
import (
"context"
"database/sql"
"net/http"
"strconv"
"github.com/labstack/echo/v4"
"go.uber.org/zap"
db "git.entr0py.de/garionion/inventory/database/sqlite/generated"
)
type StorageHandler struct {
db *db.Queries
logger *zap.Logger
}
func NewStorageHandler(db *db.Queries, logger *zap.Logger) *StorageHandler {
return &StorageHandler{
db: db,
logger: logger,
}
}
// GetStorageSpaces returns all storage spaces
func (h *StorageHandler) GetStorageSpaces(c echo.Context) error {
ctx := context.Background()
storageSpaces, err := h.db.GetAllStorageSpaces(ctx)
if err != nil {
h.logger.Error("Failed to fetch storage spaces", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to fetch storage spaces",
})
}
// Convert to a format suitable for the frontend
result := make([]map[string]interface{}, len(storageSpaces))
for i, space := range storageSpaces {
result[i] = map[string]interface{}{
"id": space.ID,
"parent": space.Parent,
"location": space.Location,
"name": space.Name,
}
}
return c.JSON(http.StatusOK, result)
}
// GetObjectsInStorage returns all objects in a specific storage space
func (h *StorageHandler) GetObjectsInStorage(c echo.Context) error {
ctx := context.Background()
// Parse storage ID from URL
storageIDStr := c.Param("id")
storageID, err := strconv.ParseInt(storageIDStr, 10, 64)
if err != nil {
h.logger.Warn("Invalid storage ID", zap.String("id", storageIDStr))
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid storage ID",
})
}
// Check if storage exists
_, err = h.db.GetStorageSpaceByID(ctx, storageID)
if err != nil {
if err == sql.ErrNoRows {
return c.JSON(http.StatusNotFound, map[string]string{
"error": "Storage space not found",
})
}
h.logger.Error("Failed to fetch storage space", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to fetch storage space",
})
}
// Get objects in this storage
objects, err := h.db.GetObjectsByStorageID(ctx, storageID)
if err != nil {
h.logger.Error("Failed to fetch objects in storage", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to fetch objects in storage",
})
}
// Convert to a format suitable for the frontend
result := make([]map[string]interface{}, len(objects))
for i, obj := range objects {
result[i] = map[string]interface{}{
"id": obj.ID,
"name": obj.Name,
"storagespaceId": obj.StoragespaceID,
"description": obj.Description.String,
"serialnumber": obj.Serialnumber.String,
}
}
return c.JSON(http.StatusOK, result)
}
// GetStorageHierarchyObjects returns all objects in a storage hierarchy
func (h *StorageHandler) GetStorageHierarchyObjects(c echo.Context) error {
ctx := context.Background()
// Parse root storage ID from URL
rootStorageIDStr := c.Param("id")
rootStorageID, err := strconv.ParseInt(rootStorageIDStr, 10, 64)
if err != nil {
h.logger.Warn("Invalid storage ID", zap.String("id", rootStorageIDStr))
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid storage ID",
})
}
// Check if root storage exists
_, err = h.db.GetStorageSpaceByID(ctx, rootStorageID)
if err != nil {
if err == sql.ErrNoRows {
return c.JSON(http.StatusNotFound, map[string]string{
"error": "Storage space not found",
})
}
h.logger.Error("Failed to fetch storage space", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to fetch storage space",
})
}
// Get all storage spaces to build the hierarchy
allStorageSpaces, err := h.db.GetAllStorageSpaces(ctx)
if err != nil {
h.logger.Error("Failed to fetch all storage spaces", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to fetch storage hierarchy",
})
}
// Build a list of all storage IDs in the hierarchy
storageIDs := []int64{rootStorageID}
storageIDs = append(storageIDs, h.getChildStorageIDs(allStorageSpaces, rootStorageID)...)
// Get objects for all storage spaces in the hierarchy
var allObjects []map[string]interface{}
for _, storageID := range storageIDs {
// Get objects in this storage
objects, err := h.db.GetObjectsByStorageID(ctx, storageID)
if err != nil {
h.logger.Error("Failed to fetch objects in storage",
zap.Int64("storageID", storageID),
zap.Error(err))
continue // Skip this storage if there's an error
}
// Convert to a format suitable for the frontend
for _, obj := range objects {
allObjects = append(allObjects, map[string]interface{}{
"id": obj.ID,
"name": obj.Name,
"storagespaceId": obj.StoragespaceID,
"description": obj.Description.String,
"serialnumber": obj.Serialnumber.String,
})
}
}
return c.JSON(http.StatusOK, allObjects)
}
// Helper function to recursively get all child storage IDs
func (h *StorageHandler) getChildStorageIDs(spaces []db.Storagespace, parentID int64) []int64 {
var childIDs []int64
for _, space := range spaces {
if space.Parent.Valid && space.Parent.Int64 == parentID {
childIDs = append(childIDs, space.ID)
// Recursively get children of this child
childIDs = append(childIDs, h.getChildStorageIDs(spaces, space.ID)...)
}
}
return childIDs
}
// CreateStorageSpace creates a new storage space
func (h *StorageHandler) CreateStorageSpace(c echo.Context) error {
ctx := context.Background()
// Parse request body
type StorageSpaceRequest struct {
Name string `json:"name"`
Location string `json:"location"`
Parent *struct {
Valid bool `json:"valid"`
Int64 int64 `json:"int64"`
} `json:"parent"`
}
var req StorageSpaceRequest
if err := c.Bind(&req); err != nil {
h.logger.Warn("Invalid request body", zap.Error(err))
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Invalid request body",
})
}
// Convert parent to sql.NullInt64
var parent sql.NullInt64
if req.Parent != nil && req.Parent.Valid {
parent.Valid = true
parent.Int64 = req.Parent.Int64
// Verify parent exists
_, err := h.db.GetStorageSpaceByID(ctx, parent.Int64)
if err != nil {
if err == sql.ErrNoRows {
return c.JSON(http.StatusBadRequest, map[string]string{
"error": "Parent storage space not found",
})
}
h.logger.Error("Failed to fetch parent storage space", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to verify parent storage space",
})
}
}
// Convert location to sql.NullString
var location sql.NullString
if req.Location != "" {
location.Valid = true
location.String = req.Location
}
// Create storage space
err := h.db.CreateStorageSpace(ctx, db.CreateStorageSpaceParams{
Parent: parent,
Location: location,
Name: req.Name,
})
if err != nil {
h.logger.Error("Failed to create storage space", zap.Error(err))
return c.JSON(http.StatusInternalServerError, map[string]string{
"error": "Failed to create storage space",
})
}
return c.JSON(http.StatusCreated, map[string]string{
"message": "Storage space created successfully",
})
}
// RegisterRoutes registers all storage-related routes
func (h *StorageHandler) RegisterRoutes(g *echo.Group) {
g.GET("/storageSpaces", h.GetStorageSpaces)
g.POST("/storageSpaces", h.CreateStorageSpace)
g.GET("/storageSpaces/:id/objects", h.GetObjectsInStorage)
g.GET("/storageSpaces/:id/hierarchy/objects", h.GetStorageHierarchyObjects)
}