diff --git a/.env.example b/.env.example index 4b313a9..2f50fe6 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ +#BASE URL +BASE_URL= + # SERVER SETTINGS SERVER_HOST= SERVER_PORT= diff --git a/.gitignore b/.gitignore index a622dd0..e3d41dc 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,4 @@ go.work.sum .env.dev # Ignore public uploads -/public/uploads/ \ No newline at end of file +/public/apirijig/v2/uploads/ \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 1c865ce..371c38f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -8,10 +8,11 @@ import ( func main() { config.SetupConfig() - + app := fiber.New() - + // app.Static(utils.BaseUrl+"/uploads", "./public"+utils.BaseUrl+"/uploads") + router.SetupRoutes(app) - config.StartServer(app) + } diff --git a/dto/product_dto.go b/dto/product_dto.go new file mode 100644 index 0000000..66a5a58 --- /dev/null +++ b/dto/product_dto.go @@ -0,0 +1,55 @@ +package dto + +import ( + "mime/multipart" + "regexp" + "strings" +) + +type ResponseProductImageDTO struct { + ID string `json:"id"` + ProductID string `json:"productId"` + ImageURL string `json:"imageURL"` +} + +type ResponseProductDTO struct { + ID string `json:"id"` + StoreID string `json:"storeId"` + ProductName string `json:"productName"` + Quantity int `json:"quantity"` + Saled int `json:"saled"` + ProductImages []ResponseProductImageDTO `json:"productImages,omitempty"` + CreatedAt string `json:"createdAt"` + UpdatedAt string `json:"updatedAt"` +} + +type RequestProductDTO struct { + ProductName string `json:"product_name"` + Quantity int `json:"quantity"` + ProductImages []*multipart.FileHeader `json:"product_images,omitempty"` +} + +func (r *RequestProductDTO) ValidateProductInput() (map[string][]string, bool) { + errors := make(map[string][]string) + + if strings.TrimSpace(r.ProductName) == "" { + errors["product_name"] = append(errors["product_name"], "Product name is required") + } else if len(r.ProductName) < 3 { + errors["product_name"] = append(errors["product_name"], "Product name must be at least 3 characters long") + } else { + validNameRegex := `^[a-zA-Z0-9\s_.-]+$` + if matched, _ := regexp.MatchString(validNameRegex, r.ProductName); !matched { + errors["product_name"] = append(errors["product_name"], "Product name can only contain letters, numbers, spaces, underscores, and dashes") + } + } + + if r.Quantity < 1 { + errors["quantity"] = append(errors["quantity"], "Quantity must be at least 1") + } + + if len(errors) > 0 { + return errors, false + } + + return nil, true +} diff --git a/internal/handler/product_handler.go b/internal/handler/product_handler.go new file mode 100644 index 0000000..f41b931 --- /dev/null +++ b/internal/handler/product_handler.go @@ -0,0 +1,120 @@ +package handler + +import ( + "fmt" + "log" + "strconv" + + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/services" + "github.com/pahmiudahgede/senggoldong/utils" +) + +type ProductHandler struct { + ProductService services.ProductService +} + +func NewProductHandler(productService services.ProductService) *ProductHandler { + return &ProductHandler{ProductService: productService} +} + +func ConvertStringToInt(value string) (int, error) { + convertedValue, err := strconv.Atoi(value) + if err != nil { + return 0, fmt.Errorf("invalid integer format: %s", value) + } + return convertedValue, nil +} + +func GetPaginationParams(c *fiber.Ctx) (int, int, error) { + pageStr := c.Query("page", "1") + limitStr := c.Query("limit", "50") + + page, err := strconv.Atoi(pageStr) + if err != nil || page <= 0 { + return 0, 0, fmt.Errorf("invalid page value") + } + + limit, err := strconv.Atoi(limitStr) + if err != nil || limit <= 0 { + return 0, 0, fmt.Errorf("invalid limit value") + } + + return page, limit, nil +} + +func (h *ProductHandler) CreateProduct(c *fiber.Ctx) error { + userID, ok := c.Locals("userID").(string) + if !ok { + log.Println("User ID not found in Locals") + return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") + } + + productName := c.FormValue("product_name") + quantityStr := c.FormValue("quantity") + productImages, err := c.MultipartForm() + if err != nil { + log.Printf("Error parsing form data: %v", err) + return utils.GenericResponse(c, fiber.StatusBadRequest, "Error parsing form data") + } + + quantity, err := ConvertStringToInt(quantityStr) + if err != nil { + log.Printf("Invalid quantity: %v", err) + return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid quantity") + } + + productDTO := dto.RequestProductDTO{ + ProductName: productName, + Quantity: quantity, + ProductImages: productImages.File["product_image"], + } + + product, err := h.ProductService.CreateProduct(userID, &productDTO) + if err != nil { + log.Printf("Error creating product: %v", err) + return utils.GenericResponse(c, fiber.StatusConflict, err.Error()) + } + + return utils.CreateResponse(c, product, "Product created successfully") +} + +func (h *ProductHandler) GetAllProductsByStoreID(c *fiber.Ctx) error { + userID, ok := c.Locals("userID").(string) + if !ok { + log.Println("User ID not found in Locals") + return utils.GenericResponse(c, fiber.StatusUnauthorized, "User ID not found") + } + + page, limit, err := GetPaginationParams(c) + if err != nil { + log.Printf("Invalid pagination params: %v", err) + return utils.GenericResponse(c, fiber.StatusBadRequest, "Invalid pagination parameters") + } + + products, total, err := h.ProductService.GetAllProductsByStoreID(userID, page, limit) + if err != nil { + log.Printf("Error fetching products: %v", err) + return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) + } + + return utils.PaginatedResponse(c, products, page, limit, int(total), "Products fetched successfully") +} + +func (h *ProductHandler) GetProductByID(c *fiber.Ctx) error { + + productID := c.Params("product_id") + if productID == "" { + log.Println("Product ID is required") + return utils.GenericResponse(c, fiber.StatusBadRequest, "Product ID is required") + } + + product, err := h.ProductService.GetProductByID(productID) + if err != nil { + log.Printf("Error fetching product: %v", err) + return utils.GenericResponse(c, fiber.StatusNotFound, err.Error()) + } + + return utils.SuccessResponse(c, product, "Product fetched successfully") +} diff --git a/internal/repositories/product_repo.go b/internal/repositories/product_repo.go new file mode 100644 index 0000000..66a60e7 --- /dev/null +++ b/internal/repositories/product_repo.go @@ -0,0 +1,101 @@ +package repositories + +import ( + "github.com/pahmiudahgede/senggoldong/model" + "gorm.io/gorm" +) + +type ProductRepository interface { + CountProductsByStoreID(storeID string) (int64, error) + CreateProduct(product *model.Product) error + GetProductByID(productID string) (*model.Product, error) + GetProductsByStoreID(storeID string) ([]model.Product, error) + FindProductsByStoreID(storeID string, page, limit int) ([]model.Product, error) + FindProductImagesByProductID(productID string) ([]model.ProductImage, error) + UpdateProduct(product *model.Product) error + DeleteProduct(productID string) error + + AddProductImages(images []model.ProductImage) error + DeleteProductImagesByProductID(productID string) error +} + +type productRepository struct { + DB *gorm.DB +} + +func NewProductRepository(DB *gorm.DB) ProductRepository { + return &productRepository{DB} +} + +func (r *productRepository) CreateProduct(product *model.Product) error { + return r.DB.Create(product).Error +} + +func (r *productRepository) CountProductsByStoreID(storeID string) (int64, error) { + var count int64 + if err := r.DB.Model(&model.Product{}).Where("store_id = ?", storeID).Count(&count).Error; err != nil { + return 0, err + } + return count, nil +} + +func (r *productRepository) GetProductByID(productID string) (*model.Product, error) { + var product model.Product + if err := r.DB.Preload("ProductImages").Where("id = ?", productID).First(&product).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return nil, err + } + return &product, nil +} + +func (r *productRepository) GetProductsByStoreID(storeID string) ([]model.Product, error) { + var products []model.Product + if err := r.DB.Where("store_id = ?", storeID).Preload("ProductImages").Find(&products).Error; err != nil { + return nil, err + } + return products, nil +} + +func (r *productRepository) FindProductsByStoreID(storeID string, page, limit int) ([]model.Product, error) { + var products []model.Product + offset := (page - 1) * limit + + if err := r.DB. + Where("store_id = ?", storeID). + Limit(limit). + Offset(offset). + Find(&products).Error; err != nil { + return nil, err + } + + return products, nil +} + +func (r *productRepository) FindProductImagesByProductID(productID string) ([]model.ProductImage, error) { + var productImages []model.ProductImage + if err := r.DB.Where("product_id = ?", productID).Find(&productImages).Error; err != nil { + return nil, err + } + return productImages, nil +} + +func (r *productRepository) UpdateProduct(product *model.Product) error { + return r.DB.Save(product).Error +} + +func (r *productRepository) DeleteProduct(productID string) error { + return r.DB.Delete(&model.Product{}, "id = ?", productID).Error +} + +func (r *productRepository) AddProductImages(images []model.ProductImage) error { + if len(images) == 0 { + return nil + } + return r.DB.Create(&images).Error +} + +func (r *productRepository) DeleteProductImagesByProductID(productID string) error { + return r.DB.Where("product_id = ?", productID).Delete(&model.ProductImage{}).Error +} diff --git a/internal/services/article_service.go b/internal/services/article_service.go index b8467ab..7d674b8 100644 --- a/internal/services/article_service.go +++ b/internal/services/article_service.go @@ -33,7 +33,7 @@ func NewArticleService(articleRepo repositories.ArticleRepository) ArticleServic func (s *articleService) CreateArticle(request dto.RequestArticleDTO, coverImage *multipart.FileHeader) (*dto.ArticleResponseDTO, error) { - coverImageDir := "./public/uploads/articles" + coverImageDir := "./public" + os.Getenv("BASE_URL") + "/uploads/articles" if err := os.MkdirAll(coverImageDir, os.ModePerm); err != nil { return nil, fmt.Errorf("failed to create directory for cover image: %v", err) } @@ -338,7 +338,7 @@ func (s *articleService) UpdateArticle(id string, request dto.RequestArticleDTO, } func (s *articleService) saveCoverImage(coverImage *multipart.FileHeader, oldImagePath string) (string, error) { - coverImageDir := "./public/uploads/articles" + coverImageDir := "/uploads/articles" if _, err := os.Stat(coverImageDir); os.IsNotExist(err) { if err := os.MkdirAll(coverImageDir, os.ModePerm); err != nil { return "", fmt.Errorf("failed to create directory for cover image: %v", err) diff --git a/internal/services/banner_service.go b/internal/services/banner_service.go index 9d5b6c1..67a5d7c 100644 --- a/internal/services/banner_service.go +++ b/internal/services/banner_service.go @@ -31,7 +31,7 @@ func NewBannerService(bannerRepo repositories.BannerRepository) BannerService { } func (s *bannerService) saveBannerImage(bannerImage *multipart.FileHeader) (string, error) { - bannerImageDir := "./public/uploads/banners" + bannerImageDir := "./public" + os.Getenv("BASE_URL") + "/uploads/banners" if _, err := os.Stat(bannerImageDir); os.IsNotExist(err) { if err := os.MkdirAll(bannerImageDir, os.ModePerm); err != nil { return "", fmt.Errorf("failed to create directory for banner image: %v", err) diff --git a/internal/services/product_service.go b/internal/services/product_service.go new file mode 100644 index 0000000..c24fa16 --- /dev/null +++ b/internal/services/product_service.go @@ -0,0 +1,228 @@ +package services + +import ( + "fmt" + "mime/multipart" + "os" + "path/filepath" + + "github.com/google/uuid" + "github.com/pahmiudahgede/senggoldong/dto" + "github.com/pahmiudahgede/senggoldong/internal/repositories" + "github.com/pahmiudahgede/senggoldong/model" + "github.com/pahmiudahgede/senggoldong/utils" +) + +type ProductService interface { + SaveProductImage(file *multipart.FileHeader, imageType string) (string, error) + CreateProduct(userID string, productDTO *dto.RequestProductDTO) (*dto.ResponseProductDTO, error) + + GetAllProductsByStoreID(userID string, page, limit int) ([]dto.ResponseProductDTO, int64, error) + GetProductByID(productID string) (*dto.ResponseProductDTO, error) +} + +type productService struct { + productRepo repositories.ProductRepository + storeRepo repositories.StoreRepository +} + +func NewProductService(productRepo repositories.ProductRepository, storeRepo repositories.StoreRepository) ProductService { + return &productService{productRepo, storeRepo} +} + +func (s *productService) CreateProduct(userID string, productDTO *dto.RequestProductDTO) (*dto.ResponseProductDTO, error) { + store, err := s.storeRepo.FindStoreByUserID(userID) + if err != nil { + return nil, fmt.Errorf("error retrieving store by user ID: %w", err) + } + if store == nil { + return nil, fmt.Errorf("store not found for user %s", userID) + } + + var imagePaths []string + var productImages []model.ProductImage + for _, file := range productDTO.ProductImages { + imagePath, err := s.SaveProductImage(file, "product") + if err != nil { + return nil, fmt.Errorf("failed to save product image: %w", err) + } + imagePaths = append(imagePaths, imagePath) + + productImages = append(productImages, model.ProductImage{ + ImageURL: imagePath, + }) + } + + if len(imagePaths) == 0 { + return nil, fmt.Errorf("at least one image is required for the product") + } + + product := model.Product{ + StoreID: store.ID, + ProductName: productDTO.ProductName, + Quantity: productDTO.Quantity, + } + + product.ProductImages = productImages + + if err := s.productRepo.CreateProduct(&product); err != nil { + return nil, fmt.Errorf("failed to create product: %w", err) + } + + createdAt, err := utils.FormatDateToIndonesianFormat(product.CreatedAt) + if err != nil { + return nil, fmt.Errorf("failed to format createdAt: %w", err) + } + updatedAt, err := utils.FormatDateToIndonesianFormat(product.UpdatedAt) + if err != nil { + return nil, fmt.Errorf("failed to format updatedAt: %w", err) + } + + var productImagesDTO []dto.ResponseProductImageDTO + for _, img := range product.ProductImages { + productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ + ID: img.ID, + ProductID: img.ProductID, + ImageURL: img.ImageURL, + }) + } + + productDTOResponse := &dto.ResponseProductDTO{ + ID: product.ID, + StoreID: product.StoreID, + ProductName: product.ProductName, + Quantity: product.Quantity, + ProductImages: productImagesDTO, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } + + return productDTOResponse, nil +} + +func (s *productService) GetAllProductsByStoreID(userID string, page, limit int) ([]dto.ResponseProductDTO, int64, error) { + + store, err := s.storeRepo.FindStoreByUserID(userID) + if err != nil { + return nil, 0, fmt.Errorf("error retrieving store by user ID: %w", err) + } + if store == nil { + return nil, 0, fmt.Errorf("store not found for user %s", userID) + } + + total, err := s.productRepo.CountProductsByStoreID(store.ID) + if err != nil { + return nil, 0, fmt.Errorf("error counting products: %w", err) + } + + products, err := s.productRepo.FindProductsByStoreID(store.ID, page, limit) + if err != nil { + return nil, 0, fmt.Errorf("error fetching products: %w", err) + } + + var productDTOs []dto.ResponseProductDTO + for _, product := range products { + productImages, err := s.productRepo.FindProductImagesByProductID(product.ID) + if err != nil { + return nil, 0, fmt.Errorf("error fetching product images: %w", err) + } + + var productImagesDTO []dto.ResponseProductImageDTO + for _, img := range productImages { + productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ + ID: img.ID, + ProductID: img.ProductID, + ImageURL: img.ImageURL, + }) + } + + createdAt, _ := utils.FormatDateToIndonesianFormat(product.CreatedAt) + updatedAt, _ := utils.FormatDateToIndonesianFormat(product.UpdatedAt) + + productDTOs = append(productDTOs, dto.ResponseProductDTO{ + ID: product.ID, + StoreID: product.StoreID, + ProductName: product.ProductName, + Quantity: product.Quantity, + Saled: product.Saled, + ProductImages: productImagesDTO, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + }) + } + + return productDTOs, total, nil +} + +func (s *productService) GetProductByID(productID string) (*dto.ResponseProductDTO, error) { + + product, err := s.productRepo.GetProductByID(productID) + if err != nil { + return nil, fmt.Errorf("failed to retrieve product: %w", err) + } + if product == nil { + return nil, fmt.Errorf("product not found") + } + + createdAt, _ := utils.FormatDateToIndonesianFormat(product.CreatedAt) + updatedAt, _ := utils.FormatDateToIndonesianFormat(product.UpdatedAt) + + productDTO := &dto.ResponseProductDTO{ + ID: product.ID, + StoreID: product.StoreID, + ProductName: product.ProductName, + Quantity: product.Quantity, + Saled: product.Saled, + CreatedAt: createdAt, + UpdatedAt: updatedAt, + } + + var productImagesDTO []dto.ResponseProductImageDTO + for _, image := range product.ProductImages { + productImagesDTO = append(productImagesDTO, dto.ResponseProductImageDTO{ + ID: image.ID, + ProductID: image.ProductID, + ImageURL: image.ImageURL, + }) + } + + productDTO.ProductImages = productImagesDTO + + return productDTO, nil +} + +func (s *productService) SaveProductImage(file *multipart.FileHeader, imageType string) (string, error) { + imageDir := fmt.Sprintf("./public%s/uploads/store/%s", os.Getenv("BASE_URL"), imageType) + if _, err := os.Stat(imageDir); os.IsNotExist(err) { + if err := os.MkdirAll(imageDir, os.ModePerm); err != nil { + return "", fmt.Errorf("failed to create directory for %s image: %v", imageType, err) + } + } + + allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true} + extension := filepath.Ext(file.Filename) + if !allowedExtensions[extension] { + return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed for %s", imageType) + } + + fileName := fmt.Sprintf("%s_%s%s", imageType, uuid.New().String(), extension) + filePath := filepath.Join(imageDir, fileName) + + fileData, err := file.Open() + if err != nil { + return "", fmt.Errorf("failed to open file: %w", err) + } + defer fileData.Close() + + outFile, err := os.Create(filePath) + if err != nil { + return "", fmt.Errorf("failed to create %s image file: %v", imageType, err) + } + defer outFile.Close() + + if _, err := outFile.ReadFrom(fileData); err != nil { + return "", fmt.Errorf("failed to save %s image: %v", imageType, err) + } + + return filepath.Join("/uploads/store/", imageType, fileName), nil +} diff --git a/internal/services/store_service.go b/internal/services/store_service.go index 067a777..43467dd 100644 --- a/internal/services/store_service.go +++ b/internal/services/store_service.go @@ -237,7 +237,7 @@ func (s *storeService) DeleteStore(storeID string) error { func (s *storeService) saveStoreImage(file *multipart.FileHeader, imageType string) (string, error) { - imageDir := fmt.Sprintf("./public/uploads/store/%s", imageType) + imageDir := fmt.Sprintf("./public%s/uploads/store/%s",os.Getenv("BASE_URL"), imageType) if _, err := os.Stat(imageDir); os.IsNotExist(err) { if err := os.MkdirAll(imageDir, os.ModePerm); err != nil { diff --git a/internal/services/user_service.go b/internal/services/user_service.go index 827a099..de79026 100644 --- a/internal/services/user_service.go +++ b/internal/services/user_service.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "log" "mime/multipart" "os" "path/filepath" @@ -16,8 +17,6 @@ import ( "golang.org/x/crypto/bcrypt" ) -const avatarDir = "./public/uploads/avatars" - var allowedExtensions = []string{".jpg", ".jpeg", ".png"} type UserProfileService interface { @@ -183,8 +182,13 @@ func (s *userProfileService) UpdateUserPassword(userID string, passwordData dto. } func (s *userProfileService) UpdateUserAvatar(userID string, file *multipart.FileHeader) (string, error) { + baseURL := os.Getenv("BASE_URL") + if baseURL == "" { + return "", fmt.Errorf("BASE_URL is not set in environment variables") + } - if err := ensureAvatarDirectoryExists(); err != nil { + avatarDir := filepath.Join("./public", baseURL, "/uploads/avatars") + if err := ensureAvatarDirectoryExists(avatarDir); err != nil { return "", err } @@ -198,13 +202,19 @@ func (s *userProfileService) UpdateUserAvatar(userID string, file *multipart.Fil } if updatedUser.Avatar != nil && *updatedUser.Avatar != "" { - oldAvatarPath := "./public" + *updatedUser.Avatar - if err := os.Remove(oldAvatarPath); err != nil { - return "", fmt.Errorf("failed to remove old avatar: %v", err) + oldAvatarPath := filepath.Join("./public", *updatedUser.Avatar) + if _, err := os.Stat(oldAvatarPath); err == nil { + + if err := os.Remove(oldAvatarPath); err != nil { + return "", fmt.Errorf("failed to remove old avatar: %v", err) + } + } else { + + log.Printf("Old avatar file not found: %s", oldAvatarPath) } } - avatarURL, err := saveAvatarFile(file, userID) + avatarURL, err := saveAvatarFile(file, userID, avatarDir) if err != nil { return "", err } @@ -217,7 +227,7 @@ func (s *userProfileService) UpdateUserAvatar(userID string, file *multipart.Fil return "Foto profil berhasil diupdate", nil } -func ensureAvatarDirectoryExists() error { +func ensureAvatarDirectoryExists(avatarDir string) error { if _, err := os.Stat(avatarDir); os.IsNotExist(err) { if err := os.MkdirAll(avatarDir, os.ModePerm); err != nil { return fmt.Errorf("failed to create avatar directory: %v", err) @@ -236,7 +246,7 @@ func validateAvatarFile(file *multipart.FileHeader) error { return fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed") } -func saveAvatarFile(file *multipart.FileHeader, userID string) (string, error) { +func saveAvatarFile(file *multipart.FileHeader, userID, avatarDir string) (string, error) { extension := filepath.Ext(file.Filename) avatarFileName := fmt.Sprintf("%s_avatar%s", userID, extension) avatarPath := filepath.Join(avatarDir, avatarFileName) @@ -258,5 +268,6 @@ func saveAvatarFile(file *multipart.FileHeader, userID string) (string, error) { return "", fmt.Errorf("failed to save avatar file: %v", err) } - return fmt.Sprintf("/uploads/avatars/%s", avatarFileName), nil + relativePath := filepath.Join("/uploads/avatars", avatarFileName) + return relativePath, nil } diff --git a/presentation/product_route.go b/presentation/product_route.go new file mode 100644 index 0000000..0fa5f8a --- /dev/null +++ b/presentation/product_route.go @@ -0,0 +1,24 @@ +package presentation + +import ( + "github.com/gofiber/fiber/v2" + "github.com/pahmiudahgede/senggoldong/config" + "github.com/pahmiudahgede/senggoldong/internal/handler" + "github.com/pahmiudahgede/senggoldong/internal/repositories" + "github.com/pahmiudahgede/senggoldong/internal/services" + "github.com/pahmiudahgede/senggoldong/middleware" + "github.com/pahmiudahgede/senggoldong/utils" +) + +func ProductRouter(api fiber.Router) { + productRepo := repositories.NewProductRepository(config.DB) + storeRepo := repositories.NewStoreRepository(config.DB) + productService := services.NewProductService(productRepo, storeRepo) + productHandler := handler.NewProductHandler(productService) + + productAPI := api.Group("/productinstore") + + productAPI.Post("/add-product", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator, utils.RolePengelola, utils.RolePengepul), productHandler.CreateProduct) + productAPI.Get("/getproductbyuser", middleware.AuthMiddleware, productHandler.GetAllProductsByStoreID) + productAPI.Get("getproduct/:product_id", middleware.AuthMiddleware, productHandler.GetProductByID) +} diff --git a/router/setup_routes.go.go b/router/setup_routes.go.go index 84e9e80..3885718 100644 --- a/router/setup_routes.go.go +++ b/router/setup_routes.go.go @@ -1,13 +1,17 @@ package router import ( + "os" + "github.com/gofiber/fiber/v2" "github.com/pahmiudahgede/senggoldong/middleware" "github.com/pahmiudahgede/senggoldong/presentation" ) func SetupRoutes(app *fiber.App) { - api := app.Group("/apirijikid/v2") + app.Static(os.Getenv("BASE_URL")+"/uploads", "./public"+os.Getenv("BASE_URL")+"/uploads") + + api := app.Group(os.Getenv("BASE_URL")) api.Use(middleware.APIKeyMiddleware) presentation.AuthRouter(api) @@ -21,4 +25,5 @@ func SetupRoutes(app *fiber.App) { presentation.InitialCointRoute(api) presentation.TrashRouter(api) presentation.StoreRouter(api) + presentation.ProductRouter(api) }