package locations import ( "database/sql" "encoding/json" "net/http" "strconv" "github.com/dustinpianalto/errors" "github.com/dustinpianalto/quartermaster" "github.com/dustinpianalto/quartermaster/pkg/services" "github.com/gorilla/mux" ) type itemsResponse struct { Count int `json:"count"` *quartermaster.Item } func locations(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "locations" if r.Method == "POST" { err := addLocation(w, r, user) if err != nil { return errors.E(method, "there was a problem adding the location", err) } } else if r.Method == "GET" { err := getTopLocations(w, r, user) if err != nil { return errors.E(method, "there was a problem getting locations", err) } } else { return errors.E(method, errors.Malformed, "http method not allowed") } return nil } func addLocation(w *http.ResponseWriter, r *http.Request, u *quartermaster.User) error { const method errors.Method = "locations/addLocation" var l *quartermaster.Location err := json.NewDecoder(r.Body).Decode(&l) if err != nil { return errors.E(method, errors.Malformed, "failed to decode location request", err) } if l.Name == "" || l.Description == "" { return errors.E(method, errors.Malformed, "name and description are required") } if l.Parent != nil { _, err := services.LocationService.Location(l.Parent.ID, u) if err != nil { return errors.E(method, errors.Malformed, "parent does not exist", err) } } l, err = services.LocationService.AddLocation(l, u) if err != nil { return errors.E(method, errors.Internal, err) } lJson, err := json.Marshal(l) if err != nil { return errors.E(method, errors.Internal, "error marshalling location", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusCreated) (*w).Write(lJson) return nil } func getTopLocations(w *http.ResponseWriter, r *http.Request, u *quartermaster.User) error { const method errors.Method = "locations/getTopLocations" locations, err := services.LocationService.GetTopLocations(u) if err != nil { return errors.E(method, errors.Internal, "error getting locations", err) } locationsJson, err := json.Marshal(locations) if err != nil { return errors.E(method, errors.Internal, "error marshalling locations", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusOK) (*w).Write(locationsJson) return nil } func getChildren(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "locations/getChildren" params := mux.Vars(r) idString := params["id"] id, err := strconv.Atoi(idString) if err != nil { return errors.E(method, errors.Malformed, "id must be a valid number") } location, err := services.LocationService.Location(id, user) if err != nil { if err == sql.ErrNoRows { return errors.E(method, errors.Malformed, "location not found", err) } return errors.E(method, errors.Internal, "probem retrieving location", err) } children, err := services.LocationService.GetChildren(location, user) if err != nil { return errors.E(method, errors.Internal, "problem retrieving children", err) } var childrenJson []byte if children == nil { childrenJson = []byte("[]") } else { childrenJson, err = json.Marshal(children) } if err != nil { return errors.E(method, errors.Internal, "problem marshalling children", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusOK) (*w).Write(childrenJson) return nil } func getLocation(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "locations/getLocation" params := mux.Vars(r) idString := params["id"] id, err := strconv.Atoi(idString) if err != nil { return errors.E(method, errors.Malformed, "id must be a valid number") } location, err := services.LocationService.Location(id, user) if err != nil { if err == sql.ErrNoRows { return errors.E(method, errors.Malformed, "location not found", err) } return errors.E(method, errors.Internal, "robem retrieving location", err) } locationJson, err := json.Marshal(location) if err != nil { return errors.E(method, errors.Internal, "problem marshalling location", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusOK) (*w).Write(locationJson) return nil } func getItems(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "locations/getItems" params := mux.Vars(r) idString := params["id"] id, err := strconv.Atoi(idString) if err != nil { return errors.E(method, errors.Malformed, "id must be a valid number") } location, err := services.LocationService.Location(id, user) if err != nil { return errors.E(method, errors.Malformed, "location not found", err) } items, err := services.LocationService.GetItems(location, user) if err != nil { return errors.E(method, "problem getting items", err) } var itemsResp []itemsResponse for i, c := range items { itemsResp = append(itemsResp, itemsResponse{Count: c, Item: i}) } var itemsJson []byte if itemsResp == nil { itemsJson = []byte("[]") } else { itemsJson, err = json.Marshal(itemsResp) } if err != nil { return errors.E(method, errors.Internal, "error marshalling items", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusOK) (*w).Write(itemsJson) return nil } func addItem(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "items/addItem" params := mux.Vars(r) idString := params["id"] id, err := strconv.Atoi(idString) if err != nil { return errors.E(method, errors.Malformed, "location id must be a valid number") } location, err := services.LocationService.Location(id, user) if err != nil { return errors.E(method, errors.Malformed, "location not found", err) } itemIDString := params["item_id"] itemID, err := strconv.Atoi(itemIDString) if err != nil { return errors.E(method, errors.Malformed, "item id must be a valid number") } item, err := services.ItemService.Item(itemID, user) if err != nil { return errors.E(method, errors.Malformed, "item not found", err) } i, err := services.ItemService.AddItem(item, location, user) if err != nil { return errors.E(method, errors.Internal, "error adding item to location", err) } iJson, err := json.Marshal(i) if err != nil { return errors.E(method, errors.Internal, "error marshalling item", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusCreated) (*w).Write(iJson) return nil } func removeItem(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "items/removeItem" params := mux.Vars(r) idString := params["id"] id, err := strconv.Atoi(idString) if err != nil { return errors.E(method, errors.Malformed, "location id must be a valid number") } location, err := services.LocationService.Location(id, user) if err != nil { return errors.E(method, errors.Malformed, "location not found", err) } itemIDString := params["item_id"] itemID, err := strconv.Atoi(itemIDString) if err != nil { return errors.E(method, errors.Malformed, "item id must be a valid number") } item, err := services.ItemService.Item(itemID, user) if err != nil { return errors.E(method, errors.Malformed, "item not found", err) } err = services.ItemService.RemoveItem(item, location, user) if err != nil { return errors.E(method, errors.Internal, "error removing item from location", err) } iJson, err := json.Marshal(struct{ Status string }{Status: "ok"}) if err != nil { return errors.E(method, errors.Internal, "error marshalling item", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusCreated) (*w).Write(iJson) return nil } func getItemCount(w *http.ResponseWriter, r *http.Request, user *quartermaster.User) error { const method errors.Method = "items/getItemCount" params := mux.Vars(r) idString := params["id"] id, err := strconv.Atoi(idString) if err != nil { return errors.E(method, errors.Malformed, "location id must be a valid number") } location, err := services.LocationService.Location(id, user) if err != nil { return errors.E(method, errors.Malformed, "location not found", err) } itemIDString := params["item_id"] itemID, err := strconv.Atoi(itemIDString) if err != nil { return errors.E(method, errors.Malformed, "item id must be a valid number") } item, err := services.ItemService.Item(itemID, user) if err != nil { return errors.E(method, errors.Malformed, "item not found", err) } c, err := services.LocationService.GetItemCount(location, item, user) if err != nil { return errors.E(method, errors.Internal, "error getting count of items in location", err) } iJson, err := json.Marshal(struct{ Count int }{Count: c}) if err != nil { return errors.E(method, errors.Internal, "error marshalling item", err) } (*w).Header().Set("Content-Type", "application/json") (*w).WriteHeader(http.StatusCreated) (*w).Write(iJson) return nil }