diff --git a/app/module/products/mapper/products.mapper.go b/app/module/products/mapper/products.mapper.go index 0de47c0..eed5080 100644 --- a/app/module/products/mapper/products.mapper.go +++ b/app/module/products/mapper/products.mapper.go @@ -4,6 +4,7 @@ import ( "encoding/json" "jaecoo-be/app/database/entity" res "jaecoo-be/app/module/products/response" + "path/filepath" ) func ProductsResponseMapper(product *entity.Products, host string) *res.ProductsResponse { @@ -13,30 +14,33 @@ func ProductsResponseMapper(product *entity.Products, host string) *res.Products var colors []res.ProductColorResponse - if product.Colors != nil && *product.Colors != "" { - var rawColors []struct { - Name string `json:"name"` - ImagePath *string `json:"image_path"` - } - - _ = json.Unmarshal([]byte(*product.Colors), &rawColors) - - for _, c := range rawColors { - var imageUrl *string - - if c.ImagePath != nil && *c.ImagePath != "" { - url := host + "/products/viewer/" + *c.ImagePath - imageUrl = &url - } - - colors = append(colors, res.ProductColorResponse{ - Name: c.Name, - ImagePath: c.ImagePath, - ImageUrl: imageUrl, - }) - } +if product.Colors != nil && *product.Colors != "" { + var rawColors []struct { + Name string `json:"name"` + ImagePath *string `json:"image_path"` } + _ = json.Unmarshal([]byte(*product.Colors), &rawColors) + + for _, c := range rawColors { + var imageUrl *string + + if c.ImagePath != nil { + filename := filepath.Base(*c.ImagePath) + url := host + "/products/viewer/" + filename + imageUrl = &url + + } + + colors = append(colors, res.ProductColorResponse{ + Name: c.Name, + ImagePath: c.ImagePath, + ImageUrl: imageUrl, + }) + } +} + + response := &res.ProductsResponse{ ID: product.ID, Title: product.Title, @@ -52,7 +56,9 @@ func ProductsResponseMapper(product *entity.Products, host string) *res.Products } if product.ThumbnailPath != nil && *product.ThumbnailPath != "" { - thumbnailUrl := host + "/products/viewer/" + *product.ThumbnailPath + // Extract filename from path + filename := filepath.Base(*product.ThumbnailPath) + thumbnailUrl := host + "/products/viewer/" + filename response.ThumbnailUrl = &thumbnailUrl } diff --git a/app/module/products/service/products.service.go b/app/module/products/service/products.service.go index cadde46..a9721f2 100644 --- a/app/module/products/service/products.service.go +++ b/app/module/products/service/products.service.go @@ -307,111 +307,68 @@ func (_i *productsService) Delete(id uint) (err error) { return } -// func (_i *productsService) Viewer(c *fiber.Ctx) (err error) { -// filename := c.Params("filename") +func (_i *productsService) Viewer(c *fiber.Ctx) (err error) { + filename := c.Params("filename") -// // Find product by filename (repository will search using LIKE pattern) -// result, err := _i.Repo.FindByThumbnailPath(filename) -// if err != nil { -// return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ -// "error": true, -// "msg": "Product file not found", -// }) -// } - -// if result.ThumbnailPath == nil || *result.ThumbnailPath == "" { -// return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ -// "error": true, -// "msg": "Product thumbnail path not found", -// }) -// } - -// ctx := context.Background() -// bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName -// objectName := *result.ThumbnailPath - -// _i.Log.Info().Str("timestamp", time.Now(). -// Format(time.RFC3339)).Str("Service:Resource", "Products:Viewer"). -// Interface("data", objectName).Msg("") - -// // Create minio connection -// minioClient, err := _i.MinioStorage.ConnectMinio() -// if err != nil { -// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ -// "error": true, -// "msg": err.Error(), -// }) -// } - -// fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{}) -// if err != nil { -// _i.Log.Error().Str("timestamp", time.Now(). -// Format(time.RFC3339)).Str("Service:Resource", "Products:Viewer"). -// Interface("Error getting file", err).Msg("") -// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ -// "error": true, -// "msg": "Failed to retrieve file", -// }) -// } -// defer fileContent.Close() - -// // Determine Content-Type based on file extension -// contentType := mime.TypeByExtension("." + getFileExtension(objectName)) -// if contentType == "" { -// contentType = "application/octet-stream" // fallback if no MIME type matches -// } - -// c.Set("Content-Type", contentType) - -// if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil { -// return err -// } - -// return -// } - -func (_i *productsService) Viewer(c *fiber.Ctx) error { - // ambil full path setelah /viewer - objectPath := strings.TrimPrefix(c.Params("*"), "/") - - if objectPath == "" { - return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + // Find product by filename (repository will search using LIKE pattern) + result, err := _i.Repo.FindByThumbnailPath(filename) + if err != nil { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ "error": true, - "msg": "File path is required", + "msg": "Product file not found", + }) + } + + if result.ThumbnailPath == nil || *result.ThumbnailPath == "" { + return c.Status(fiber.StatusNotFound).JSON(fiber.Map{ + "error": true, + "msg": "Product thumbnail path not found", }) } ctx := context.Background() bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName + objectName := *result.ThumbnailPath + _i.Log.Info().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:Resource", "Products:Viewer"). + Interface("data", objectName).Msg("") + + // Create minio connection minioClient, err := _i.MinioStorage.ConnectMinio() if err != nil { - return c.Status(500).JSON(fiber.Map{ + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": true, "msg": err.Error(), }) } - file, err := minioClient.GetObject(ctx, bucketName, objectPath, minio.GetObjectOptions{}) + fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{}) if err != nil { - return c.Status(404).JSON(fiber.Map{ + _i.Log.Error().Str("timestamp", time.Now(). + Format(time.RFC3339)).Str("Service:Resource", "Products:Viewer"). + Interface("Error getting file", err).Msg("") + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": true, - "msg": "Product file not found", + "msg": "Failed to retrieve file", }) } - defer file.Close() + defer fileContent.Close() - // content-type - contentType := mime.TypeByExtension(filepath.Ext(objectPath)) + // Determine Content-Type based on file extension + contentType := mime.TypeByExtension("." + getFileExtension(objectName)) if contentType == "" { - contentType = "application/octet-stream" + contentType = "application/octet-stream" // fallback if no MIME type matches } + c.Set("Content-Type", contentType) - _, err = io.Copy(c.Response().BodyWriter(), file) - return err -} + if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil { + return err + } + return +} func getFileExtension(filename string) string { // split file name