first commit
This commit is contained in:
161
controllers/product_controller.go
Normal file
161
controllers/product_controller.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
database "ares/database/config"
|
||||
"ares/database/models"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// GetProducts godoc
|
||||
// @Summary List products (public) with pagination
|
||||
// @Tags Products
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number"
|
||||
// @Param per_page query int false "Items per page"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /api/v1/products [get]
|
||||
func GetProducts(c fiber.Ctx) error {
|
||||
pageStr := c.Query("page", "1")
|
||||
perPageStr := c.Query("per_page", "10")
|
||||
page, _ := strconv.Atoi(pageStr)
|
||||
perPage, _ := strconv.Atoi(perPageStr)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 10
|
||||
}
|
||||
if perPage > 100 {
|
||||
perPage = 100
|
||||
}
|
||||
offset := (page - 1) * perPage
|
||||
|
||||
var total int64
|
||||
database.DB.Model(&models.Product{}).Count(&total)
|
||||
|
||||
var products []models.Product
|
||||
database.DB.Preload("Categories").Preload("Tags").Limit(perPage).Offset(offset).Order("created_at desc").Find(&products)
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"data": products,
|
||||
"meta": fiber.Map{"page": page, "per_page": perPage, "total": total},
|
||||
})
|
||||
}
|
||||
|
||||
// GetProduct godoc
|
||||
// @Summary Get single product (public) by slug
|
||||
// @Tags Products
|
||||
// @Produce json
|
||||
// @Param slug path string true "Product slug"
|
||||
// @Success 200 {object} models.ProductDoc
|
||||
// @Failure 404 {object} map[string]string
|
||||
// @Router /api/v1/products/{slug} [get]
|
||||
func GetProduct(c fiber.Ctx) error {
|
||||
slug := c.Params("slug")
|
||||
if slug == "" {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid slug"})
|
||||
}
|
||||
|
||||
var product models.Product
|
||||
if err := database.DB.Preload("Categories").Preload("Tags").Where("slug = ? AND deleted_at IS NULL", slug).First(&product).Error; err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "product not found"})
|
||||
}
|
||||
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "db error"})
|
||||
}
|
||||
|
||||
return c.JSON(product)
|
||||
}
|
||||
|
||||
// AddProductCommentRequest represents payload
|
||||
type AddProductCommentRequest struct {
|
||||
ProductID uint `json:"product_id" validate:"required"`
|
||||
Body string `json:"body" validate:"required,min=3"`
|
||||
}
|
||||
|
||||
|
||||
func AddProductComment(c fiber.Ctx) error {
|
||||
userID, ok := c.Locals("user_id").(uint)
|
||||
if !ok || userID == 0 {
|
||||
return c.Status(http.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"})
|
||||
}
|
||||
|
||||
var input AddProductCommentRequest
|
||||
if err := c.Bind().Body(&input); err != nil {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
||||
}
|
||||
|
||||
// Add validation if needed
|
||||
if input.Body == "" {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "body is required"})
|
||||
}
|
||||
|
||||
var product models.Product
|
||||
if err := database.DB.First(&product, input.ProductID).Error; err != nil {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "product not found"})
|
||||
}
|
||||
|
||||
comment := models.ProductComment{
|
||||
UserID: userID,
|
||||
ProductID: input.ProductID,
|
||||
Body: input.Body,
|
||||
}
|
||||
|
||||
if err := database.DB.Create(&comment).Error; err != nil {
|
||||
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not save comment"})
|
||||
}
|
||||
|
||||
return c.Status(http.StatusCreated).JSON(comment)
|
||||
}
|
||||
|
||||
// GetProductComments godoc
|
||||
// @Summary Get comments for a product
|
||||
// @Tags Products
|
||||
// @Produce json
|
||||
// @Param id path int true "Product ID"
|
||||
// @Success 200 {array} models.ProductCommentDoc
|
||||
// @Router /api/v1/products/{id}/comments [get]
|
||||
func GetProductComments(c fiber.Ctx) error {
|
||||
productID, err := strconv.Atoi(c.Params("id"))
|
||||
if err != nil {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid product id"})
|
||||
}
|
||||
|
||||
var comments []models.ProductComment
|
||||
database.DB.Where("product_id = ?", productID).Order("created_at desc").Find(&comments)
|
||||
|
||||
return c.JSON(comments)
|
||||
}
|
||||
|
||||
// RecordProductCategoryView godoc
|
||||
// @Summary Record a view for a product category
|
||||
// @Tags Products
|
||||
// @Produce json
|
||||
// @Param id path int true "Category ID"
|
||||
// @Success 201 {object} models.ProductCategoryViewDoc
|
||||
// @Router /api/v1/product-categories/{id}/view [post]
|
||||
func RecordProductCategoryView(c fiber.Ctx) error {
|
||||
categoryID, err := strconv.Atoi(c.Params("id"))
|
||||
if err != nil {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid category id"})
|
||||
}
|
||||
|
||||
var category models.ProductCategory
|
||||
if err := database.DB.First(&category, categoryID).Error; err != nil {
|
||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "category not found"})
|
||||
}
|
||||
|
||||
view := models.ProductCategoryView{
|
||||
CategoryID: uint(categoryID),
|
||||
IPAddress: c.IP(),
|
||||
}
|
||||
|
||||
database.DB.Create(&view)
|
||||
|
||||
return c.Status(http.StatusCreated).JSON(view)
|
||||
}
|
||||
Reference in New Issue
Block a user