Merge branch 'main' of ssh://git.ma-al.com:8822/goc_daniel/b2b into no-vat-customers

This commit is contained in:
2026-04-14 13:40:37 +02:00
16 changed files with 140 additions and 49 deletions

View File

@@ -10,14 +10,14 @@ import (
"git.ma-al.com/goc_daniel/b2b/app/model"
"git.ma-al.com/goc_daniel/b2b/app/service/authService"
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"
)
// AuthMiddleware creates authentication middleware
func AuthMiddleware() fiber.Handler {
func Authenticate() fiber.Handler {
authService := authService.NewAuthService()
return func(c fiber.Ctx) error {
// Get token from Authorization header
authHeader := c.Get("Authorization")
@@ -25,17 +25,13 @@ func AuthMiddleware() fiber.Handler {
// Try to get from cookie
authHeader = c.Cookies("access_token")
if authHeader == "" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "authorization token required",
})
return c.Next()
}
} else {
// Extract token from "Bearer <token>"
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "invalid authorization header format",
})
return c.Next()
}
authHeader = parts[1]
}
@@ -43,24 +39,18 @@ func AuthMiddleware() fiber.Handler {
// Validate token
claims, err := authService.ValidateToken(authHeader)
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "invalid or expired token",
})
return c.Next()
}
// Get user from database
user, err := authService.GetUserByID(claims.UserID)
if err != nil {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "user not found",
})
return c.Next()
}
// Check if user is active
if !user.IsActive {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
"error": "user account is inactive",
})
return c.Next()
}
// Create locale. LangID is overwritten by auth Token
@@ -79,9 +69,7 @@ func AuthMiddleware() fiber.Handler {
// We now populate the target user
if model.CustomerRole(user.Role.Name) != model.RoleAdmin {
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
"error": "admin access required",
})
return c.Next()
}
targetUserID, err := strconv.Atoi(targetUserIDAttribute)
@@ -114,6 +102,18 @@ func AuthMiddleware() fiber.Handler {
}
}
func Authorize() fiber.Handler {
return func(c fiber.Ctx) error {
_, ok := localeExtractor.GetUserID(c)
if !ok {
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
"error": "not authenticated",
})
}
return c.Next()
}
}
// Webdav
func Webdav() fiber.Handler {
authService := authService.NewAuthService()

View File

@@ -49,7 +49,7 @@ func AuthHandlerRoutes(r fiber.Router) fiber.Router {
r.Get("/google", handler.GoogleLogin)
r.Get("/google/callback", handler.GoogleCallback)
authProtected := r.Group("", middleware.AuthMiddleware())
authProtected := r.Group("", middleware.Authorize())
authProtected.Get("/me", handler.Me)
authProtected.Post("/update-choice", handler.UpdateJWTToken)

View File

@@ -2,6 +2,7 @@ package public
import (
"git.ma-al.com/goc_daniel/b2b/app/service/menuService"
constdata "git.ma-al.com/goc_daniel/b2b/app/utils/const_data"
"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/nullable"
@@ -31,12 +32,21 @@ func RoutingHandlerRoutes(r fiber.Router) fiber.Router {
}
func (h *RoutingHandler) GetRouting(c fiber.Ctx) error {
lang_id, ok := localeExtractor.GetLangID(c)
langId, ok := localeExtractor.GetLangID(c)
if !ok {
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute)))
return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrInvalidBody)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrInvalidBody)))
}
menu, err := h.menuService.GetRoutes(lang_id)
var roleId uint
customer, ok := localeExtractor.GetCustomer(c)
if !ok {
roleId = constdata.UNLOGGED_USER_ROLE_ID
} else {
roleId = customer.RoleID
}
menu, err := h.menuService.GetRoutes(langId, roleId)
if err != nil {
return c.Status(responseErrors.GetErrorStatus(err)).
JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err)))

View File

@@ -86,9 +86,10 @@ func (s *Server) Setup() error {
// API routes
s.api = s.app.Group("/api/v1")
s.api.Use(middleware.Authenticate())
s.public = s.api.Group("/public")
s.restricted = s.api.Group("/restricted")
s.restricted.Use(middleware.AuthMiddleware())
s.restricted.Use(middleware.Authorize())
s.webdav = s.api.Group("/webdav")
s.webdav.Use(middleware.Webdav())

View File

@@ -7,7 +7,6 @@ type Route struct {
Component string `gorm:"type:varchar(255);not null;comment:path to component file" json:"component"`
Meta *string `gorm:"type:longtext;default:'{}'" json:"meta,omitempty"`
Active *bool `gorm:"type:tinyint;default:1" json:"active,omitempty"`
SortOrder *int `gorm:"type:int;default:0" json:"sort_order,omitempty"`
}
func (Route) TableName() string {

View File

@@ -18,7 +18,7 @@ type UIProductsRepo interface {
// GetJSON(p_id_product, p_id_shop, p_id_lang, p_id_customer, b2b_id_country, p_quantity int) (*json.RawMessage, error)
Find(id_lang uint, userID uint, p find.Paging, filt *filters.FiltersList) (*find.Found[model.ProductInList], error)
GetProductVariants(langID uint, productID uint, shopID uint, customerID uint, countryID uint, quantity uint) ([]view.ProductAttribute, error)
GetBase(p_id_product, p_id_shop, p_id_lang uint) (view.Product, error)
GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error)
GetPrice(p_id_product uint, productAttributeID *uint, p_id_shop uint, p_id_customer uint, p_id_country uint, p_quantity uint) (view.Price, error)
GetVariants(p_id_product, p_id_shop, p_id_lang, p_id_customer, p_id_country, p_quantity uint) ([]view.ProductAttribute, error)
AddToFavorites(userID uint, productID uint) error
@@ -33,11 +33,11 @@ func New() UIProductsRepo {
return &ProductsRepo{}
}
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang uint) (view.Product, error) {
func (repo *ProductsRepo) GetBase(p_id_product, p_id_shop, p_id_lang, p_id_customer uint) (view.Product, error) {
var result view.Product
err := db.DB.Raw(`CALL get_product_base(?,?,?)`,
p_id_product, p_id_shop, p_id_lang).
err := db.DB.Raw(`CALL get_product_base(?,?,?,?)`,
p_id_product, p_id_shop, p_id_lang, p_id_customer).
Scan(&result).Error
return result, err

View File

@@ -7,7 +7,7 @@ import (
)
type UIRoutesRepo interface {
GetRoutes(langId uint) ([]model.Route, error)
GetRoutes(langId uint, roleId uint) ([]model.Route, error)
GetTopMenu(id uint, roleId uint) ([]model.B2BTopMenu, error)
}
@@ -17,13 +17,18 @@ func New() UIRoutesRepo {
return &RoutesRepo{}
}
func (p *RoutesRepo) GetRoutes(langId uint) ([]model.Route, error) {
func (p *RoutesRepo) GetRoutes(langId uint, roleId uint) ([]model.Route, error) {
routes := []model.Route{}
err := db.DB.Find(&routes, model.Route{Active: nullable.GetNil(true)}).Error
if err != nil {
return nil, err
}
return routes, nil
err := db.
Get().
Model(model.Route{}).
Joins("JOIN b2b_route_roles rr ON rr.route_id = b2b_routes.id").
Where(model.Route{Active: nullable.GetNil(true)}).
Where("rr.role_id = ?", roleId).
Find(&routes).Error
return routes, err
}
func (p *RoutesRepo) GetTopMenu(langId uint, roleId uint) ([]model.B2BTopMenu, error) {

View File

@@ -102,8 +102,8 @@ func (s *MenuService) createTree(index int, all_categories *([]model.ScannedCate
return node, true
}
func (s *MenuService) GetRoutes(id_lang uint) ([]model.Route, error) {
return s.routesRepo.GetRoutes(id_lang)
func (s *MenuService) GetRoutes(id_lang, roleId uint) ([]model.Route, error) {
return s.routesRepo.GetRoutes(id_lang, roleId)
}
func (s *MenuService) scannedToNormalCategory(scanned model.ScannedCategory) model.Category {

View File

@@ -27,7 +27,7 @@ func (s *ProductService) Get(
p_id_product, p_id_lang, p_id_customer, b2b_id_country, p_quantity uint,
) (*json.RawMessage, error) {
product, err := s.productsRepo.GetBase(p_id_product, constdata.SHOP_ID, p_id_lang)
product, err := s.productsRepo.GetBase(p_id_product, constdata.SHOP_ID, p_id_lang, p_id_customer)
if err != nil {
return nil, err
}

View File

@@ -32,3 +32,5 @@ const WEBDAV_TRIMMED_ROOT = "localhost:3000/api/v1/webdav/storage"
const NON_ALNUM_REGEX = `[^a-z0-9]+`
const MULTI_DASH_REGEX = `-+`
const SLUG_REGEX = `^[a-z0-9]+(?:-[a-z0-9]+)*$`
const UNLOGGED_USER_ROLE_ID = 4