238 lines
7.0 KiB
Go
238 lines
7.0 KiB
Go
package controllers
|
|
|
|
import (
|
|
database "ares/database/config"
|
|
"ares/database/models"
|
|
"errors"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/gofiber/fiber/v3"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// getOrCreateCart is a helper to fetch the cart of the current user.
|
|
func getOrCreateCart(userID uint) (models.Cart, error) {
|
|
var cart models.Cart
|
|
if err := database.DB.Preload("Items").Preload("Items.Product").Where("user_id = ?", userID).First(&cart).Error; err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
cart = models.Cart{UserID: userID}
|
|
if createErr := database.DB.Create(&cart).Error; createErr != nil {
|
|
return cart, createErr
|
|
}
|
|
return cart, nil
|
|
}
|
|
return cart, err
|
|
}
|
|
return cart, nil
|
|
}
|
|
|
|
// GetMyCart godoc
|
|
// @Summary Get the current user's cart
|
|
// @Tags Cart
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Success 200 {object} models.CartDoc
|
|
// @Failure 401 {object} map[string]string
|
|
// @Router /api/v1/cart [get]
|
|
func GetMyCart(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"})
|
|
}
|
|
|
|
cart, err := getOrCreateCart(userID)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not load cart"})
|
|
}
|
|
|
|
return c.JSON(cart)
|
|
}
|
|
|
|
// AddToCartRequest represents the body for adding to a cart
|
|
type AddToCartRequest struct {
|
|
ProductID uint `json:"product_id" validate:"required"`
|
|
Quantity int `json:"quantity" validate:"required,min=1"`
|
|
}
|
|
|
|
// AddToCart godoc
|
|
// @Summary Add item to cart
|
|
// @Tags Cart
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param data body AddToCartRequest true "Cart Item Details"
|
|
// @Success 200 {object} models.CartDoc
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Router /api/v1/cart/items [post]
|
|
func AddToCart(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 AddToCartRequest
|
|
if err := c.Bind().Body(&input); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
|
}
|
|
|
|
if err := validate.Struct(input); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
|
|
// Check product exists
|
|
var product models.Product
|
|
if err := database.DB.First(&product, input.ProductID).Error; err != nil {
|
|
return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "product not found"})
|
|
}
|
|
|
|
cart, err := getOrCreateCart(userID)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not load cart"})
|
|
}
|
|
|
|
// Check if item already exists in cart
|
|
var existingItem models.CartItem
|
|
if err := database.DB.Where("cart_id = ? AND product_id = ?", cart.ID, input.ProductID).First(&existingItem).Error; err == nil {
|
|
// Update quantity
|
|
existingItem.Quantity += input.Quantity
|
|
database.DB.Save(&existingItem)
|
|
} else {
|
|
// Create new item
|
|
newItem := models.CartItem{
|
|
CartID: cart.ID,
|
|
ProductID: input.ProductID,
|
|
Quantity: input.Quantity,
|
|
}
|
|
database.DB.Create(&newItem)
|
|
}
|
|
|
|
// Return updated cart
|
|
cart, _ = getOrCreateCart(userID)
|
|
return c.JSON(cart)
|
|
}
|
|
|
|
// UpdateCartItemRequest represents the body for updating a cart item quantity
|
|
type UpdateCartItemRequest struct {
|
|
Quantity int `json:"quantity" validate:"required,min=1"`
|
|
}
|
|
|
|
// UpdateCartItem godoc
|
|
// @Summary Update cart item quantity
|
|
// @Tags Cart
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param item_id path int true "Cart Item ID"
|
|
// @Param data body UpdateCartItemRequest true "Update Quantity"
|
|
// @Success 200 {object} models.CartDoc
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Router /api/v1/cart/items/{item_id} [put]
|
|
func UpdateCartItem(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"})
|
|
}
|
|
|
|
itemID, err := strconv.ParseUint(c.Params("item_id"), 10, 32)
|
|
if err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid item id"})
|
|
}
|
|
|
|
var input UpdateCartItemRequest
|
|
if err := c.Bind().Body(&input); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid payload"})
|
|
}
|
|
|
|
if err := validate.Struct(input); err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": err.Error()})
|
|
}
|
|
|
|
cart, err := getOrCreateCart(userID)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not load cart"})
|
|
}
|
|
|
|
var cartItem models.CartItem
|
|
if err := database.DB.Where("id = ? AND cart_id = ?", itemID, cart.ID).First(&cartItem).Error; err != nil {
|
|
return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "item not found in your cart"})
|
|
}
|
|
|
|
cartItem.Quantity = input.Quantity
|
|
database.DB.Save(&cartItem)
|
|
|
|
// Return updated cart
|
|
cart, _ = getOrCreateCart(userID)
|
|
return c.JSON(cart)
|
|
}
|
|
|
|
// RemoveFromCart godoc
|
|
// @Summary Remove item from cart
|
|
// @Tags Cart
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Param item_id path int true "Cart Item ID"
|
|
// @Success 200 {object} models.CartDoc
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Router /api/v1/cart/items/{item_id} [delete]
|
|
func RemoveFromCart(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"})
|
|
}
|
|
|
|
itemID, err := strconv.ParseUint(c.Params("item_id"), 10, 32)
|
|
if err != nil {
|
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{"error": "invalid item id"})
|
|
}
|
|
|
|
cart, err := getOrCreateCart(userID)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not load cart"})
|
|
}
|
|
|
|
var cartItem models.CartItem
|
|
if err := database.DB.Where("id = ? AND cart_id = ?", itemID, cart.ID).First(&cartItem).Error; err != nil {
|
|
return c.Status(http.StatusNotFound).JSON(fiber.Map{"error": "item not found in your cart"})
|
|
}
|
|
|
|
database.DB.Delete(&cartItem)
|
|
|
|
// Return updated cart
|
|
cart, _ = getOrCreateCart(userID)
|
|
return c.JSON(cart)
|
|
}
|
|
|
|
// ClearCart godoc
|
|
// @Summary Clear the entire cart
|
|
// @Tags Cart
|
|
// @Produce json
|
|
// @Security BearerAuth
|
|
// @Success 200 {object} models.CartDoc
|
|
// @Failure 401 {object} map[string]string
|
|
// @Router /api/v1/cart [delete]
|
|
func ClearCart(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"})
|
|
}
|
|
|
|
cart, err := getOrCreateCart(userID)
|
|
if err != nil {
|
|
return c.Status(http.StatusInternalServerError).JSON(fiber.Map{"error": "could not load cart"})
|
|
}
|
|
|
|
// Delete all items for this cart
|
|
database.DB.Where("cart_id = ?", cart.ID).Delete(&models.CartItem{})
|
|
|
|
// Return updated empty cart
|
|
cart, _ = getOrCreateCart(userID)
|
|
return c.JSON(cart)
|
|
}
|