most importantly: new category and filter on is_new

This commit is contained in:
Daniel Goc
2026-04-13 15:29:21 +02:00
parent 7f05d39b38
commit ce4cadaa16
14 changed files with 159 additions and 189 deletions

View File

@@ -10,7 +10,6 @@ import (
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/service/authService" "git.ma-al.com/goc_daniel/b2b/app/service/authService"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data" constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
"github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3"
) )
@@ -115,26 +114,6 @@ func AuthMiddleware() fiber.Handler {
} }
} }
// RequireAdmin creates admin-only middleware
func RequireAdmin() fiber.Handler {
return func(c fiber.Ctx) error {
originalUserRole, ok := localeExtractor.GetOriginalUserRole(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "not authenticated",
})
}
if model.CustomerRole(originalUserRole.Name) != model.RoleAdmin {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
"error": "admin access required",
})
}
return c.Next()
}
}
// Webdav // Webdav
func Webdav() fiber.Handler { func Webdav() fiber.Handler {
authService := authService.NewAuthService() authService := authService.NewAuthService()

View File

@@ -3,9 +3,13 @@ package perms
type Permission string type Permission string
const ( const (
UserReadAny Permission = "user.read.any" UserReadAny Permission = "user.read.any"
UserWriteAny Permission = "user.write.any" UserWriteAny Permission = "user.write.any"
UserDeleteAny Permission = "user.delete.any" UserDeleteAny Permission = "user.delete.any"
CurrencyWrite Permission = "currency.write" CurrencyWrite Permission = "currency.write"
SpecificPriceManage Permission = "specific_price.manage" SpecificPriceManage Permission = "specific_price.manage"
CreateWebdavToken Permission = "webdav.create_token"
ProductTranslationSave Permission = "product_translation.save"
ProductTranslationTranslate Permission = "product_translation.translate"
SearchCreateIndex Permission = "search.create_index"
) )

View File

@@ -111,6 +111,7 @@ var columnMappingListProducts map[string]string = map[string]string{
"category_id": "cp.id_category", "category_id": "cp.id_category",
"quantity": "sa.quantity", "quantity": "sa.quantity",
"is_favorite": "ps.is_favorite", "is_favorite": "ps.is_favorite",
"is_new": "is_new",
} }
func (h *ProductsHandler) AddToFavorites(c fiber.Ctx) error { func (h *ProductsHandler) AddToFavorites(c fiber.Ctx) error {

View File

@@ -4,7 +4,7 @@ import (
"strconv" "strconv"
"git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/config"
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
"git.ma-al.com/goc_daniel/b2b/app/service/productTranslationService" "git.ma-al.com/goc_daniel/b2b/app/service/productTranslationService"
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n" "git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor" "git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
@@ -35,8 +35,8 @@ func ProductTranslationHandlerRoutes(r fiber.Router) fiber.Router {
handler := NewProductTranslationHandler() handler := NewProductTranslationHandler()
r.Get("/get-product-description", handler.GetProductDescription) r.Get("/get-product-description", handler.GetProductDescription)
r.Post("/save-product-description", handler.SaveProductDescription) r.Post("/save-product-description", middleware.Require("product_translation.save"), handler.SaveProductDescription)
r.Get("/translate-product-description", handler.TranslateProductDescription) r.Get("/translate-product-description", middleware.Require("product_translation.translate"), handler.TranslateProductDescription)
return r return r
} }
@@ -80,12 +80,6 @@ func (h *ProductTranslationHandler) SaveProductDescription(c fiber.Ctx) error {
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody))) JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
} }
userRole, ok := localeExtractor.GetOriginalUserRole(c)
if !ok || model.CustomerRole(userRole.Name) != model.RoleAdmin {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrAdminAccessRequired)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrAdminAccessRequired)))
}
productID_attribute := c.Query("productID") productID_attribute := c.Query("productID")
productID, err := strconv.Atoi(productID_attribute) productID, err := strconv.Atoi(productID_attribute)
if err != nil { if err != nil {
@@ -123,12 +117,6 @@ func (h *ProductTranslationHandler) TranslateProductDescription(c fiber.Ctx) err
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody))) JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
} }
userRole, ok := localeExtractor.GetOriginalUserRole(c)
if !ok || model.CustomerRole(userRole.Name) != model.RoleAdmin {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrAdminAccessRequired)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrAdminAccessRequired)))
}
productID_attribute := c.Query("productID") productID_attribute := c.Query("productID")
productID, err := strconv.Atoi(productID_attribute) productID, err := strconv.Atoi(productID_attribute)
if err != nil { if err != nil {

View File

@@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
"git.ma-al.com/goc_daniel/b2b/app/service/meiliService" "git.ma-al.com/goc_daniel/b2b/app/service/meiliService"
searchservice "git.ma-al.com/goc_daniel/b2b/app/service/searchService" searchservice "git.ma-al.com/goc_daniel/b2b/app/service/searchService"
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n" "git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
@@ -30,7 +30,7 @@ func NewMeiliSearchHandler() *MeiliSearchHandler {
func MeiliSearchHandlerRoutes(r fiber.Router) fiber.Router { func MeiliSearchHandlerRoutes(r fiber.Router) fiber.Router {
handler := NewMeiliSearchHandler() handler := NewMeiliSearchHandler()
r.Get("/create-index", handler.CreateIndex) r.Get("/create-index", middleware.Require("search.create_index"), handler.CreateIndex)
r.Post("/search", handler.Search) r.Post("/search", handler.Search)
r.Post("/settings", handler.GetSettings) r.Post("/settings", handler.GetSettings)
@@ -44,12 +44,6 @@ func (h *MeiliSearchHandler) CreateIndex(c fiber.Ctx) error {
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
} }
userRole, ok := localeExtractor.GetOriginalUserRole(c)
if !ok || model.CustomerRole(userRole.Name) != model.RoleAdmin {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrAdminAccessRequired)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrAdminAccessRequired)))
}
err := h.meiliService.CreateIndex(id_lang) err := h.meiliService.CreateIndex(id_lang)
if err != nil { if err != nil {
fmt.Printf("CreateIndex error: %v\n", err) fmt.Printf("CreateIndex error: %v\n", err)

View File

@@ -4,7 +4,7 @@ import (
"strconv" "strconv"
"git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/config"
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/delivery/middleware"
"git.ma-al.com/goc_daniel/b2b/app/service/storageService" "git.ma-al.com/goc_daniel/b2b/app/service/storageService"
"git.ma-al.com/goc_daniel/b2b/app/utils/i18n" "git.ma-al.com/goc_daniel/b2b/app/utils/i18n"
"git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor" "git.ma-al.com/goc_daniel/b2b/app/utils/localeExtractor"
@@ -34,7 +34,7 @@ func StorageHandlerRoutes(r fiber.Router) fiber.Router {
r.Get("/download-file/*", handler.DownloadFile) r.Get("/download-file/*", handler.DownloadFile)
// for admins only // for admins only
r.Get("/create-new-webdav-token", handler.CreateNewWebdavToken) r.Get("/create-new-webdav-token", middleware.Require("webdav.create_token"), handler.CreateNewWebdavToken)
return r return r
} }
@@ -84,12 +84,6 @@ func (h *StorageHandler) CreateNewWebdavToken(c fiber.Ctx) error {
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody))) JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
} }
userRole, ok := localeExtractor.GetOriginalUserRole(c)
if !ok || model.CustomerRole(userRole.Name) != model.RoleAdmin {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrAdminAccessRequired)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrAdminAccessRequired)))
}
new_token, err := h.storageService.NewWebdavToken(userID) new_token, err := h.storageService.NewWebdavToken(userID)
if err != nil { if err != nil {
return c.Status(responseErrors.GetErrorStatus(err)). return c.Status(responseErrors.GetErrorStatus(err)).

View File

@@ -161,16 +161,6 @@ func (s *Server) Setup() error {
// }) // })
// }) // })
// // Admin routes example
// admin := s.api.Group("/admin")
// admin.Use(middleware.AuthMiddleware())
// admin.Use(middleware.RequireAdmin())
// admin.Get("/users", func(c fiber.Ctx) error {
// return c.JSON(fiber.Map{
// "message": "Admin area - user management",
// })
// })
// keep this at the end because its wilderange // keep this at the end because its wilderange
general.InitBo(s.App()) general.InitBo(s.App())

View File

@@ -12,6 +12,7 @@ type ProductInList struct {
PriceTaxExcl float64 `gorm:"column:price_tax_excl" json:"price_tax_excl"` PriceTaxExcl float64 `gorm:"column:price_tax_excl" json:"price_tax_excl"`
PriceTaxIncl float64 `gorm:"column:price_tax_incl" json:"price_tax_incl"` PriceTaxIncl float64 `gorm:"column:price_tax_incl" json:"price_tax_incl"`
IsFavorite bool `gorm:"column:is_favorite" json:"is_favorite"` IsFavorite bool `gorm:"column:is_favorite" json:"is_favorite"`
IsNew uint `gorm:"column:is_new" json:"is_new"`
} }
type ProductFilters struct { type ProductFilters struct {

View File

@@ -9,7 +9,6 @@ import (
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model"
"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"
"gorm.io/gorm" "gorm.io/gorm"
) )
@@ -17,7 +16,6 @@ type UIProductDescriptionRepo interface {
GetProductDescription(productID uint, productid_lang uint) (*model.ProductDescription, error) GetProductDescription(productID uint, productid_lang uint) (*model.ProductDescription, error)
CreateIfDoesNotExist(productID uint, productid_lang uint) error CreateIfDoesNotExist(productID uint, productid_lang uint) error
UpdateFields(productID uint, productid_lang uint, updates map[string]string) error UpdateFields(productID uint, productid_lang uint, updates map[string]string) error
GetMeiliProducts(id_lang uint, offset, limit int) ([]model.MeiliSearchProduct, error)
} }
type ProductDescriptionRepo struct{} type ProductDescriptionRepo struct{}
@@ -118,108 +116,3 @@ func (r *ProductDescriptionRepo) UpdateFields(productID uint, productid_lang uin
return nil return nil
} }
// GetMeiliProductsBatchedScanned returns a batch of products with LIMIT/OFFSET pagination
// The scanning is done inside the repo to keep the service layer cleaner
func (r *ProductDescriptionRepo) GetMeiliProducts(id_lang uint, offset, limit int) ([]model.MeiliSearchProduct, error) {
var products []model.MeiliSearchProduct
err := db.Get().
Table("ps_product_shop ps").
Select(`
ps.id_product AS id_product,
pl.name AS name,
TRIM(REGEXP_REPLACE(REGEXP_REPLACE(pl.description_short, '<[^>]*>', ' '), '[[:space:]]+', ' ')) AS description,
p.ean13,
p.reference,
ps.price,
ps.id_category_default AS id_category,
cl.name AS cat_name,
cl.link_rewrite AS l_rew,
COALESCE(vary.attributes, JSON_OBJECT()) AS attr,
COALESCE(feat.features, JSON_OBJECT()) AS feat,
img.id_image,
cat.category_ids,
(SELECT COUNT(*) FROM ps_product_attribute_shop pas2 WHERE pas2.id_product = ps.id_product AND pas2.id_shop = ?) AS variations
`, constdata.SHOP_ID).
Joins("JOIN ps_product p ON p.id_product = ps.id_product").
Joins("JOIN ps_product_lang pl ON pl.id_product = ps.id_product AND pl.id_shop = ? AND pl.id_lang = ?", constdata.SHOP_ID, id_lang).
Joins("JOIN ps_category_lang cl ON cl.id_category = ps.id_category_default AND cl.id_shop = ? AND cl.id_lang = ?", constdata.SHOP_ID, id_lang).
Joins("LEFT JOIN variations vary ON vary.id_product = ps.id_product").
Joins("LEFT JOIN features feat ON feat.id_product = ps.id_product").
Joins("LEFT JOIN images img ON img.id_product = ps.id_product").
Joins("LEFT JOIN categories cat ON cat.id_product = ps.id_product").
Joins("JOIN products_page pp ON pp.id_product = ps.id_product").
Where("ps.active = ?", 1).
Order("ps.id_product").
Clauses(exclause.With{CTEs: []exclause.CTE{
{
Name: "products_page",
Subquery: exclause.Subquery{
DB: db.Get().
Model(&dbmodel.PsProductShop{}).
Select("id_product, price").
Where("id_shop = ? AND active = 1", constdata.SHOP_ID).
Order("id_product").
Limit(limit).
Offset(offset),
},
},
{
Name: "variation_attributes",
Subquery: exclause.Subquery{
DB: db.Get().
Table("ps_product_attribute_shop pas"). // <- explicit alias here
Select(`
pas.id_product,
pag.id_attribute_group AS attribute_name,
JSON_ARRAYAGG(DISTINCT pa.id_attribute) AS attribute_values
`).
Joins("JOIN ps_product_attribute_combination ppac ON ppac.id_product_attribute = pas.id_product_attribute").
Joins("JOIN ps_attribute pa ON pa.id_attribute = ppac.id_attribute").
Joins("JOIN ps_attribute_group pag ON pag.id_attribute_group = pa.id_attribute_group").
Where("pas.id_shop = ?", constdata.SHOP_ID).
Group("pas.id_product, pag.id_attribute_group"),
},
},
{
Name: "variations",
Subquery: exclause.Subquery{
DB: db.Get().
Table("variation_attributes").
Select("id_product, JSON_OBJECTAGG(attribute_name, attribute_values) AS attributes").
Group("id_product"),
},
},
{
Name: "features",
Subquery: exclause.Subquery{
DB: db.Get().
Table("ps_feature_product pfp"). // <- explicit alias
Select("pfp.id_product, JSON_OBJECTAGG(pfp.id_feature, pfp.id_feature_value) AS features").
Group("pfp.id_product"),
},
},
{
Name: "images",
Subquery: exclause.Subquery{
DB: db.Get().
Model(&dbmodel.PsImageShop{}).
Select("id_product, id_image").
Where("id_shop = ? AND cover = 1", constdata.SHOP_ID),
},
},
{
Name: "categories",
Subquery: exclause.Subquery{
DB: db.Get().
Model(&dbmodel.PsCategoryProduct{}).
Select("id_product, JSON_ARRAYAGG(id_category) AS category_ids").
Group("id_product"),
},
},
}}).Find(&products).Error
return products, err
}

View File

@@ -116,7 +116,19 @@ func (repo *ProductsRepo) Find(langID uint, userID uint, p find.Paging, filt *fi
p.reference AS reference, p.reference AS reference,
COALESCE(v.variants_number, 0) AS variants_number, COALESCE(v.variants_number, 0) AS variants_number,
sa.quantity AS quantity, sa.quantity AS quantity,
COALESCE(f.is_favorite, 0) AS is_favorite COALESCE(f.is_favorite, 0) AS is_favorite,
CASE
WHEN ps.date_add >= DATE_SUB(
NOW(),
INTERVAL (
SELECT value
FROM ps_configuration
WHERE name = 'PS_NB_DAYS_NEW_PRODUCT'
) DAY
) AND ps.active = 1
THEN 1
ELSE 0
END AS is_new
`, config.Get().Image.ImagePrefix). `, config.Get().Image.ImagePrefix).
Joins("JOIN "+dbmodel.PsProductCols.IDProduct.Tab()+" p ON p.id_product = ps.id_product"). Joins("JOIN "+dbmodel.PsProductCols.IDProduct.Tab()+" p ON p.id_product = ps.id_product").
Joins("JOIN ps_product_lang pl ON pl.id_product = ps.id_product AND pl.id_lang = ?", langID). Joins("JOIN ps_product_lang pl ON pl.id_product = ps.id_product AND pl.id_lang = ?", langID).

View File

@@ -7,7 +7,11 @@ import (
"net/http" "net/http"
"git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/config"
"git.ma-al.com/goc_daniel/b2b/app/db"
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/model/dbmodel"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"github.com/WinterYukky/gorm-extra-clause-plugin/exclause"
) )
type SearchProxyResponse struct { type SearchProxyResponse struct {
@@ -17,6 +21,7 @@ type SearchProxyResponse struct {
type UISearchRepo interface { type UISearchRepo interface {
Search(index string, body []byte) (*SearchProxyResponse, error) Search(index string, body []byte) (*SearchProxyResponse, error)
GetMeiliProducts(id_lang uint, offset, limit int) ([]model.MeiliSearchProduct, error)
GetIndexSettings(index string) (*SearchProxyResponse, error) GetIndexSettings(index string) (*SearchProxyResponse, error)
GetRoutes(langId uint) ([]model.Route, error) GetRoutes(langId uint) ([]model.Route, error)
} }
@@ -80,3 +85,108 @@ func (r *SearchRepo) doRequest(method, url string, body []byte) (*SearchProxyRes
func (r *SearchRepo) GetRoutes(langId uint) ([]model.Route, error) { func (r *SearchRepo) GetRoutes(langId uint) ([]model.Route, error) {
return nil, nil return nil, nil
} }
// GetMeiliProductsProducts returns a batch of products with LIMIT/OFFSET pagination
// The scanning is done inside the repo to keep the service layer cleaner
func (r *SearchRepo) GetMeiliProducts(id_lang uint, offset, limit int) ([]model.MeiliSearchProduct, error) {
var products []model.MeiliSearchProduct
err := db.Get().
Table("ps_product_shop ps").
Select(`
ps.id_product AS id_product,
pl.name AS name,
TRIM(REGEXP_REPLACE(REGEXP_REPLACE(pl.description_short, '<[^>]*>', ' '), '[[:space:]]+', ' ')) AS description,
p.ean13,
p.reference,
ps.price,
ps.id_category_default AS id_category,
cl.name AS cat_name,
cl.link_rewrite AS l_rew,
COALESCE(vary.attributes, JSON_OBJECT()) AS attr,
COALESCE(feat.features, JSON_OBJECT()) AS feat,
img.id_image,
cat.category_ids,
(SELECT COUNT(*) FROM ps_product_attribute_shop pas2 WHERE pas2.id_product = ps.id_product AND pas2.id_shop = ?) AS variations
`, constdata.SHOP_ID).
Joins("JOIN ps_product p ON p.id_product = ps.id_product").
Joins("JOIN ps_product_lang pl ON pl.id_product = ps.id_product AND pl.id_shop = ? AND pl.id_lang = ?", constdata.SHOP_ID, id_lang).
Joins("JOIN ps_category_lang cl ON cl.id_category = ps.id_category_default AND cl.id_shop = ? AND cl.id_lang = ?", constdata.SHOP_ID, id_lang).
Joins("LEFT JOIN variations vary ON vary.id_product = ps.id_product").
Joins("LEFT JOIN features feat ON feat.id_product = ps.id_product").
Joins("LEFT JOIN images img ON img.id_product = ps.id_product").
Joins("LEFT JOIN categories cat ON cat.id_product = ps.id_product").
Joins("JOIN products_page pp ON pp.id_product = ps.id_product").
Where("ps.active = ?", 1).
Order("ps.id_product").
Clauses(exclause.With{CTEs: []exclause.CTE{
{
Name: "products_page",
Subquery: exclause.Subquery{
DB: db.Get().
Model(&dbmodel.PsProductShop{}).
Select("id_product, price").
Where("id_shop = ? AND active = 1", constdata.SHOP_ID).
Order("id_product").
Limit(limit).
Offset(offset),
},
},
{
Name: "variation_attributes",
Subquery: exclause.Subquery{
DB: db.Get().
Table("ps_product_attribute_shop pas"). // <- explicit alias here
Select(`
pas.id_product,
pag.id_attribute_group AS attribute_name,
JSON_ARRAYAGG(DISTINCT pa.id_attribute) AS attribute_values
`).
Joins("JOIN ps_product_attribute_combination ppac ON ppac.id_product_attribute = pas.id_product_attribute").
Joins("JOIN ps_attribute pa ON pa.id_attribute = ppac.id_attribute").
Joins("JOIN ps_attribute_group pag ON pag.id_attribute_group = pa.id_attribute_group").
Where("pas.id_shop = ?", constdata.SHOP_ID).
Group("pas.id_product, pag.id_attribute_group"),
},
},
{
Name: "variations",
Subquery: exclause.Subquery{
DB: db.Get().
Table("variation_attributes").
Select("id_product, JSON_OBJECTAGG(attribute_name, attribute_values) AS attributes").
Group("id_product"),
},
},
{
Name: "features",
Subquery: exclause.Subquery{
DB: db.Get().
Table("ps_feature_product pfp"). // <- explicit alias
Select("pfp.id_product, JSON_OBJECTAGG(pfp.id_feature, pfp.id_feature_value) AS features").
Group("pfp.id_product"),
},
},
{
Name: "images",
Subquery: exclause.Subquery{
DB: db.Get().
Model(&dbmodel.PsImageShop{}).
Select("id_product, id_image").
Where("id_shop = ? AND cover = 1", constdata.SHOP_ID),
},
},
{
Name: "categories",
Subquery: exclause.Subquery{
DB: db.Get().
Model(&dbmodel.PsCategoryProduct{}).
Select("id_product, JSON_ARRAYAGG(id_category) AS category_ids").
Group("id_product"),
},
},
}}).Find(&products).Error
return products, err
}

View File

@@ -6,7 +6,7 @@ import (
"git.ma-al.com/goc_daniel/b2b/app/config" "git.ma-al.com/goc_daniel/b2b/app/config"
"git.ma-al.com/goc_daniel/b2b/app/model" "git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/repos/productDescriptionRepo" searchrepo "git.ma-al.com/goc_daniel/b2b/app/repos/searchRepo"
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/meilisearch/meilisearch-go" "github.com/meilisearch/meilisearch-go"
) )
@@ -20,8 +20,8 @@ type MeiliIndexSettings struct {
} }
type MeiliService struct { type MeiliService struct {
productDescriptionRepo productDescriptionRepo.UIProductDescriptionRepo searchRepo searchrepo.UISearchRepo
meiliClient meilisearch.ServiceManager meiliClient meilisearch.ServiceManager
} }
func New() *MeiliService { func New() *MeiliService {
@@ -32,8 +32,8 @@ func New() *MeiliService {
) )
return &MeiliService{ return &MeiliService{
meiliClient: client, meiliClient: client,
productDescriptionRepo: productDescriptionRepo.New(), searchRepo: searchrepo.New(),
} }
} }
@@ -50,7 +50,7 @@ func (s *MeiliService) CreateIndex(id_lang uint) error {
for { for {
// Get batch of products from repo (includes scanning) // Get batch of products from repo (includes scanning)
products, err := s.productDescriptionRepo.GetMeiliProducts(id_lang, offset, batchSize) products, err := s.searchRepo.GetMeiliProducts(id_lang, offset, batchSize)
if err != nil { if err != nil {
return fmt.Errorf("failed to get products batch at offset %d: %w", offset, err) return fmt.Errorf("failed to get products batch at offset %d: %w", offset, err)
} }

View File

@@ -22,14 +22,6 @@ func GetUserID(c fiber.Ctx) (uint, bool) {
return user_locale.User.ID, true return user_locale.User.ID, true
} }
func GetOriginalUserRole(c fiber.Ctx) (model.Role, bool) {
user_locale, ok := c.Locals(constdata.USER_LOCALE).(*model.UserLocale)
if !ok || user_locale.OriginalUser == nil || user_locale.OriginalUser.Role == nil {
return model.Role{}, false
}
return *user_locale.OriginalUser.Role, true
}
func GetCustomer(c fiber.Ctx) (*model.Customer, bool) { func GetCustomer(c fiber.Ctx) (*model.Customer, bool) {
user_locale, ok := c.Locals(constdata.USER_LOCALE).(*model.UserLocale) user_locale, ok := c.Locals(constdata.USER_LOCALE).(*model.UserLocale)
if !ok || user_locale.User == nil { if !ok || user_locale.User == nil {

View File

@@ -35,15 +35,27 @@ INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('2', 'user.write.any');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('3', 'user.delete.any'); INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('3', 'user.delete.any');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('4', 'currency.write'); INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('4', 'currency.write');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('5', 'specific_price.manage'); INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('5', 'specific_price.manage');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('6', 'webdav.create_token');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('7', 'product_translation.save');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('8', 'product_translation.translate');
INSERT INTO `b2b_permissions` (`id`, `name`) VALUES ('9', 'search.create_index');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '1'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '1');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '2'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '2');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '3'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '3');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '4'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '4');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '5'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '5');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '6');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '7');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '8');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('2', '9');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '1'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '1');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '2'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '2');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '3'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '3');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '4'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '4');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '5'); INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '5');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '6');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '7');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '8');
INSERT INTO `b2b_role_permissions` (`role_id`, `permission_id`) VALUES ('3', '9');
-- +goose Down -- +goose Down