284 lines
8.6 KiB
Go
284 lines
8.6 KiB
Go
package httpapi
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"net/http"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/catalog"
|
||
|
|
"github.com/go-chi/chi/v5"
|
||
|
|
"github.com/google/uuid"
|
||
|
|
)
|
||
|
|
|
||
|
|
func (s *Server) handleListFieldGroups(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
items, err := s.Catalog.ListFieldGroups(r.Context(), cid)
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusInternalServerError, "list failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
limit, offset := ParseLimitOffsetMax(r, maxTreePageLimit)
|
||
|
|
page, total := pageSlice(items, limit, offset)
|
||
|
|
JSON(w, http.StatusOK, map[string]any{"groups": page, "total": total, "limit": limit, "offset": offset})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleCreateFieldGroup(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
var body map[string]any
|
||
|
|
if err := DecodeJSON(r, &body); err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
name, _ := body["name"].(string)
|
||
|
|
var desc *string
|
||
|
|
if v, ok := body["description"]; ok {
|
||
|
|
if v == nil {
|
||
|
|
empty := ""
|
||
|
|
desc = &empty
|
||
|
|
} else if str, ok := v.(string); ok {
|
||
|
|
desc = &str
|
||
|
|
}
|
||
|
|
}
|
||
|
|
order := 0
|
||
|
|
if v, ok := body["order"].(float64); ok {
|
||
|
|
order = int(v)
|
||
|
|
}
|
||
|
|
item, err := s.Catalog.CreateFieldGroup(r.Context(), cid, name, desc, order)
|
||
|
|
if err != nil {
|
||
|
|
ClientOrLog(w, http.StatusBadRequest, "could not create field group", err, catalog.ClientError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusCreated, item)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleUpdateFieldGroup(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
id, err := uuid.Parse(chi.URLParam(r, "id"))
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
var body map[string]any
|
||
|
|
if err := DecodeJSON(r, &body); err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
item, err := s.Catalog.UpdateFieldGroup(r.Context(), cid, id, body)
|
||
|
|
if errors.Is(err, catalog.ErrNotFound) {
|
||
|
|
Error(w, http.StatusNotFound, "not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if errors.Is(err, catalog.ErrSystemImmutable) {
|
||
|
|
Error(w, http.StatusForbidden, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
ClientOrLog(w, http.StatusBadRequest, "could not update field group", err, catalog.ClientError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, item)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleDeleteFieldGroup(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
id, err := uuid.Parse(chi.URLParam(r, "id"))
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
err = s.Catalog.DeleteFieldGroup(r.Context(), cid, id)
|
||
|
|
if errors.Is(err, catalog.ErrNotFound) {
|
||
|
|
Error(w, http.StatusNotFound, "not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if errors.Is(err, catalog.ErrSystemImmutable) {
|
||
|
|
Error(w, http.StatusForbidden, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusInternalServerError, "delete failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleListStandardFields(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
enabledOnly := false
|
||
|
|
switch strings.ToLower(strings.TrimSpace(r.URL.Query().Get("enabled"))) {
|
||
|
|
case "1", "true", "yes":
|
||
|
|
enabledOnly = true
|
||
|
|
}
|
||
|
|
items, err := s.Catalog.ListStandardFields(r.Context(), cid, enabledOnly)
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusInternalServerError, "list failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
limit, offset := ParseLimitOffsetMax(r, maxTreePageLimit)
|
||
|
|
page, total := pageSlice(items, limit, offset)
|
||
|
|
JSON(w, http.StatusOK, map[string]any{"fields": page, "total": total, "limit": limit, "offset": offset})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleCreateStandardField(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
var body map[string]any
|
||
|
|
if err := DecodeJSON(r, &body); err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
item, err := s.Catalog.CreateStandardField(r.Context(), cid, body)
|
||
|
|
if err != nil {
|
||
|
|
ClientOrLog(w, http.StatusBadRequest, "could not create standard field", err, catalog.ClientError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusCreated, item)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleUpdateStandardField(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
id, err := uuid.Parse(chi.URLParam(r, "id"))
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
var body map[string]any
|
||
|
|
if err := DecodeJSON(r, &body); err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
item, err := s.Catalog.UpdateStandardField(r.Context(), cid, id, body)
|
||
|
|
if errors.Is(err, catalog.ErrNotFound) {
|
||
|
|
Error(w, http.StatusNotFound, "not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if errors.Is(err, catalog.ErrSystemImmutable) {
|
||
|
|
Error(w, http.StatusForbidden, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
ClientOrLog(w, http.StatusBadRequest, "could not update standard field", err, catalog.ClientError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, item)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleDeleteStandardField(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
id, err := uuid.Parse(chi.URLParam(r, "id"))
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
err = s.Catalog.DeleteStandardField(r.Context(), cid, id)
|
||
|
|
if errors.Is(err, catalog.ErrNotFound) {
|
||
|
|
Error(w, http.StatusNotFound, "not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if errors.Is(err, catalog.ErrSystemImmutable) {
|
||
|
|
Error(w, http.StatusForbidden, err.Error())
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusInternalServerError, "delete failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleBulkStandardFieldsEnabled(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
var body struct {
|
||
|
|
IDs []string `json:"ids"`
|
||
|
|
Enabled *bool `json:"enabled"`
|
||
|
|
}
|
||
|
|
if err := DecodeJSON(r, &body); err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if body.Enabled == nil {
|
||
|
|
Error(w, http.StatusBadRequest, "enabled required")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
ids := make([]uuid.UUID, 0, len(body.IDs))
|
||
|
|
for _, raw := range body.IDs {
|
||
|
|
id, err := uuid.Parse(strings.TrimSpace(raw))
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
ids = append(ids, id)
|
||
|
|
}
|
||
|
|
n, err := s.Catalog.BulkSetStandardFieldsEnabled(r.Context(), cid, ids, *body.Enabled)
|
||
|
|
if err != nil {
|
||
|
|
ClientOrLog(w, http.StatusBadRequest, "could not update standard fields", err, catalog.ClientError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, map[string]any{"updated": n, "enabled": *body.Enabled})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleEnableRecommendedStandardFields(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
items, err := s.Catalog.EnableRecommendedEcommerce(r.Context(), cid)
|
||
|
|
if err != nil {
|
||
|
|
LogAndError(w, http.StatusInternalServerError, "enable recommended fields failed", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, map[string]any{"fields": items, "status": "ok"})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleListStructuredDescriptions(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
items, err := s.Catalog.ListStructuredDescriptions(r.Context(), cid)
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusInternalServerError, "list failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
limit, offset := ParseLimitOffsetMax(r, maxTreePageLimit)
|
||
|
|
page, total := pageSlice(items, limit, offset)
|
||
|
|
JSON(w, http.StatusOK, map[string]any{"fields": page, "total": total, "limit": limit, "offset": offset})
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleCreateStructuredDescription(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
var body map[string]any
|
||
|
|
if err := DecodeJSON(r, &body); err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid json")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
fieldKey := ""
|
||
|
|
if v, ok := body["field_key"].(string); ok {
|
||
|
|
fieldKey = v
|
||
|
|
} else if v, ok := body["fieldKey"].(string); ok {
|
||
|
|
fieldKey = v
|
||
|
|
}
|
||
|
|
typ := "text"
|
||
|
|
if v, ok := body["type"].(string); ok && v != "" {
|
||
|
|
typ = v
|
||
|
|
}
|
||
|
|
item, err := s.Catalog.CreateStructuredDescription(r.Context(), cid, fieldKey, typ)
|
||
|
|
if err != nil {
|
||
|
|
ClientOrLog(w, http.StatusBadRequest, "could not create structured description", err, catalog.ClientError)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusCreated, item)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (s *Server) handleDeleteStructuredDescription(w http.ResponseWriter, r *http.Request) {
|
||
|
|
cid, _ := CompanyIDFromContext(r.Context())
|
||
|
|
id, err := uuid.Parse(chi.URLParam(r, "id"))
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusBadRequest, "invalid id")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
err = s.Catalog.DeleteStructuredDescription(r.Context(), cid, id)
|
||
|
|
if errors.Is(err, catalog.ErrNotFound) {
|
||
|
|
Error(w, http.StatusNotFound, "not found")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
if err != nil {
|
||
|
|
Error(w, http.StatusInternalServerError, "delete failed")
|
||
|
|
return
|
||
|
|
}
|
||
|
|
JSON(w, http.StatusOK, map[string]string{"status": "ok"})
|
||
|
|
}
|