255 lines
6.0 KiB
Go
255 lines
6.0 KiB
Go
/**
|
|
* file: api/v0/product.go
|
|
* author: Theo Technicguy
|
|
* license: Apache 2.0
|
|
*
|
|
* Product tags API endpoint
|
|
*/
|
|
|
|
package apiv0
|
|
|
|
// TODO: refactor status code setting and json encoding into a function
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"git.licolas.net/hoffman/server/types"
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
const (
|
|
eanQry = "ean"
|
|
namesQry = "names"
|
|
tagsQry = "tags"
|
|
masterOperatorQry = "operator"
|
|
nameOperatorQry = "names_operator"
|
|
tagsOperatorQry = "tags_operator"
|
|
)
|
|
|
|
var (
|
|
ErrMismatchingIds = errors.New("mismatching request and product ids")
|
|
)
|
|
|
|
func getAllProducts(w http.ResponseWriter, r *http.Request) {
|
|
logger.Trace().Msg("getting all products")
|
|
|
|
products, err := lgc.GetAllProducts()
|
|
if err != nil {
|
|
respondWithError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
respond(w, http.StatusOK, products)
|
|
}
|
|
|
|
func getProductById(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.ParseUint(mux.Vars(r)[idQry], 10, 64)
|
|
|
|
if err != nil {
|
|
respondWithError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
logger.Trace().Uint("product", uint(id)).Msg("getting product by id")
|
|
|
|
product, err := lgc.GetProductByID(uint(id))
|
|
|
|
if err != nil {
|
|
var status int
|
|
if err == types.ErrIDNotFound {
|
|
status = http.StatusNotFound
|
|
} else {
|
|
status = http.StatusInternalServerError
|
|
}
|
|
|
|
respondWithError(w, status, err)
|
|
return
|
|
}
|
|
|
|
respond(w, http.StatusOK, product)
|
|
}
|
|
|
|
func getProductsLike(w http.ResponseWriter, r *http.Request) {
|
|
logger.Trace().Msg("getting products like")
|
|
vars := r.URL.Query()
|
|
|
|
logger.Trace().Msg("parsing search tags")
|
|
tags := []uint{}
|
|
for _, tag := range strings.Split(vars.Get(tagsQry), ",") {
|
|
if tag == "" {
|
|
continue
|
|
}
|
|
uint64Tag, err := strconv.ParseUint(tag, 10, 64)
|
|
if err != nil {
|
|
respondWithError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
tags = append(tags, uint(uint64Tag))
|
|
}
|
|
|
|
logger.Trace().Msg("parsing search names")
|
|
names := strings.Split(vars.Get(namesQry), ",")
|
|
if names[0] == "" {
|
|
names = []string{}
|
|
}
|
|
|
|
ps := &types.ProductSearch{
|
|
Ean: vars.Get(eanQry),
|
|
Names: names,
|
|
TagIds: tags,
|
|
Oprators: types.ProductSearchOperators{
|
|
Master: strings.ToUpper(vars.Get(masterOperatorQry)),
|
|
Names: strings.ToUpper(vars.Get(nameOperatorQry)),
|
|
TagIds: strings.ToUpper(vars.Get(tagsOperatorQry)),
|
|
},
|
|
}
|
|
ps.Oprators.FillDefaults()
|
|
logger.Debug().Any("product search", ps).Msg("created search")
|
|
|
|
products, err := lgc.GetProductsLike(ps)
|
|
|
|
if err != nil {
|
|
respondWithError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
respond(w, http.StatusOK, products)
|
|
}
|
|
|
|
func postProduct(w http.ResponseWriter, r *http.Request) {
|
|
logger.Trace().Msg("posting product")
|
|
var product types.Product
|
|
if err := json.NewDecoder(r.Body).Decode(&product); err != nil {
|
|
respondWithError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
if err := lgc.CreateProduct(&product); err != nil {
|
|
respondWithError(w, http.StatusInternalServerError, err)
|
|
return
|
|
}
|
|
|
|
respond(w, http.StatusCreated, product)
|
|
}
|
|
|
|
func putProductById(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.ParseUint(mux.Vars(r)[idQry], 10, 64)
|
|
if err != nil {
|
|
respondWithError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
logger := logger.With().Uint("product", uint(id)).Logger()
|
|
logger.Trace().Msg("putting product")
|
|
|
|
var newProduct types.Product
|
|
if err = json.NewDecoder(r.Body).Decode(&newProduct); err != nil {
|
|
respondWithError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
logger.Trace().Msg("checking ids")
|
|
if id != uint64(newProduct.Id) {
|
|
respondWithError(w, http.StatusBadRequest, ErrMismatchingIds)
|
|
return
|
|
}
|
|
|
|
logger.Trace().Msg("updating product")
|
|
product, err := lgc.UpdateProduct(&newProduct)
|
|
if err != nil {
|
|
var status int
|
|
if err == types.ErrIDNotFound {
|
|
status = http.StatusNotFound
|
|
} else {
|
|
status = http.StatusInternalServerError
|
|
}
|
|
|
|
respondWithError(w, status, err)
|
|
return
|
|
}
|
|
|
|
respond(w, http.StatusCreated, product)
|
|
}
|
|
|
|
func deleteProductById(w http.ResponseWriter, r *http.Request) {
|
|
id, err := strconv.ParseUint(mux.Vars(r)[idQry], 10, 64)
|
|
|
|
if err != nil {
|
|
respondWithError(w, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
logger.With().Uint("product", uint(id)).Logger()
|
|
logger.Trace().Msg("deleting product")
|
|
|
|
product, err := lgc.DeleteProduct(uint(id))
|
|
if err != nil {
|
|
var status int
|
|
if err == types.ErrIDNotFound {
|
|
status = http.StatusNotFound
|
|
} else {
|
|
status = http.StatusInternalServerError
|
|
}
|
|
|
|
respondWithError(w, status, err)
|
|
return
|
|
}
|
|
|
|
respond(w, http.StatusAccepted, product)
|
|
}
|
|
|
|
func SetProductRoutes(router *mux.Router) {
|
|
productRouter := router.PathPrefix("/product").Subrouter()
|
|
|
|
productRouter.HandleFunc("", getAllProducts).Methods("GET")
|
|
productRouter.HandleFunc("/", getAllProducts).Methods("GET")
|
|
|
|
// Searches
|
|
searchPath := "/search"
|
|
|
|
eanVar := "{" + eanQry + ":[0-9]+}"
|
|
namesVar := "{" + namesQry + ":[^\x00-+.:-@[\\]^{|}~]+}"
|
|
tagVar := "{" + tagsQry + ":[0-9]+(?:,[0-9]+)*,?}"
|
|
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(eanQry, eanVar, namesQry, namesVar, tagsQry, tagVar)
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(eanQry, eanVar, namesQry, namesVar)
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(eanQry, eanVar, tagsQry, tagVar)
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(namesQry, namesVar, tagsQry, tagVar)
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(eanQry, eanVar)
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(namesQry, namesVar)
|
|
productRouter.
|
|
HandleFunc(searchPath, getProductsLike).
|
|
Methods("GET").
|
|
Queries(tagsQry, tagVar)
|
|
|
|
idPath := "/" + idVar
|
|
productRouter.HandleFunc(idPath, getProductById).Methods("GET")
|
|
|
|
productRouter.HandleFunc("", postProduct).Methods("POST")
|
|
productRouter.HandleFunc("/new", postProduct).Methods("POST")
|
|
|
|
productRouter.HandleFunc(idPath, putProductById).Methods("PUT")
|
|
|
|
productRouter.HandleFunc(idPath, deleteProductById).Methods("DELETE")
|
|
}
|