Merge branch 'expand_get_menu' of ssh://git.ma-al.com:8822/goc_daniel/b2b into test
This commit is contained in:
@@ -1127,21 +1127,32 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/api/v1/restricted/menu/get-menu": {
|
"/api/v1/restricted/menu/get-category-tree": {
|
||||||
"get": {
|
"get": {
|
||||||
"tags": ["Menu"],
|
"tags": ["Menu"],
|
||||||
"summary": "Get menu structure",
|
"summary": "Get category tree",
|
||||||
"description": "Returns the menu structure for the current language. Requires authentication.",
|
"description": "Returns the category tree rooted at the given category ID for the current language. Requires authentication.",
|
||||||
"operationId": "getMenu",
|
"operationId": "getCategoryTree",
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"CookieAuth": [],
|
"CookieAuth": [],
|
||||||
"BearerAuth": []
|
"BearerAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "root_category_id",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Root category ID to build the tree from",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Menu retrieved successfully",
|
"description": "Category tree retrieved successfully",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
@@ -1151,7 +1162,73 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"400": {
|
"400": {
|
||||||
"description": "Invalid request",
|
"description": "Invalid request or root category not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Not authenticated",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/v1/restricted/menu/get-breadcrumb": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["Menu"],
|
||||||
|
"summary": "Get breadcrumb",
|
||||||
|
"description": "Returns the breadcrumb path from the root category to the specified category for the current language. Requires authentication.",
|
||||||
|
"operationId": "getBreadcrumb",
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"CookieAuth": [],
|
||||||
|
"BearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "root_category_id",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Root category ID (breadcrumb starting point)",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "category_id",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Target category ID (breadcrumb destination)",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Breadcrumb retrieved successfully",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/ApiResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Invalid request, category not found, or root never reached",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
@@ -1221,7 +1298,23 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/components/schemas/ApiResponse"
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/B2BTopMenu"
|
||||||
|
},
|
||||||
|
"description": "Root menu items with nested children"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of root menu items"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1995,46 +2088,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"MenuItem": {
|
|
||||||
"type": "object",
|
|
||||||
"description": "Menu item structure",
|
|
||||||
"properties": {
|
|
||||||
"category_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "uint",
|
|
||||||
"description": "Category ID"
|
|
||||||
},
|
|
||||||
"label": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Menu item label"
|
|
||||||
},
|
|
||||||
"params": {
|
|
||||||
"$ref": "#/components/schemas/MenuItemParams"
|
|
||||||
},
|
|
||||||
"children": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/components/schemas/MenuItem"
|
|
||||||
},
|
|
||||||
"description": "Child menu items"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"MenuItemParams": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"category_id": {
|
|
||||||
"type": "integer",
|
|
||||||
"format": "uint"
|
|
||||||
},
|
|
||||||
"link_rewrite": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"locale": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Route": {
|
"Route": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Application route",
|
"description": "Application route",
|
||||||
@@ -2338,6 +2391,58 @@
|
|||||||
"description": "Build date in RFC3339 format"
|
"description": "Build date in RFC3339 format"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"CategoryInBreadcrumb": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "A single item in a category breadcrumb path",
|
||||||
|
"properties": {
|
||||||
|
"category_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "uint",
|
||||||
|
"description": "Category ID"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Category name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"B2BTopMenu": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Top-level menu item for B2B back-office",
|
||||||
|
"properties": {
|
||||||
|
"menu_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Menu item ID"
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Menu label as JSON (multilingual, e.g. {\"en\": \"Dashboard\", \"pl\": \"Panel\"})"
|
||||||
|
},
|
||||||
|
"parent_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Parent menu ID (null for root items)"
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Menu item parameters as JSON"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Active status (1 = active, 0 = inactive)"
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Sort position"
|
||||||
|
},
|
||||||
|
"children": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/B2BTopMenu"
|
||||||
|
},
|
||||||
|
"description": "Child menu items"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes": {
|
"securitySchemes": {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ func MenuHandlerRoutes(r fiber.Router) fiber.Router {
|
|||||||
handler := NewMenuHandler()
|
handler := NewMenuHandler()
|
||||||
|
|
||||||
r.Get("/get-category-tree", handler.GetCategoryTree)
|
r.Get("/get-category-tree", handler.GetCategoryTree)
|
||||||
|
r.Get("/get-breadcrumb", handler.GetBreadcrumb)
|
||||||
r.Get("/get-top-menu", handler.GetTopMenu)
|
r.Get("/get-top-menu", handler.GetTopMenu)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
@@ -54,6 +55,36 @@ func (h *MenuHandler) GetCategoryTree(c fiber.Ctx) error {
|
|||||||
return c.JSON(response.Make(&category_tree, 0, i18n.T_(c, response.Message_OK)))
|
return c.JSON(response.Make(&category_tree, 0, i18n.T_(c, response.Message_OK)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *MenuHandler) GetBreadcrumb(c fiber.Ctx) error {
|
||||||
|
lang_id, ok := c.Locals("langID").(uint)
|
||||||
|
if !ok {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
root_category_id_attribute := c.Query("root_category_id")
|
||||||
|
root_category_id, err := strconv.Atoi(root_category_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
category_id_attribute := c.Query("category_id")
|
||||||
|
category_id, err := strconv.Atoi(category_id_attribute)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
|
||||||
|
}
|
||||||
|
|
||||||
|
breadcrumb, err := h.menuService.GetBreadcrumb(uint(root_category_id), uint(category_id), lang_id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(responseErrors.GetErrorStatus(err)).
|
||||||
|
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(response.Make(&breadcrumb, 0, i18n.T_(c, response.Message_OK)))
|
||||||
|
}
|
||||||
|
|
||||||
func (h *MenuHandler) GetTopMenu(c fiber.Ctx) error {
|
func (h *MenuHandler) GetTopMenu(c fiber.Ctx) error {
|
||||||
lang_id, ok := c.Locals("langID").(uint)
|
lang_id, ok := c.Locals("langID").(uint)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ type AppSettings struct {
|
|||||||
Environment string `json:"environment"`
|
Environment string `json:"environment"`
|
||||||
BaseURL string `json:"base_url"`
|
BaseURL string `json:"base_url"`
|
||||||
PasswordRegex string `json:"password_regex"`
|
PasswordRegex string `json:"password_regex"`
|
||||||
|
CategoryTreeRootID uint `json:"category_tree_root_id"`
|
||||||
|
ShopDefaultLanguage uint `json:"shop_default_language"`
|
||||||
// Config config.Config `json:"config"`
|
// Config config.Config `json:"config"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +71,8 @@ func (h *SettingsHandler) GetSettings(cfg *config.Config) fiber.Handler {
|
|||||||
Environment: cfg.App.Environment,
|
Environment: cfg.App.Environment,
|
||||||
BaseURL: cfg.App.BaseURL,
|
BaseURL: cfg.App.BaseURL,
|
||||||
PasswordRegex: constdata.PASSWORD_VALIDATION_REGEX,
|
PasswordRegex: constdata.PASSWORD_VALIDATION_REGEX,
|
||||||
|
CategoryTreeRootID: constdata.CATEGORY_TREE_ROOT_ID,
|
||||||
|
ShopDefaultLanguage: constdata.SHOP_DEFAULT_LANGUAGE,
|
||||||
// Config: *config.Get(),
|
// Config: *config.Get(),
|
||||||
},
|
},
|
||||||
Server: ServerSettings{
|
Server: ServerSettings{
|
||||||
|
|||||||
33
app/model/category.go
Normal file
33
app/model/category.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
type ScannedCategory struct {
|
||||||
|
CategoryID uint `gorm:"column:category_id;primaryKey"`
|
||||||
|
Name string `gorm:"column:name"`
|
||||||
|
Active uint `gorm:"column:active"`
|
||||||
|
Position uint `gorm:"column:position"`
|
||||||
|
ParentID uint `gorm:"column:id_parent"`
|
||||||
|
IsRoot uint `gorm:"column:is_root_category"`
|
||||||
|
LinkRewrite string `gorm:"column:link_rewrite"`
|
||||||
|
IsoCode string `gorm:"column:iso_code"`
|
||||||
|
|
||||||
|
Visited bool //this is for internal backend use only
|
||||||
|
}
|
||||||
|
|
||||||
|
type Category struct {
|
||||||
|
CategoryID uint `json:"category_id" form:"category_id"`
|
||||||
|
Label string `json:"label" form:"label"`
|
||||||
|
// Active bool `json:"active" form:"active"`
|
||||||
|
Params CategoryParams `json:"params" form:"params"`
|
||||||
|
Children []Category `json:"children" form:"children"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CategoryParams struct {
|
||||||
|
CategoryID uint `json:"category_id" form:"category_id"`
|
||||||
|
LinkRewrite string `json:"link_rewrite" form:"link_rewrite"`
|
||||||
|
Locale string `json:"locale" form:"locale"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CategoryInBreadcrumb struct {
|
||||||
|
CategoryID uint `json:"category_id" form:"category_id"`
|
||||||
|
Name string `json:"name" form:"name"`
|
||||||
|
}
|
||||||
@@ -84,30 +84,4 @@ type ProductFilters struct {
|
|||||||
InStock uint `query:"stock,omitempty"`
|
InStock uint `query:"stock,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScannedCategory struct {
|
|
||||||
CategoryID uint `gorm:"column:category_id;primaryKey"`
|
|
||||||
Name string `gorm:"column:name"`
|
|
||||||
Active uint `gorm:"column:active"`
|
|
||||||
Position uint `gorm:"column:position"`
|
|
||||||
ParentID uint `gorm:"column:id_parent"`
|
|
||||||
IsRoot uint `gorm:"column:is_root_category"`
|
|
||||||
LinkRewrite string `gorm:"column:link_rewrite"`
|
|
||||||
IsoCode string `gorm:"column:iso_code"`
|
|
||||||
|
|
||||||
Visited bool //this is for internal backend use only
|
|
||||||
}
|
|
||||||
type Category struct {
|
|
||||||
CategoryID uint `json:"category_id" form:"category_id"`
|
|
||||||
Label string `json:"label" form:"label"`
|
|
||||||
// Active bool `json:"active" form:"active"`
|
|
||||||
Params CategoryParams `json:"params" form:"params"`
|
|
||||||
Children []Category `json:"children" form:"children"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CategoryParams struct {
|
|
||||||
CategoryID uint `json:"category_id" form:"category_id"`
|
|
||||||
LinkRewrite string `json:"link_rewrite" form:"link_rewrite"`
|
|
||||||
Locale string `json:"locale" form:"locale"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type FeatVal = map[uint][]uint
|
type FeatVal = map[uint][]uint
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ type ProductDescription struct {
|
|||||||
DeliveryInStock string `gorm:"column:delivery_in_stock;type:varchar(255)" json:"delivery_in_stock" form:"delivery_in_stock"`
|
DeliveryInStock string `gorm:"column:delivery_in_stock;type:varchar(255)" json:"delivery_in_stock" form:"delivery_in_stock"`
|
||||||
DeliveryOutStock string `gorm:"column:delivery_out_stock;type:varchar(255)" json:"delivery_out_stock" form:"delivery_out_stock"`
|
DeliveryOutStock string `gorm:"column:delivery_out_stock;type:varchar(255)" json:"delivery_out_stock" form:"delivery_out_stock"`
|
||||||
Usage string `gorm:"column:usage;type:text" json:"usage" form:"usage"`
|
Usage string `gorm:"column:usage;type:text" json:"usage" form:"usage"`
|
||||||
|
|
||||||
|
ExistsInDatabse bool `gorm:"-" json:"exists_in_database"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductRow struct {
|
type ProductRow struct {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package productDescriptionRepo
|
package productDescriptionRepo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/db"
|
"git.ma-al.com/goc_daniel/b2b/app/db"
|
||||||
@@ -8,6 +9,7 @@ import (
|
|||||||
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
|
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
|
||||||
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
|
||||||
"github.com/WinterYukky/gorm-extra-clause-plugin/exclause"
|
"github.com/WinterYukky/gorm-extra-clause-plugin/exclause"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UIProductDescriptionRepo interface {
|
type UIProductDescriptionRepo interface {
|
||||||
@@ -35,8 +37,14 @@ func (r *ProductDescriptionRepo) GetProductDescription(productID uint, productid
|
|||||||
IDLang: int32(productid_lang),
|
IDLang: int32(productid_lang),
|
||||||
}).
|
}).
|
||||||
First(&ProductDescription).Error
|
First(&ProductDescription).Error
|
||||||
if err != nil {
|
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
// handle "not found" case only
|
||||||
|
ProductDescription.ExistsInDatabse = false
|
||||||
|
} else if err != nil {
|
||||||
return nil, fmt.Errorf("database error: %w", err)
|
return nil, fmt.Errorf("database error: %w", err)
|
||||||
|
} else {
|
||||||
|
ProductDescription.ExistsInDatabse = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ProductDescription, nil
|
return &ProductDescription, nil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package menuService
|
package menuService
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"git.ma-al.com/goc_daniel/b2b/app/model"
|
"git.ma-al.com/goc_daniel/b2b/app/model"
|
||||||
@@ -112,6 +113,69 @@ func (a ByPosition) Len() int { return len(a) }
|
|||||||
func (a ByPosition) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
func (a ByPosition) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
func (a ByPosition) Less(i, j int) bool { return a[i].Position < a[j].Position }
|
func (a ByPosition) Less(i, j int) bool { return a[i].Position < a[j].Position }
|
||||||
|
|
||||||
|
func (s *MenuService) GetBreadcrumb(root_category_id uint, start_category_id uint, id_lang uint) ([]model.CategoryInBreadcrumb, error) {
|
||||||
|
all_categories, err := s.categoriesRepo.GetAllCategories(id_lang)
|
||||||
|
if err != nil {
|
||||||
|
return []model.CategoryInBreadcrumb{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
breadcrumb := []model.CategoryInBreadcrumb{}
|
||||||
|
|
||||||
|
start_index := 0
|
||||||
|
start_found := false
|
||||||
|
for i := 0; i < len(all_categories); i++ {
|
||||||
|
if all_categories[i].CategoryID == start_category_id {
|
||||||
|
start_index = i
|
||||||
|
start_found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !start_found {
|
||||||
|
return []model.CategoryInBreadcrumb{}, responseErrors.ErrStartCategoryNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// map category ids to indices
|
||||||
|
id_to_index := make(map[uint]int)
|
||||||
|
for i := 0; i < len(all_categories); i++ {
|
||||||
|
all_categories[i].Visited = false
|
||||||
|
id_to_index[all_categories[i].CategoryID] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
// do a simple graph traversal, always jumping from node to its parent
|
||||||
|
index := start_index
|
||||||
|
success := true
|
||||||
|
for {
|
||||||
|
if all_categories[index].Visited {
|
||||||
|
success = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
all_categories[index].Visited = true
|
||||||
|
|
||||||
|
var next_category model.CategoryInBreadcrumb
|
||||||
|
next_category.CategoryID = all_categories[index].CategoryID
|
||||||
|
next_category.Name = all_categories[index].Name
|
||||||
|
breadcrumb = append(breadcrumb, next_category)
|
||||||
|
|
||||||
|
if all_categories[index].CategoryID == root_category_id {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
next_index, ok := id_to_index[all_categories[index].ParentID]
|
||||||
|
if !ok {
|
||||||
|
success = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
index = next_index
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.Reverse(breadcrumb)
|
||||||
|
|
||||||
|
if !success {
|
||||||
|
return breadcrumb, responseErrors.ErrRootNeverReached
|
||||||
|
}
|
||||||
|
|
||||||
|
return breadcrumb, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *MenuService) GetTopMenu(id uint) ([]*model.B2BTopMenu, error) {
|
func (s *MenuService) GetTopMenu(id uint) ([]*model.B2BTopMenu, error) {
|
||||||
items, err := s.routesRepo.GetTopMenu(id)
|
items, err := s.routesRepo.GetTopMenu(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ package constdata
|
|||||||
// PASSWORD_VALIDATION_REGEX is used by the frontend (JavaScript supports lookaheads).
|
// PASSWORD_VALIDATION_REGEX is used by the frontend (JavaScript supports lookaheads).
|
||||||
const PASSWORD_VALIDATION_REGEX = `^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{10,}$`
|
const PASSWORD_VALIDATION_REGEX = `^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{10,}$`
|
||||||
const SHOP_ID = 1
|
const SHOP_ID = 1
|
||||||
|
const SHOP_DEFAULT_LANGUAGE = 1
|
||||||
|
|
||||||
|
// CATEGORY_TREE_ROOT_ID corresponds to id_category in ps_category which has is_root_category=1
|
||||||
|
const CATEGORY_TREE_ROOT_ID = 2
|
||||||
|
|
||||||
const MAX_AMOUNT_OF_CARTS_PER_USER = 10
|
const MAX_AMOUNT_OF_CARTS_PER_USER = 10
|
||||||
const DEFAULT_NEW_CART_NAME = "new cart"
|
const DEFAULT_NEW_CART_NAME = "new cart"
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ var (
|
|||||||
// Typed errors for menu handler
|
// Typed errors for menu handler
|
||||||
ErrNoRootFound = errors.New("no root found in categories table")
|
ErrNoRootFound = errors.New("no root found in categories table")
|
||||||
ErrCircularDependency = errors.New("circular dependency structure in tree (could be caused by improper root id)")
|
ErrCircularDependency = errors.New("circular dependency structure in tree (could be caused by improper root id)")
|
||||||
|
ErrStartCategoryNotFound = errors.New("the start category has not been found")
|
||||||
|
ErrRootNeverReached = errors.New("the root category is not an ancestor of start category")
|
||||||
|
|
||||||
// Typed errors for carts handler
|
// Typed errors for carts handler
|
||||||
ErrMaxAmtOfCartsReached = errors.New("maximal amount of carts reached")
|
ErrMaxAmtOfCartsReached = errors.New("maximal amount of carts reached")
|
||||||
@@ -148,6 +150,10 @@ func GetErrorCode(c fiber.Ctx, err error) string {
|
|||||||
return i18n.T_(c, "error.no_root_found")
|
return i18n.T_(c, "error.no_root_found")
|
||||||
case errors.Is(err, ErrCircularDependency):
|
case errors.Is(err, ErrCircularDependency):
|
||||||
return i18n.T_(c, "error.circular_dependency")
|
return i18n.T_(c, "error.circular_dependency")
|
||||||
|
case errors.Is(err, ErrStartCategoryNotFound):
|
||||||
|
return i18n.T_(c, "error.start_category_not_found")
|
||||||
|
case errors.Is(err, ErrRootNeverReached):
|
||||||
|
return i18n.T_(c, "error.root_never_reached")
|
||||||
|
|
||||||
case errors.Is(err, ErrMaxAmtOfCartsReached):
|
case errors.Is(err, ErrMaxAmtOfCartsReached):
|
||||||
return i18n.T_(c, "error.max_amt_of_carts_reached")
|
return i18n.T_(c, "error.max_amt_of_carts_reached")
|
||||||
@@ -193,6 +199,8 @@ func GetErrorStatus(err error) int {
|
|||||||
errors.Is(err, ErrBadPaging),
|
errors.Is(err, ErrBadPaging),
|
||||||
errors.Is(err, ErrNoRootFound),
|
errors.Is(err, ErrNoRootFound),
|
||||||
errors.Is(err, ErrCircularDependency),
|
errors.Is(err, ErrCircularDependency),
|
||||||
|
errors.Is(err, ErrStartCategoryNotFound),
|
||||||
|
errors.Is(err, ErrRootNeverReached),
|
||||||
errors.Is(err, ErrMaxAmtOfCartsReached),
|
errors.Is(err, ErrMaxAmtOfCartsReached),
|
||||||
errors.Is(err, ErrUserHasNoSuchCart),
|
errors.Is(err, ErrUserHasNoSuchCart),
|
||||||
errors.Is(err, ErrProductOrItsVariationDoesNotExist):
|
errors.Is(err, ErrProductOrItsVariationDoesNotExist):
|
||||||
|
|||||||
22
bruno/b2b-daniel/get-breadcrumb.yml
Normal file
22
bruno/b2b-daniel/get-breadcrumb.yml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
info:
|
||||||
|
name: get-breadcrumb
|
||||||
|
type: http
|
||||||
|
seq: 18
|
||||||
|
|
||||||
|
http:
|
||||||
|
method: GET
|
||||||
|
url: http://localhost:3000/api/v1/restricted/menu/get-breadcrumb?root_category_id=10&category_id=13
|
||||||
|
params:
|
||||||
|
- name: root_category_id
|
||||||
|
value: "10"
|
||||||
|
type: query
|
||||||
|
- name: category_id
|
||||||
|
value: "13"
|
||||||
|
type: query
|
||||||
|
auth: inherit
|
||||||
|
|
||||||
|
settings:
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
followRedirects: true
|
||||||
|
maxRedirects: 5
|
||||||
@@ -5,10 +5,10 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: http://localhost:3000/api/v1/restricted/menu/get-category-tree?root_category_id=3
|
url: http://localhost:3000/api/v1/restricted/menu/get-category-tree?root_category_id=10
|
||||||
params:
|
params:
|
||||||
- name: root_category_id
|
- name: root_category_id
|
||||||
value: "3"
|
value: "10"
|
||||||
type: query
|
type: query
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ info:
|
|||||||
|
|
||||||
http:
|
http:
|
||||||
method: GET
|
method: GET
|
||||||
url: http://localhost:3000/api/v1/restricted/product-translation/get-product-description?productID=51&productLangID=2
|
url: http://localhost:3000/api/v1/restricted/product-translation/get-product-description?productID=51&productLangID=4
|
||||||
params:
|
params:
|
||||||
- name: productID
|
- name: productID
|
||||||
value: "51"
|
value: "51"
|
||||||
type: query
|
type: query
|
||||||
- name: productLangID
|
- name: productLangID
|
||||||
value: "2"
|
value: "4"
|
||||||
type: query
|
type: query
|
||||||
auth: inherit
|
auth: inherit
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user