package api import ( "net/http" "github.com/go-chi/chi/v5" "github.com/kindredsystems/silo/internal/storage" ) // DependencyResponse is the JSON representation for GET /dependencies. type DependencyResponse struct { UUID string `json:"uuid"` PartNumber *string `json:"part_number"` Revision *int `json:"revision"` Quantity *float64 `json:"quantity"` Label *string `json:"label"` Relationship string `json:"relationship"` } // ResolvedDependencyResponse is the JSON representation for GET /dependencies/resolve. type ResolvedDependencyResponse struct { UUID string `json:"uuid"` PartNumber *string `json:"part_number"` Label *string `json:"label"` Revision *int `json:"revision"` Quantity *float64 `json:"quantity"` Resolved bool `json:"resolved"` FileAvailable bool `json:"file_available"` } // HandleGetDependencies returns the raw dependency list for an item. // GET /api/items/{partNumber}/dependencies func (s *Server) HandleGetDependencies(w http.ResponseWriter, r *http.Request) { ctx := r.Context() partNumber := chi.URLParam(r, "partNumber") item, err := s.items.GetByPartNumber(ctx, partNumber) if err != nil { s.logger.Error().Err(err).Msg("failed to get item") writeError(w, http.StatusInternalServerError, "internal_error", "Failed to get item") return } if item == nil { writeError(w, http.StatusNotFound, "not_found", "Item not found") return } deps, err := s.deps.ListByItem(ctx, item.ID) if err != nil { s.logger.Error().Err(err).Msg("failed to list dependencies") writeError(w, http.StatusInternalServerError, "internal_error", "Failed to list dependencies") return } resp := make([]DependencyResponse, len(deps)) for i, d := range deps { resp[i] = DependencyResponse{ UUID: d.ChildUUID, PartNumber: d.ChildPartNumber, Revision: d.ChildRevision, Quantity: d.Quantity, Label: d.Label, Relationship: d.Relationship, } } writeJSON(w, http.StatusOK, resp) } // HandleResolveDependencies returns dependencies with UUIDs resolved to part numbers // and file availability status. // GET /api/items/{partNumber}/dependencies/resolve func (s *Server) HandleResolveDependencies(w http.ResponseWriter, r *http.Request) { ctx := r.Context() partNumber := chi.URLParam(r, "partNumber") item, err := s.items.GetByPartNumber(ctx, partNumber) if err != nil { s.logger.Error().Err(err).Msg("failed to get item") writeError(w, http.StatusInternalServerError, "internal_error", "Failed to get item") return } if item == nil { writeError(w, http.StatusNotFound, "not_found", "Item not found") return } deps, err := s.deps.Resolve(ctx, item.ID) if err != nil { s.logger.Error().Err(err).Msg("failed to resolve dependencies") writeError(w, http.StatusInternalServerError, "internal_error", "Failed to resolve dependencies") return } resp := make([]ResolvedDependencyResponse, len(deps)) for i, d := range deps { // Use resolved part number if available, fall back to .kc-provided value. pn := d.ChildPartNumber rev := d.ChildRevision if d.Resolved { pn = d.ResolvedPartNumber rev = d.ResolvedRevision } fileAvailable := false if d.Resolved && pn != nil && rev != nil && s.storage != nil { key := storage.FileKey(*pn, *rev) if exists, err := s.storage.Exists(ctx, key); err == nil { fileAvailable = exists } } resp[i] = ResolvedDependencyResponse{ UUID: d.ChildUUID, PartNumber: pn, Label: d.Label, Revision: rev, Quantity: d.Quantity, Resolved: d.Resolved, FileAvailable: fileAvailable, } } writeJSON(w, http.StatusOK, resp) }