routing
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"gorm.io/gorm"
|
||||
|
||||
appmiddleware "prestaproxy/internal/http/middleware"
|
||||
pscart "prestaproxy/internal/prestashop/cart"
|
||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
||||
psconfig "prestaproxy/internal/prestashop/config"
|
||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
||||
psroutes "prestaproxy/internal/prestashop/routes"
|
||||
"prestaproxy/internal/render"
|
||||
"prestaproxy/internal/viewmodel"
|
||||
)
|
||||
|
||||
const categorySlugContextKey = "category_slug"
|
||||
const categoryIDContextKey = "category_id"
|
||||
|
||||
type CategoryHandler struct {
|
||||
catalog *pscatalog.Service
|
||||
customers *pscustomer.Service
|
||||
carts *pscart.Service
|
||||
renderer *render.Engine
|
||||
config psconfig.Config
|
||||
products *psroutes.ProductRoute
|
||||
}
|
||||
|
||||
func NewCategoryHandler(catalog *pscatalog.Service, customers *pscustomer.Service, carts *pscart.Service, renderer *render.Engine, cfg psconfig.Config, products *psroutes.ProductRoute) *CategoryHandler {
|
||||
return &CategoryHandler{
|
||||
catalog: catalog,
|
||||
customers: customers,
|
||||
carts: carts,
|
||||
renderer: renderer,
|
||||
config: cfg,
|
||||
products: products,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *CategoryHandler) Show(c echo.Context) error {
|
||||
session := appmiddleware.GetSession(c)
|
||||
if session == nil {
|
||||
session = appmiddleware.GetSession(c)
|
||||
}
|
||||
if h == nil || h.catalog == nil || h.renderer == nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "category handler is not initialized")
|
||||
}
|
||||
|
||||
languageID := int64Default(session.LanguageID, 1)
|
||||
languageID = h.catalog.ResolveLanguageID(c.Request().Context(), c.Request(), languageID)
|
||||
shopID := int64Default(session.ShopID, 1)
|
||||
|
||||
category, err := h.catalog.GetCategoryPage(c.Request().Context(), pscatalog.CategoryPageRequest{
|
||||
ID: categoryID(c),
|
||||
Slug: categorySlug(c),
|
||||
LanguageID: languageID,
|
||||
ShopID: shopID,
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "category not found")
|
||||
}
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "category query failed: "+err.Error())
|
||||
}
|
||||
|
||||
var profile *pscustomer.Profile
|
||||
if session.CustomerID != nil && h.customers != nil {
|
||||
profile, err = h.customers.GetByID(c.Request().Context(), *session.CustomerID)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "customer query failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
var cartSummary *pscart.Summary
|
||||
if session.CartID != nil && h.carts != nil {
|
||||
cartSummary, err = h.carts.SummaryByID(c.Request().Context(), *session.CartID)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "cart query failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
page := viewmodel.CategoryPageData{
|
||||
Category: *category,
|
||||
Session: session,
|
||||
Customer: profile,
|
||||
CartSummary: cartSummary,
|
||||
ShopBaseURL: h.config.PrestaShopBaseURL,
|
||||
}
|
||||
assignCategoryProductLinks(c.Request(), h.products, &page)
|
||||
|
||||
if err := h.renderer.Category(c.Response(), c.Request(), page); err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "category render failed: "+err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetCategorySlug(c echo.Context, slug string) {
|
||||
c.Set(categorySlugContextKey, slug)
|
||||
}
|
||||
|
||||
func SetCategoryID(c echo.Context, id int64) {
|
||||
c.Set(categoryIDContextKey, id)
|
||||
}
|
||||
|
||||
func categorySlug(c echo.Context) string {
|
||||
if value := c.Get(categorySlugContextKey); value != nil {
|
||||
if slug, ok := value.(string); ok && slug != "" {
|
||||
return slug
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(c.Param("slug"))
|
||||
}
|
||||
|
||||
func categoryID(c echo.Context) int64 {
|
||||
if value := c.Get(categoryIDContextKey); value != nil {
|
||||
if id, ok := value.(int64); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func assignCategoryProductLinks(req *http.Request, route *psroutes.ProductRoute, page *viewmodel.CategoryPageData) {
|
||||
if page == nil {
|
||||
return
|
||||
}
|
||||
langPrefix := requestLanguagePrefix(req)
|
||||
categoryPath := page.Category.Slug
|
||||
for i := range page.Category.Products {
|
||||
product := &page.Category.Products[i]
|
||||
product.URL = route.BuildPath(psroutes.ProductURLData{
|
||||
ID: product.ID,
|
||||
Slug: product.Slug,
|
||||
CategoryPath: categoryPath,
|
||||
EAN13: product.EAN13,
|
||||
LanguagePrefix: langPrefix,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func requestLanguagePrefix(req *http.Request) string {
|
||||
if req == nil || req.URL == nil {
|
||||
return ""
|
||||
}
|
||||
path := strings.Trim(req.URL.Path, "/")
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
first := path
|
||||
if idx := strings.IndexByte(path, '/'); idx >= 0 {
|
||||
first = path[:idx]
|
||||
}
|
||||
first = strings.TrimSpace(first)
|
||||
if len(first) < 2 || len(first) > 5 {
|
||||
return ""
|
||||
}
|
||||
return "/" + first
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func Healthz() echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, map[string]string{"status": "ok"})
|
||||
}
|
||||
}
|
||||
|
||||
func Readyz(appDB, prestaDB *gorm.DB, proxyTarget string) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
ctx, cancel := context.WithTimeout(c.Request().Context(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if err := pingDB(ctx, appDB); err != nil {
|
||||
return echo.NewHTTPError(http.StatusServiceUnavailable, "app db unavailable")
|
||||
}
|
||||
if err := pingDB(ctx, prestaDB); err != nil {
|
||||
return echo.NewHTTPError(http.StatusServiceUnavailable, "prestashop db unavailable")
|
||||
}
|
||||
if proxyTarget == "" {
|
||||
return echo.NewHTTPError(http.StatusServiceUnavailable, "prestashop proxy target unavailable")
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, map[string]string{"status": "ready"})
|
||||
}
|
||||
}
|
||||
|
||||
func pingDB(ctx context.Context, db *gorm.DB) error {
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sqlDB.PingContext(ctx)
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"gorm.io/gorm"
|
||||
|
||||
appmiddleware "prestaproxy/internal/http/middleware"
|
||||
pscart "prestaproxy/internal/prestashop/cart"
|
||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
||||
psconfig "prestaproxy/internal/prestashop/config"
|
||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
||||
psroutes "prestaproxy/internal/prestashop/routes"
|
||||
"prestaproxy/internal/render"
|
||||
"prestaproxy/internal/viewmodel"
|
||||
)
|
||||
|
||||
const productSlugContextKey = "product_slug"
|
||||
const productIDContextKey = "product_id"
|
||||
|
||||
type ProductHandler struct {
|
||||
products *pscatalog.Service
|
||||
customers *pscustomer.Service
|
||||
carts *pscart.Service
|
||||
renderer *render.Engine
|
||||
config psconfig.Config
|
||||
categories *psroutes.CategoryRoute
|
||||
}
|
||||
|
||||
func NewProductHandler(products *pscatalog.Service, customers *pscustomer.Service, carts *pscart.Service, renderer *render.Engine, cfg psconfig.Config, categories *psroutes.CategoryRoute) *ProductHandler {
|
||||
return &ProductHandler{
|
||||
products: products,
|
||||
customers: customers,
|
||||
carts: carts,
|
||||
renderer: renderer,
|
||||
config: cfg,
|
||||
categories: categories,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ProductHandler) Show(c echo.Context) error {
|
||||
session := appmiddleware.GetSession(c)
|
||||
if session == nil {
|
||||
session = appmiddleware.GetSession(c)
|
||||
}
|
||||
if h == nil || h.products == nil || h.renderer == nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "product handler is not initialized")
|
||||
}
|
||||
|
||||
languageID := int64Default(session.LanguageID, 1)
|
||||
languageID = h.products.ResolveLanguageID(c.Request().Context(), c.Request(), languageID)
|
||||
shopID := int64Default(session.ShopID, 1)
|
||||
|
||||
product, err := h.products.GetProductPage(c.Request().Context(), pscatalog.ProductPageRequest{
|
||||
ID: productID(c),
|
||||
Slug: productSlug(c),
|
||||
LanguageID: languageID,
|
||||
ShopID: shopID,
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return echo.NewHTTPError(http.StatusNotFound, "product not found")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
var profile *pscustomer.Profile
|
||||
if session.CustomerID != nil && h.customers != nil {
|
||||
profile, err = h.customers.GetByID(c.Request().Context(), *session.CustomerID)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var cartSummary *pscart.Summary
|
||||
if session.CartID != nil && h.carts != nil {
|
||||
cartSummary, err = h.carts.SummaryByID(c.Request().Context(), *session.CartID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
page := viewmodel.ProductPageData{
|
||||
Product: *product,
|
||||
CategoryURL: productCategoryURL(c.Request(), h.categories, product),
|
||||
Session: session,
|
||||
Customer: profile,
|
||||
CartSummary: cartSummary,
|
||||
ShopBaseURL: h.config.PrestaShopBaseURL,
|
||||
}
|
||||
|
||||
return h.renderer.Product(c.Response(), c.Request(), page)
|
||||
}
|
||||
|
||||
func int64Default(value *int64, fallback int64) int64 {
|
||||
if value == nil || *value == 0 {
|
||||
return fallback
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
func SetProductSlug(c echo.Context, slug string) {
|
||||
c.Set(productSlugContextKey, slug)
|
||||
}
|
||||
|
||||
func SetProductID(c echo.Context, id int64) {
|
||||
c.Set(productIDContextKey, id)
|
||||
}
|
||||
|
||||
func productSlug(c echo.Context) string {
|
||||
if value := c.Get(productSlugContextKey); value != nil {
|
||||
if slug, ok := value.(string); ok && slug != "" {
|
||||
return slug
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(c.Param("slug"))
|
||||
}
|
||||
|
||||
func productID(c echo.Context) int64 {
|
||||
if value := c.Get(productIDContextKey); value != nil {
|
||||
if id, ok := value.(int64); ok {
|
||||
return id
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func productCategoryURL(req *http.Request, route *psroutes.CategoryRoute, product *pscatalog.ProductPageData) string {
|
||||
if route == nil || product == nil || product.CategoryID == 0 {
|
||||
return ""
|
||||
}
|
||||
return route.BuildPath(psroutes.CategoryURLData{
|
||||
ID: product.CategoryID,
|
||||
Slug: product.CategorySlug,
|
||||
LanguagePrefix: requestLanguagePrefix(req),
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user