add basic cart
This commit is contained in:
239
controllers/cartItemController.go
Normal file
239
controllers/cartItemController.go
Normal file
@@ -0,0 +1,239 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"example.com/gin/test/models"
|
||||
//"example.com/gin/test/services"
|
||||
"example.com/gin/test/repositories"
|
||||
)
|
||||
|
||||
type CartItemController interface {
|
||||
//CRUDController
|
||||
CartItemView(*gin.Context)
|
||||
AddItemHandler(*gin.Context)
|
||||
//EditCartItemHandler(*gin.Context)
|
||||
//DeleteCartItemHandler(*gin.Context)
|
||||
}
|
||||
|
||||
type cartItemController struct {}
|
||||
|
||||
func NewCartItemController() CartItemController {
|
||||
return &cartItemController{}
|
||||
}
|
||||
|
||||
func generateSessionId() string {
|
||||
bytes := make([]byte, 16) // 16 bytes = 128 bits
|
||||
_, err := rand.Read(bytes)
|
||||
if err != nil {
|
||||
panic("failed to generate session ID")
|
||||
}
|
||||
return hex.EncodeToString(bytes)
|
||||
}
|
||||
|
||||
func GetSessionId(ctx *gin.Context) string {
|
||||
sessionId, err := ctx.Cookie("session_id")
|
||||
|
||||
if err != nil {
|
||||
sessionId = generateSessionId()
|
||||
ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true)
|
||||
}
|
||||
|
||||
return sessionId
|
||||
}
|
||||
|
||||
func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) {
|
||||
fmt.Println("NEWITEM")
|
||||
sessionId := GetSessionId(ctx)
|
||||
|
||||
shopItemId, err := strconv.Atoi(ctx.PostForm("ShopItemId"))
|
||||
|
||||
if err != nil {
|
||||
return models.CartItem{}, err
|
||||
}
|
||||
|
||||
quantity := 1
|
||||
//quantity, err := strconv.Atoi(ctx.PostForm("quantity"))
|
||||
|
||||
//if err != nil {
|
||||
// return models.CartItem{}, err
|
||||
//}
|
||||
|
||||
cartItem := models.CartItem{
|
||||
SessionId: sessionId,
|
||||
ShopItemId: shopItemId,
|
||||
Quantity: quantity,
|
||||
}
|
||||
|
||||
fmt.Println("NEWITEM")
|
||||
return cartItem, nil
|
||||
}
|
||||
|
||||
|
||||
func (rc *cartItemController) Create(c *gin.Context) {
|
||||
cartItem, err := rc.NewCartItemFromForm(c)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Create(cartItem)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
ReplyOK(c, "cartItem was created")
|
||||
}
|
||||
|
||||
|
||||
func (rc *cartItemController) Update(c *gin.Context) {
|
||||
cartItem, err := rc.NewCartItemFromForm(c)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Update(cartItem)
|
||||
|
||||
if err != nil {
|
||||
ReplyError(c, fmt.Errorf("cartItem creation failed: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
ReplyOK(c, "cartItem was updated")
|
||||
}
|
||||
|
||||
//func (rc *cartItemController) Delete(c *gin.Context) {
|
||||
// err := repositories.CartItems.DeleteBySessionId(c.Param("id"))
|
||||
//
|
||||
// if err != nil {
|
||||
// ReplyError(c, fmt.Errorf("cartItem deletion failed: %s", err))
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// ReplyOK(c, "cartItem was deleted")
|
||||
//}
|
||||
|
||||
func (rc *cartItemController) CartItemView(c *gin.Context) {
|
||||
sessionId := GetSessionId(c)
|
||||
|
||||
cartItems, err := repositories.CartItems.GetAllBySession(sessionId)
|
||||
|
||||
if err != nil {
|
||||
c.HTML(http.StatusBadRequest, "cart.html", gin.H{ "data": gin.H{ "error": err } })
|
||||
}
|
||||
|
||||
data := CreateSessionData(c, gin.H{
|
||||
"cartItems": cartItems,
|
||||
})
|
||||
|
||||
c.HTML(http.StatusOK, "cart.html", data)
|
||||
}
|
||||
|
||||
func (rc *cartItemController) AddItemHandler(c *gin.Context) {
|
||||
cartItem, err := rc.NewCartItemFromForm(c)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
c.HTML(http.StatusBadRequest, "cart.html", gin.H{ "error": err })
|
||||
return
|
||||
}
|
||||
|
||||
_, err = repositories.CartItems.Create(cartItem)
|
||||
if err != nil {
|
||||
data := CreateSessionData(c, gin.H{
|
||||
"error": err,
|
||||
"success": "",
|
||||
})
|
||||
|
||||
c.HTML(http.StatusOK, "cart.html", data)
|
||||
return
|
||||
}
|
||||
|
||||
rc.CartItemView(c)
|
||||
}
|
||||
|
||||
|
||||
//func (rc *cartItemController) EditItemHandler(c *gin.Context) {
|
||||
// cartItem, err := rc.NewCartItemFromForm(c)
|
||||
//
|
||||
// if err != nil {
|
||||
// c.HTML(http.StatusBadRequest, "edititem.html", gin.H{ "error": err })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// newCartItem, err := repositories.ShopItems.GetById(c.Param("id"))
|
||||
//
|
||||
// if err != nil {
|
||||
// c.HTML(http.StatusBadRequest, "edititem.html", gin.H{ "error": err })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// newCartItem.Name = cartItem.Name
|
||||
// newCartItem.Abstract = cartItem.Abstract
|
||||
// newCartItem.Description = cartItem.Description
|
||||
// newCartItem.Price = cartItem.Price
|
||||
// newCartItem.IsPublic = cartItem.IsPublic
|
||||
// newCartItem.Tags = cartItem.Tags
|
||||
//
|
||||
// tags, err := repositories.Tags.GetAll()
|
||||
// if err != nil {
|
||||
// c.HTML(http.StatusBadRequest, "edititem.html", gin.H{ "error": err })
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// _, err = repositories.CartItems.Update(newShopItem)
|
||||
// if err != nil {
|
||||
// data := CreateSessionData(c, gin.H{
|
||||
// "error": err,
|
||||
// "success": "",
|
||||
// "tags": tags,
|
||||
// })
|
||||
//
|
||||
// c.HTML(http.StatusOK, "edititem.html", data)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// data := CreateSessionData(c, gin.H{
|
||||
// "error": "",
|
||||
// "success": fmt.Sprintf("Item '%s' Updated", newCartItem.Name),
|
||||
// "tags": tags,
|
||||
// })
|
||||
//
|
||||
// c.HTML(http.StatusOK, "edititem.html", data)
|
||||
//}
|
||||
|
||||
//func (rc *cartItemController) DeleteItemHandler(c *gin.Context) {
|
||||
// err := repositories.CartItems.DeleteById(c.Param("id"))
|
||||
//
|
||||
// if err != nil {
|
||||
// data := CreateSessionData(c, gin.H{
|
||||
// "error": err,
|
||||
// "success": "",
|
||||
// })
|
||||
//
|
||||
// c.HTML(http.StatusOK, "deleteitem.html", data)
|
||||
// }
|
||||
//
|
||||
// cartItems, _ := repositories.CartItems.GetAll()
|
||||
// fmt.Println(len(cartItems))
|
||||
//
|
||||
// data := CreateSessionData(c, gin.H{
|
||||
// "title": "cartItem Page",
|
||||
// "cartItems": shopItems,
|
||||
// })
|
||||
//
|
||||
// fmt.Println(data)
|
||||
//
|
||||
// c.HTML(http.StatusOK, "index.html", data)
|
||||
//}
|
||||
4
main.go
4
main.go
@@ -17,6 +17,7 @@ import(
|
||||
var(
|
||||
shopItemController controllers.ShopItemController = controllers.NewShopItemController()
|
||||
userController controllers.UserController = controllers.UserController{}
|
||||
cartItemController controllers.CartItemController = controllers.NewCartItemController()
|
||||
authValidator middlewares.AuthValidator = middlewares.AuthValidator{}
|
||||
)
|
||||
|
||||
@@ -84,6 +85,9 @@ func main() {
|
||||
viewRoutes.GET("/tags", authValidator.RequireAuth, shopItemController.TagView)
|
||||
viewRoutes.POST("/tags/:id", authValidator.RequireAuth, shopItemController.TagHandler)
|
||||
viewRoutes.POST("/tags", authValidator.RequireAuth, shopItemController.AddTagHandler)
|
||||
viewRoutes.GET("/cart", cartItemController.CartItemView)
|
||||
viewRoutes.POST("/cart", cartItemController.AddItemHandler)
|
||||
|
||||
//write middleware that redirects to homescreen on register/login/reset for logged in users
|
||||
viewRoutes.GET("/login", userController.LoginView)
|
||||
viewRoutes.GET("/logout", userController.Logout)
|
||||
|
||||
12
models/cart.go
Normal file
12
models/cart.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CartItem struct {
|
||||
gorm.Model
|
||||
SessionId string `gorm:"index"`
|
||||
ShopItemId int `gorm:"index"`
|
||||
Quantity int
|
||||
}
|
||||
57
repositories/cartItemRepository.go
Normal file
57
repositories/cartItemRepository.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package repositories
|
||||
|
||||
import(
|
||||
"gorm.io/gorm"
|
||||
|
||||
"example.com/gin/test/models"
|
||||
)
|
||||
|
||||
type CartItemRepository interface {
|
||||
Create(models.CartItem) (models.CartItem, error)
|
||||
GetAll() ([]models.CartItem, error)
|
||||
GetAllBySession(string) ([]models.CartItem, error)
|
||||
Update(models.CartItem) (models.CartItem, error)
|
||||
}
|
||||
|
||||
type GORMCartItemRepository struct {
|
||||
DB *gorm.DB
|
||||
}
|
||||
|
||||
func NewGORMCartItemRepository(db *gorm.DB) CartItemRepository {
|
||||
return &GORMCartItemRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) Create(cartItem models.CartItem) (models.CartItem, error) {
|
||||
result := r.DB.Create(&cartItem)
|
||||
if result.Error != nil {
|
||||
return models.CartItem{}, result.Error
|
||||
}
|
||||
|
||||
return cartItem, nil
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) GetAll() ([]models.CartItem, error) {
|
||||
var cartItems []models.CartItem
|
||||
result := r.DB.Find(&cartItems)
|
||||
|
||||
return cartItems, result.Error
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) GetAllBySession(sessionId string) ([]models.CartItem, error) {
|
||||
var cartItems []models.CartItem
|
||||
result := r.DB.Where("session_id = ?", sessionId).Find(&cartItems)
|
||||
|
||||
return cartItems, result.Error
|
||||
|
||||
}
|
||||
|
||||
func (r *GORMCartItemRepository) Update(cartItem models.CartItem) (models.CartItem, error) {
|
||||
result := r.DB.Save(&cartItem)
|
||||
if result.Error != nil {
|
||||
return models.CartItem{}, result.Error
|
||||
}
|
||||
|
||||
return cartItem, nil
|
||||
}
|
||||
@@ -12,6 +12,7 @@ var(
|
||||
ShopItems ShopItemRepository
|
||||
Users UserRepository
|
||||
Tags TagRepository
|
||||
CartItems CartItemRepository
|
||||
)
|
||||
|
||||
func InitRepositories() {
|
||||
@@ -20,7 +21,7 @@ func InitRepositories() {
|
||||
panic("failed to connect to database")
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&models.ShopItem{}, &models.User{}, &models.Tag{})
|
||||
err = db.AutoMigrate(&models.ShopItem{}, &models.User{}, &models.Tag{}, &models.CartItem{})
|
||||
if err != nil {
|
||||
panic("failed to migrate database")
|
||||
}
|
||||
@@ -28,4 +29,5 @@ func InitRepositories() {
|
||||
ShopItems = NewGORMShopItemRepository(db)
|
||||
Users = NewGORMUserRepository(db)
|
||||
Tags = NewGORMTagRepository(db)
|
||||
CartItems = NewGORMCartItemRepository(db)
|
||||
}
|
||||
|
||||
35
views/addtag.html
Normal file
35
views/addtag.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{ template "header.html" . }}
|
||||
|
||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
||||
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||
<img class="mx-auto h-10 w-auto" src="/static/img/circlea.png" alt="Your Company">
|
||||
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Add Tag</h2>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||
<form class="space-y-6" action="#" method="POST" enctype="multipart/form-data">
|
||||
<div>
|
||||
<label for="name" class="block text-sm/6 font-medium text-gray-900">Name</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="name" id="name" required class="block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="mt-10 text-center text-sm/6 text-red-500">
|
||||
{{ .data.error }}
|
||||
</p>
|
||||
<p class="mt-10 text-center text-sm/6 text-green-500">
|
||||
{{ .data.success }}
|
||||
</p>
|
||||
|
||||
|
||||
<div>
|
||||
<button type="submit" class="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm/6 font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Add Tag</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{ template "footer.html" . }}
|
||||
18
views/cart.html
Normal file
18
views/cart.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{{ template "header.html" . }}
|
||||
|
||||
{{ range .data.cartItems }}
|
||||
|
||||
<div class="group relative">
|
||||
<div class="mt-4 flex justify-between">
|
||||
<div>
|
||||
<h3 class="text-sm text-gray-700">
|
||||
{{ .ShopItemId }}
|
||||
</h3>
|
||||
</div>
|
||||
<p class="text-sm font-medium text-gray-900">{{ .Quantity }} pieces</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{ template "footer.html" . }}
|
||||
@@ -33,8 +33,7 @@
|
||||
</div>
|
||||
{{ else }}
|
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0 px-4 sm:px-8">
|
||||
<a href="/login" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Login</a>
|
||||
<a href="/register" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">Register</a>
|
||||
<a href="/cart" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300 hover:bg-gray-700 hover:text-white">🛒 Cart</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
<img class="w-full h-full object-cover" src="/{{ .data.shopItem.Image}}" alt="Product Image">
|
||||
</div>
|
||||
<div class="flex -mx-2 mb-4">
|
||||
<form action="/cart" method="POST">
|
||||
<input type="hidden" id="{{ .data.shopItem.ID}}" name="ShopItemId" value="{{ .data.shopItem.ID }}">
|
||||
<div class="w-1/3 px-2">
|
||||
<button class="w-full bg-gray-900 dark:bg-gray-600 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800 dark:hover:bg-gray-700">Add to Cart</button>
|
||||
<button type="submit" class="w-full bg-gray-900 dark:bg-gray-600 text-white py-2 px-4 rounded-full font-bold hover:bg-gray-800 dark:hover:bg-gray-700">Add to Cart</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{{ if .loggedIn }}
|
||||
<div class="w-1/3 px-2">
|
||||
|
||||
Reference in New Issue
Block a user