fix: update product, banners, gallery_files, product spec, promotions

This commit is contained in:
hanif salafi 2025-11-17 22:44:55 +07:00
parent d6aa8b6c2c
commit 1bef2a45e5
21 changed files with 63 additions and 53 deletions

View File

@ -8,7 +8,7 @@ type Products struct {
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"` ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
Title string `json:"title" gorm:"type:varchar"` Title string `json:"title" gorm:"type:varchar"`
Variant *string `json:"variant" gorm:"type:varchar"` Variant *string `json:"variant" gorm:"type:varchar"`
Price *float64 `json:"price" gorm:"type:decimal(10,2)"` Price *string `json:"price" gorm:"type:varchar"`
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"` ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
Colors *string `json:"colors" gorm:"type:text"` // JSON array stored as text Colors *string `json:"colors" gorm:"type:text"` // JSON array stored as text
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"` IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`

View File

@ -240,7 +240,7 @@ func (_i *bannersController) Delete(c *fiber.Ctx) error {
// @Tags Banners // @Tags Banners
// @Security Bearer // @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key" // @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param filename path string true "Banner File Path" // @Param filename path string true "Banner File Name (e.g., user_277788.png)"
// @Success 200 {file} file // @Success 200 {file} file
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError // @Failure 401 {object} response.UnauthorizedError

View File

@ -3,6 +3,7 @@ package mapper
import ( import (
"jaecoo-be/app/database/entity" "jaecoo-be/app/database/entity"
res "jaecoo-be/app/module/banners/response" res "jaecoo-be/app/module/banners/response"
"path/filepath"
) )
func BannersResponseMapper(banner *entity.Banners, host string) *res.BannersResponse { func BannersResponseMapper(banner *entity.Banners, host string) *res.BannersResponse {
@ -23,10 +24,11 @@ func BannersResponseMapper(banner *entity.Banners, host string) *res.BannersResp
} }
if banner.ThumbnailPath != nil && *banner.ThumbnailPath != "" { if banner.ThumbnailPath != nil && *banner.ThumbnailPath != "" {
thumbnailUrl := host + "/banners/thumbnail/viewer/" + *banner.ThumbnailPath // Extract filename from path
filename := filepath.Base(*banner.ThumbnailPath)
thumbnailUrl := host + "/banners/viewer/" + filename
response.ThumbnailUrl = &thumbnailUrl response.ThumbnailUrl = &thumbnailUrl
} }
return response return response
} }

View File

@ -195,7 +195,7 @@ func (_i *bannersService) Delete(id uint) (err error) {
func (_i *bannersService) Viewer(c *fiber.Ctx) (err error) { func (_i *bannersService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename") filename := c.Params("filename")
// Find banner by thumbnail path // Find banner by filename (repository will search using LIKE pattern)
result, err := _i.Repo.FindByThumbnailPath(filename) result, err := _i.Repo.FindByThumbnailPath(filename)
if err != nil { if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ return c.Status(fiber.StatusNotFound).JSON(fiber.Map{

View File

@ -230,7 +230,7 @@ func (_i *galleryFilesController) Delete(c *fiber.Ctx) error {
// @Tags GalleryFiles // @Tags GalleryFiles
// @Security Bearer // @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key" // @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param filename path string true "Gallery File Path" // @Param filename path string true "Gallery File Name (e.g., user_277788.png)"
// @Success 200 {file} file // @Success 200 {file} file
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError // @Failure 401 {object} response.UnauthorizedError

View File

@ -3,6 +3,7 @@ package mapper
import ( import (
"jaecoo-be/app/database/entity" "jaecoo-be/app/database/entity"
res "jaecoo-be/app/module/gallery_files/response" res "jaecoo-be/app/module/gallery_files/response"
"path/filepath"
) )
func GalleryFilesResponseMapper(file *entity.GalleryFiles, host string) *res.GalleryFilesResponse { func GalleryFilesResponseMapper(file *entity.GalleryFiles, host string) *res.GalleryFilesResponse {
@ -21,7 +22,9 @@ func GalleryFilesResponseMapper(file *entity.GalleryFiles, host string) *res.Gal
} }
if file.ImagePath != nil && *file.ImagePath != "" { if file.ImagePath != nil && *file.ImagePath != "" {
imageUrl := host + "/gallery-files/image/viewer/" + *file.ImagePath // Extract filename from path
filename := filepath.Base(*file.ImagePath)
imageUrl := host + "/gallery-files/viewer/" + filename
response.ImageUrl = &imageUrl response.ImageUrl = &imageUrl
} }

View File

@ -195,7 +195,7 @@ func (_i *galleryFilesService) Delete(id uint) (err error) {
func (_i *galleryFilesService) Viewer(c *fiber.Ctx) (err error) { func (_i *galleryFilesService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename") filename := c.Params("filename")
// Find gallery file by image path // Find gallery file by filename (repository will search using LIKE pattern)
result, err := _i.Repo.FindByImagePath(filename) result, err := _i.Repo.FindByImagePath(filename)
if err != nil { if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ return c.Status(fiber.StatusNotFound).JSON(fiber.Map{

View File

@ -235,7 +235,7 @@ func (_i *productSpecificationsController) Delete(c *fiber.Ctx) error {
// @Tags ProductSpecifications // @Tags ProductSpecifications
// @Security Bearer // @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key" // @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param filename path string true "Product Specification File Path" // @Param filename path string true "Product Specification File Name (e.g., user_277788.png)"
// @Success 200 {file} file // @Success 200 {file} file
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError // @Failure 401 {object} response.UnauthorizedError

View File

@ -3,6 +3,7 @@ package mapper
import ( import (
"jaecoo-be/app/database/entity" "jaecoo-be/app/database/entity"
res "jaecoo-be/app/module/product_specifications/response" res "jaecoo-be/app/module/product_specifications/response"
"path/filepath"
) )
func ProductSpecificationsResponseMapper(spec *entity.ProductSpecifications, host string) *res.ProductSpecificationsResponse { func ProductSpecificationsResponseMapper(spec *entity.ProductSpecifications, host string) *res.ProductSpecificationsResponse {
@ -21,7 +22,9 @@ func ProductSpecificationsResponseMapper(spec *entity.ProductSpecifications, hos
} }
if spec.ThumbnailPath != nil && *spec.ThumbnailPath != "" { if spec.ThumbnailPath != nil && *spec.ThumbnailPath != "" {
thumbnailUrl := host + "/product-specifications/thumbnail/viewer/" + *spec.ThumbnailPath // Extract filename from path
filename := filepath.Base(*spec.ThumbnailPath)
thumbnailUrl := host + "/product-specifications/viewer/" + filename
response.ThumbnailUrl = &thumbnailUrl response.ThumbnailUrl = &thumbnailUrl
} }

View File

@ -195,7 +195,7 @@ func (_i *productSpecificationsService) Delete(id uint) (err error) {
func (_i *productSpecificationsService) Viewer(c *fiber.Ctx) (err error) { func (_i *productSpecificationsService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename") filename := c.Params("filename")
// Find product specification by thumbnail path // Find product specification by filename (repository will search using LIKE pattern)
result, err := _i.Repo.FindByThumbnailPath(filename) result, err := _i.Repo.FindByThumbnailPath(filename)
if err != nil { if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ return c.Status(fiber.StatusNotFound).JSON(fiber.Map{

View File

@ -110,7 +110,7 @@ func (_i *productsController) Show(c *fiber.Ctx) error {
// @Param file formData file false "Upload file" // @Param file formData file false "Upload file"
// @Param title formData string true "Product title" // @Param title formData string true "Product title"
// @Param variant formData string false "Product variant" // @Param variant formData string false "Product variant"
// @Param price formData number false "Product price" // @Param price formData string false "Product price"
// @Param colors formData string false "Product colors (JSON array)" // @Param colors formData string false "Product colors (JSON array)"
// @Success 200 {object} response.Response // @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
@ -136,10 +136,8 @@ func (_i *productsController) Save(c *fiber.Ctx) error {
req.Variant = &variant req.Variant = &variant
} }
if priceStr := c.FormValue("price"); priceStr != "" { if price := c.FormValue("price"); price != "" {
if price, err := strconv.ParseFloat(priceStr, 64); err == nil { req.Price = &price
req.Price = &price
}
} }
// Handle colors (JSON array string) // Handle colors (JSON array string)
@ -246,7 +244,7 @@ func (_i *productsController) Delete(c *fiber.Ctx) error {
// @Tags Products // @Tags Products
// @Security Bearer // @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key" // @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param filename path string true "Product File Path" // @Param filename path string true "Product File Name (e.g., user_277788.png)"
// @Success 200 {file} file // @Success 200 {file} file
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError // @Failure 401 {object} response.UnauthorizedError
@ -255,4 +253,3 @@ func (_i *productsController) Delete(c *fiber.Ctx) error {
func (_i *productsController) Viewer(c *fiber.Ctx) error { func (_i *productsController) Viewer(c *fiber.Ctx) error {
return _i.productsService.Viewer(c) return _i.productsService.Viewer(c)
} }

View File

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"jaecoo-be/app/database/entity" "jaecoo-be/app/database/entity"
res "jaecoo-be/app/module/products/response" res "jaecoo-be/app/module/products/response"
"path/filepath"
) )
func ProductsResponseMapper(product *entity.Products, host string) *res.ProductsResponse { func ProductsResponseMapper(product *entity.Products, host string) *res.ProductsResponse {
@ -29,7 +30,9 @@ func ProductsResponseMapper(product *entity.Products, host string) *res.Products
} }
if product.ThumbnailPath != nil && *product.ThumbnailPath != "" { if product.ThumbnailPath != nil && *product.ThumbnailPath != "" {
thumbnailUrl := host + "/products/thumbnail/viewer/" + *product.ThumbnailPath // Extract filename from path
filename := filepath.Base(*product.ThumbnailPath)
thumbnailUrl := host + "/products/viewer/" + filename
response.ThumbnailUrl = &thumbnailUrl response.ThumbnailUrl = &thumbnailUrl
} }

View File

@ -33,7 +33,7 @@ func (req ProductsQueryRequestContext) ToParamRequest() ProductsQueryRequest {
type ProductsCreateRequest struct { type ProductsCreateRequest struct {
Title string `json:"title" validate:"required"` Title string `json:"title" validate:"required"`
Variant *string `json:"variant"` Variant *string `json:"variant"`
Price *float64 `json:"price"` Price *string `json:"price"`
ThumbnailPath *string `json:"thumbnail_path"` ThumbnailPath *string `json:"thumbnail_path"`
Colors []string `json:"colors"` Colors []string `json:"colors"`
} }
@ -55,12 +55,12 @@ func (req ProductsCreateRequest) ToEntity() *entity.Products {
} }
type ProductsUpdateRequest struct { type ProductsUpdateRequest struct {
Title *string `json:"title"` Title *string `json:"title"`
Variant *string `json:"variant"` Variant *string `json:"variant"`
Price *float64 `json:"price"` Price *string `json:"price"`
ThumbnailPath *string `json:"thumbnail_path"` ThumbnailPath *string `json:"thumbnail_path"`
Colors []string `json:"colors"` Colors []string `json:"colors"`
IsActive *bool `json:"is_active"` IsActive *bool `json:"is_active"`
} }
func (req ProductsUpdateRequest) ToEntity() *entity.Products { func (req ProductsUpdateRequest) ToEntity() *entity.Products {
@ -86,4 +86,3 @@ func getStringValue(s *string) string {
} }
return *s return *s
} }

View File

@ -8,7 +8,7 @@ type ProductsResponse struct {
ID uint `json:"id"` ID uint `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Variant *string `json:"variant"` Variant *string `json:"variant"`
Price *float64 `json:"price"` Price *string `json:"price"`
ThumbnailPath *string `json:"thumbnail_path"` ThumbnailPath *string `json:"thumbnail_path"`
ThumbnailUrl *string `json:"thumbnail_url"` ThumbnailUrl *string `json:"thumbnail_url"`
Colors []string `json:"colors"` Colors []string `json:"colors"`

View File

@ -195,7 +195,7 @@ func (_i *productsService) Delete(id uint) (err error) {
func (_i *productsService) Viewer(c *fiber.Ctx) (err error) { func (_i *productsService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename") filename := c.Params("filename")
// Find product by thumbnail path // Find product by filename (repository will search using LIKE pattern)
result, err := _i.Repo.FindByThumbnailPath(filename) result, err := _i.Repo.FindByThumbnailPath(filename)
if err != nil { if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ return c.Status(fiber.StatusNotFound).JSON(fiber.Map{

View File

@ -228,7 +228,7 @@ func (_i *promotionsController) Delete(c *fiber.Ctx) error {
// @Tags Promotions // @Tags Promotions
// @Security Bearer // @Security Bearer
// @Param X-Client-Key header string true "Insert the X-Client-Key" // @Param X-Client-Key header string true "Insert the X-Client-Key"
// @Param filename path string true "Promotion File Path" // @Param filename path string true "Promotion File Name (e.g., user_277788.png)"
// @Success 200 {file} file // @Success 200 {file} file
// @Failure 400 {object} response.BadRequestError // @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError // @Failure 401 {object} response.UnauthorizedError

View File

@ -3,6 +3,7 @@ package mapper
import ( import (
"jaecoo-be/app/database/entity" "jaecoo-be/app/database/entity"
res "jaecoo-be/app/module/promotions/response" res "jaecoo-be/app/module/promotions/response"
"path/filepath"
) )
func PromotionsResponseMapper(promotion *entity.Promotions, host string) *res.PromotionsResponse { func PromotionsResponseMapper(promotion *entity.Promotions, host string) *res.PromotionsResponse {
@ -21,7 +22,9 @@ func PromotionsResponseMapper(promotion *entity.Promotions, host string) *res.Pr
} }
if promotion.ThumbnailPath != nil && *promotion.ThumbnailPath != "" { if promotion.ThumbnailPath != nil && *promotion.ThumbnailPath != "" {
thumbnailUrl := host + "/promotions/thumbnail/viewer/" + *promotion.ThumbnailPath // Extract filename from path
filename := filepath.Base(*promotion.ThumbnailPath)
thumbnailUrl := host + "/promotions/viewer/" + filename
response.ThumbnailUrl = &thumbnailUrl response.ThumbnailUrl = &thumbnailUrl
} }

View File

@ -195,7 +195,7 @@ func (_i *promotionsService) Delete(id uint) (err error) {
func (_i *promotionsService) Viewer(c *fiber.Ctx) (err error) { func (_i *promotionsService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename") filename := c.Params("filename")
// Find promotion by thumbnail path // Find promotion by filename (repository will search using LIKE pattern)
result, err := _i.Repo.FindByThumbnailPath(filename) result, err := _i.Repo.FindByThumbnailPath(filename)
if err != nil { if err != nil {
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ return c.Status(fiber.StatusNotFound).JSON(fiber.Map{

View File

@ -3426,7 +3426,7 @@ const docTemplate = `{
}, },
{ {
"type": "string", "type": "string",
"description": "Banner File Path", "description": "Banner File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -5440,7 +5440,7 @@ const docTemplate = `{
}, },
{ {
"type": "string", "type": "string",
"description": "Gallery File Path", "description": "Gallery File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -5835,7 +5835,7 @@ const docTemplate = `{
}, },
{ {
"type": "string", "type": "string",
"description": "Product Specification File Path", "description": "Product Specification File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -6179,7 +6179,7 @@ const docTemplate = `{
"in": "formData" "in": "formData"
}, },
{ {
"type": "number", "type": "string",
"description": "Product price", "description": "Product price",
"name": "price", "name": "price",
"in": "formData" "in": "formData"
@ -6241,7 +6241,7 @@ const docTemplate = `{
}, },
{ {
"type": "string", "type": "string",
"description": "Product File Path", "description": "Product File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -6630,7 +6630,7 @@ const docTemplate = `{
}, },
{ {
"type": "string", "type": "string",
"description": "Promotion File Path", "description": "Promotion File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -10406,7 +10406,7 @@ const docTemplate = `{
"type": "boolean" "type": "boolean"
}, },
"price": { "price": {
"type": "number" "type": "string"
}, },
"thumbnail_path": { "thumbnail_path": {
"type": "string" "type": "string"

View File

@ -3415,7 +3415,7 @@
}, },
{ {
"type": "string", "type": "string",
"description": "Banner File Path", "description": "Banner File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -5429,7 +5429,7 @@
}, },
{ {
"type": "string", "type": "string",
"description": "Gallery File Path", "description": "Gallery File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -5824,7 +5824,7 @@
}, },
{ {
"type": "string", "type": "string",
"description": "Product Specification File Path", "description": "Product Specification File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -6168,7 +6168,7 @@
"in": "formData" "in": "formData"
}, },
{ {
"type": "number", "type": "string",
"description": "Product price", "description": "Product price",
"name": "price", "name": "price",
"in": "formData" "in": "formData"
@ -6230,7 +6230,7 @@
}, },
{ {
"type": "string", "type": "string",
"description": "Product File Path", "description": "Product File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -6619,7 +6619,7 @@
}, },
{ {
"type": "string", "type": "string",
"description": "Promotion File Path", "description": "Promotion File Name (e.g., user_277788.png)",
"name": "filename", "name": "filename",
"in": "path", "in": "path",
"required": true "required": true
@ -10395,7 +10395,7 @@
"type": "boolean" "type": "boolean"
}, },
"price": { "price": {
"type": "number" "type": "string"
}, },
"thumbnail_path": { "thumbnail_path": {
"type": "string" "type": "string"

View File

@ -436,7 +436,7 @@ definitions:
is_active: is_active:
type: boolean type: boolean
price: price:
type: number type: string
thumbnail_path: thumbnail_path:
type: string type: string
title: title:
@ -3133,7 +3133,7 @@ paths:
name: X-Client-Key name: X-Client-Key
required: true required: true
type: string type: string
- description: Banner File Path - description: Banner File Name (e.g., user_277788.png)
in: path in: path
name: filename name: filename
required: true required: true
@ -4415,7 +4415,7 @@ paths:
name: X-Client-Key name: X-Client-Key
required: true required: true
type: string type: string
- description: Gallery File Path - description: Gallery File Name (e.g., user_277788.png)
in: path in: path
name: filename name: filename
required: true required: true
@ -4668,7 +4668,7 @@ paths:
name: X-Client-Key name: X-Client-Key
required: true required: true
type: string type: string
- description: Product Specification File Path - description: Product Specification File Name (e.g., user_277788.png)
in: path in: path
name: filename name: filename
required: true required: true
@ -4780,7 +4780,7 @@ paths:
- description: Product price - description: Product price
in: formData in: formData
name: price name: price
type: number type: string
- description: Product colors (JSON array) - description: Product colors (JSON array)
in: formData in: formData
name: colors name: colors
@ -4928,7 +4928,7 @@ paths:
name: X-Client-Key name: X-Client-Key
required: true required: true
type: string type: string
- description: Product File Path - description: Product File Name (e.g., user_277788.png)
in: path in: path
name: filename name: filename
required: true required: true
@ -5177,7 +5177,7 @@ paths:
name: X-Client-Key name: X-Client-Key
required: true required: true
type: string type: string
- description: Promotion File Path - description: Promotion File Name (e.g., user_277788.png)
in: path in: path
name: filename name: filename
required: true required: true