Compare commits
11 Commits
trifold
...
8ce01417e7
| Author | SHA1 | Date | |
|---|---|---|---|
|
8ce01417e7
|
|||
|
8e1df934b3
|
|||
|
17a1ef0123
|
|||
|
6330a990f5
|
|||
| f4faeb351d | |||
| 861b18651b | |||
|
5f53d66bc4
|
|||
|
459c873986
|
|||
|
ef2e6c99a7
|
|||
|
e29287c29d
|
|||
| f55470636f |
318
controllers/configController.go
Normal file
318
controllers/configController.go
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
//"git.dynamicdiscord.de/kalipso/zineshop/services"
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigController interface {
|
||||||
|
AddConfigHandler(*gin.Context)
|
||||||
|
ConfigHandler(*gin.Context)
|
||||||
|
ConfigView(*gin.Context)
|
||||||
|
|
||||||
|
GetAllPaper(*gin.Context)
|
||||||
|
PaperView(*gin.Context)
|
||||||
|
PaperHandler(*gin.Context)
|
||||||
|
AddPaperHandler(*gin.Context)
|
||||||
|
|
||||||
|
CreateTag(*gin.Context)
|
||||||
|
GetAllTags(*gin.Context)
|
||||||
|
TagView(*gin.Context)
|
||||||
|
TagHandler(*gin.Context)
|
||||||
|
AddTagHandler(*gin.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
type configController struct{}
|
||||||
|
|
||||||
|
func NewConfigController() ConfigController {
|
||||||
|
return &configController{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) AddConfigHandler(c *gin.Context) {
|
||||||
|
key := c.PostForm("key")
|
||||||
|
value := c.PostForm("value")
|
||||||
|
|
||||||
|
if key == "" || value == "" {
|
||||||
|
err := "Key or Value empty during config creation"
|
||||||
|
fmt.Println(err)
|
||||||
|
c.HTML(http.StatusBadRequest, "configview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
config := models.Config{
|
||||||
|
Key: key,
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := repositories.ConfigOptions.Create(config)
|
||||||
|
if err != nil {
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"error": err,
|
||||||
|
"success": "",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "configview.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.ConfigView(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) ConfigView(c *gin.Context) {
|
||||||
|
configOptions, err := repositories.ConfigOptions.GetAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "configview.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"configOptions": configOptions,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "configview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "configview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) ConfigHandler(ctx *gin.Context) {
|
||||||
|
key := ctx.PostForm("key")
|
||||||
|
value := ctx.PostForm("value")
|
||||||
|
action := ctx.PostForm("action")
|
||||||
|
|
||||||
|
config, err := repositories.ConfigOptions.GetById(ctx.Param("id"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "configview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "update" {
|
||||||
|
config.Key = key
|
||||||
|
config.Value = value
|
||||||
|
config, err = repositories.ConfigOptions.Update(config)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "configview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "delete" {
|
||||||
|
repositories.ConfigOptions.DeleteById(ctx.Param("id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.ConfigView(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) PaperHandler(ctx *gin.Context) {
|
||||||
|
newPaper, err := models.NewPaper(ctx)
|
||||||
|
action := ctx.PostForm("action")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "paperview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
paper, err := repositories.Papers.GetById(ctx.Param("id"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "paperview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "update" {
|
||||||
|
paper.Name = newPaper.Name
|
||||||
|
paper.Brand = newPaper.Brand
|
||||||
|
paper.Size = newPaper.Size
|
||||||
|
paper.Weight = newPaper.Weight
|
||||||
|
paper.Price = newPaper.Price
|
||||||
|
paper, err = repositories.Papers.Update(paper)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "paperview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "delete" {
|
||||||
|
repositories.Papers.DeleteById(ctx.Param("id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.PaperView(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) AddPaperHandler(c *gin.Context) {
|
||||||
|
paper, err := models.NewPaper(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
c.HTML(http.StatusBadRequest, "paperview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = repositories.Papers.Create(paper)
|
||||||
|
if err != nil {
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"error": err,
|
||||||
|
"success": "",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "paperview.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.PaperView(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) PaperView(c *gin.Context) {
|
||||||
|
papers, err := repositories.Papers.GetAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "paperview.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"paper": papers,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "paperview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "paperview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) GetAllPaper(c *gin.Context) {
|
||||||
|
papers, err := repositories.Papers.GetAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("Could not query Papers"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, papers)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
func (rc *configController) TagHandler(ctx *gin.Context) {
|
||||||
|
name := ctx.PostForm("name")
|
||||||
|
color := ctx.PostForm("color")
|
||||||
|
action := ctx.PostForm("action")
|
||||||
|
|
||||||
|
tag, err := repositories.Tags.GetById(ctx.Param("id"))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "update" {
|
||||||
|
tag.Name = name
|
||||||
|
tag.Color = color
|
||||||
|
tag, err = repositories.Tags.Update(tag)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "delete" {
|
||||||
|
repositories.Tags.DeleteById(ctx.Param("id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.TagView(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) AddTagHandler(c *gin.Context) {
|
||||||
|
tag, err := models.NewTag(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
c.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = repositories.Tags.Create(tag)
|
||||||
|
if err != nil {
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"error": err,
|
||||||
|
"success": "",
|
||||||
|
})
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "tagview.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.TagView(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) TagView(c *gin.Context) {
|
||||||
|
tags, err := repositories.Tags.GetAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "tagview.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"tags": tags,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "tagview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "tagview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) CreateTag(c *gin.Context) {
|
||||||
|
tag, err := models.NewTagByJson(c)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ReplyError(c, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = repositories.Tags.Create(tag)
|
||||||
|
if err != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("tag creation failed: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//userID := user.(models.User).ID
|
||||||
|
//rc.DB.Model(&models.shopItem{}).Where("id = ?"), room.ID).Association("Admins").Append(&models.User{ID: userID})
|
||||||
|
|
||||||
|
//if result.Error != nil {
|
||||||
|
// ReplyError(c, fmt.Errorf("shopItem creation failed: %s", result.Error))
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
ReplyOK(c, fmt.Sprintf("tag '%s' was created", tag.Name))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) GetAllTags(c *gin.Context) {
|
||||||
|
tags, err := repositories.Tags.GetAll()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ReplyError(c, fmt.Errorf("Could not query Tags"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, tags)
|
||||||
|
}
|
||||||
@@ -2,11 +2,13 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,7 +65,14 @@ func (rc *printController) PrintCartView(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paper, err := repositories.Papers.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"paper": paper,
|
||||||
"cartItems": cartItems,
|
"cartItems": cartItems,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -78,9 +87,16 @@ func (rc *printController) PrintOrderView(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paper, err := repositories.Papers.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
cartItems := order.CartItems
|
cartItems := order.CartItems
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"paper": paper,
|
||||||
"cartItems": cartItems,
|
"cartItems": cartItems,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -90,6 +106,7 @@ func (rc *printController) PrintOrderView(c *gin.Context) {
|
|||||||
func (rc *printController) PrintHandler(c *gin.Context) {
|
func (rc *printController) PrintHandler(c *gin.Context) {
|
||||||
variantIds := c.PostFormArray("variant-id[]")
|
variantIds := c.PostFormArray("variant-id[]")
|
||||||
variantAmounts := c.PostFormArray("variant-amount[]")
|
variantAmounts := c.PostFormArray("variant-amount[]")
|
||||||
|
variantPapertypes := c.PostFormArray("variant-papertype[]")
|
||||||
variantCoverPages := c.PostFormArray("variant-coverpage[]")
|
variantCoverPages := c.PostFormArray("variant-coverpage[]")
|
||||||
|
|
||||||
if len(variantIds) != len(variantAmounts) || len(variantIds) != len(variantCoverPages) {
|
if len(variantIds) != len(variantAmounts) || len(variantIds) != len(variantCoverPages) {
|
||||||
@@ -113,9 +130,53 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
coverPage := false
|
paperType, err := repositories.Papers.GetById(fmt.Sprintf("%v", variantPapertypes[idx]))
|
||||||
if variantCoverPages[idx] == "1" {
|
if err != nil {
|
||||||
coverPage = true
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var coverPage models.Paper
|
||||||
|
doPrintCoverpage := false
|
||||||
|
if variantCoverPages[idx] != "0" {
|
||||||
|
coverPage, err = repositories.Papers.GetById(fmt.Sprintf("%v", variantCoverPages[idx]))
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
doPrintCoverpage = true
|
||||||
|
}
|
||||||
|
|
||||||
|
calculatePrintCosts := func(shopItem models.ShopItem, paperType models.Paper, coverPagePaperType models.Paper, colored bool, amount int) (float64, error) {
|
||||||
|
pageCount := utils.CountPagesAtPath(shopItem.Pdf)
|
||||||
|
printMode := models.GetPrintMode(shopItem.PrintMode)
|
||||||
|
|
||||||
|
//Get actual pagecount depending on printmode
|
||||||
|
actualPageCount := pageCount
|
||||||
|
|
||||||
|
if printMode == models.CreateBooklet {
|
||||||
|
dividedCount := float64(pageCount) / 4.0
|
||||||
|
actualPageCount = int(math.Ceil(dividedCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
if printMode == models.LongEdge || printMode == models.ShortEdge {
|
||||||
|
dividedCount := float64(pageCount) / 2.0
|
||||||
|
actualPageCount = int(math.Ceil(dividedCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
PPC := 0.002604
|
||||||
|
partCost := 0.0067
|
||||||
|
if colored {
|
||||||
|
partCost = 0.0478
|
||||||
|
}
|
||||||
|
printingCosts := float64(actualPageCount) * paperType.Price
|
||||||
|
printingCosts += float64(actualPageCount/2) * PPC
|
||||||
|
printingCosts += partCost * float64(actualPageCount)
|
||||||
|
|
||||||
|
fmt.Printf("Printing Costs per Zine: %v\n", printingCosts)
|
||||||
|
fmt.Printf("Printing Costs Total: %v\n", printingCosts*float64(amount))
|
||||||
|
return printingCosts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
variantAmount, err := strconv.Atoi(variantAmounts[idx])
|
variantAmount, err := strconv.Atoi(variantAmounts[idx])
|
||||||
@@ -124,7 +185,12 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
printJob, err := models.NewPrintJob(shopItem, variant, coverPage, uint(variantAmount))
|
fmt.Println("Printing Costs:")
|
||||||
|
|
||||||
|
colored := variant.Name == "Colored"
|
||||||
|
calculatePrintCosts(shopItem, paperType, coverPage, colored, int(variantAmount))
|
||||||
|
|
||||||
|
printJob, err := models.NewPrintJob(shopItem, variant, doPrintCoverpage, uint(variantAmount))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
|||||||
@@ -29,15 +29,10 @@ type ShopItemController interface {
|
|||||||
AddItemHandler(*gin.Context)
|
AddItemHandler(*gin.Context)
|
||||||
AddItemsView(*gin.Context)
|
AddItemsView(*gin.Context)
|
||||||
AddItemsHandler(*gin.Context)
|
AddItemsHandler(*gin.Context)
|
||||||
CreateTag(*gin.Context)
|
|
||||||
GetAllTags(*gin.Context)
|
|
||||||
EditItemView(*gin.Context)
|
EditItemView(*gin.Context)
|
||||||
EditItemHandler(*gin.Context)
|
EditItemHandler(*gin.Context)
|
||||||
DeleteItemView(*gin.Context)
|
DeleteItemView(*gin.Context)
|
||||||
DeleteItemHandler(*gin.Context)
|
DeleteItemHandler(*gin.Context)
|
||||||
TagView(*gin.Context)
|
|
||||||
TagHandler(*gin.Context)
|
|
||||||
AddTagHandler(*gin.Context)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type shopItemController struct{}
|
type shopItemController struct{}
|
||||||
@@ -621,115 +616,6 @@ func (rc *shopItemController) DeleteItemHandler(c *gin.Context) {
|
|||||||
c.HTML(http.StatusOK, "index.html", data)
|
c.HTML(http.StatusOK, "index.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *shopItemController) TagHandler(ctx *gin.Context) {
|
|
||||||
name := ctx.PostForm("name")
|
|
||||||
color := ctx.PostForm("color")
|
|
||||||
action := ctx.PostForm("action")
|
|
||||||
|
|
||||||
tag, err := repositories.Tags.GetById(ctx.Param("id"))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if action == "update" {
|
|
||||||
tag.Name = name
|
|
||||||
tag.Color = color
|
|
||||||
tag, err = repositories.Tags.Update(tag)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if action == "delete" {
|
|
||||||
repositories.Tags.DeleteById(ctx.Param("id"))
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.TagView(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *shopItemController) AddTagHandler(c *gin.Context) {
|
|
||||||
tag, err := models.NewTag(c)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
c.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = repositories.Tags.Create(tag)
|
|
||||||
if err != nil {
|
|
||||||
data := CreateSessionData(c, gin.H{
|
|
||||||
"error": err,
|
|
||||||
"success": "",
|
|
||||||
})
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "tagview.html", data)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.TagView(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *shopItemController) TagView(c *gin.Context) {
|
|
||||||
tags, err := repositories.Tags.GetAll()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
c.HTML(http.StatusBadRequest, "tagview.html", gin.H{"data": gin.H{"error": err}})
|
|
||||||
}
|
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
|
||||||
"tags": tags,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
c.HTML(http.StatusBadRequest, "tagview.html", data)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "tagview.html", data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *shopItemController) CreateTag(c *gin.Context) {
|
|
||||||
tag, err := models.NewTagByJson(c)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ReplyError(c, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = repositories.Tags.Create(tag)
|
|
||||||
if err != nil {
|
|
||||||
ReplyError(c, fmt.Errorf("shopItem creation failed: %s", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//userID := user.(models.User).ID
|
|
||||||
//rc.DB.Model(&models.shopItem{}).Where("id = ?"), room.ID).Association("Admins").Append(&models.User{ID: userID})
|
|
||||||
|
|
||||||
//if result.Error != nil {
|
|
||||||
// ReplyError(c, fmt.Errorf("shopItem creation failed: %s", result.Error))
|
|
||||||
// return
|
|
||||||
//}
|
|
||||||
|
|
||||||
ReplyOK(c, fmt.Sprintf("tag '%s' was created", tag.Name))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *shopItemController) GetAllTags(c *gin.Context) {
|
|
||||||
tags, err := repositories.Tags.GetAll()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ReplyError(c, fmt.Errorf("Could not query Tags"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, tags)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReplyError(ctx *gin.Context, err error) {
|
func ReplyError(ctx *gin.Context, err error) {
|
||||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
}
|
}
|
||||||
|
|||||||
17
main.go
17
main.go
@@ -19,6 +19,7 @@ var (
|
|||||||
userController controllers.UserController = controllers.UserController{}
|
userController controllers.UserController = controllers.UserController{}
|
||||||
cartItemController controllers.CartItemController = controllers.NewCartItemController()
|
cartItemController controllers.CartItemController = controllers.NewCartItemController()
|
||||||
printController controllers.PrintController = controllers.NewPrintController()
|
printController controllers.PrintController = controllers.NewPrintController()
|
||||||
|
configController controllers.ConfigController = controllers.NewConfigController()
|
||||||
authValidator middlewares.AuthValidator = middlewares.AuthValidator{}
|
authValidator middlewares.AuthValidator = middlewares.AuthValidator{}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,10 +68,20 @@ func main() {
|
|||||||
viewRoutes.GET("/cart/print", authValidator.RequireAdmin, printController.PrintCartView)
|
viewRoutes.GET("/cart/print", authValidator.RequireAdmin, printController.PrintCartView)
|
||||||
viewRoutes.POST("/print", authValidator.RequireAdmin, printController.PrintHandler)
|
viewRoutes.POST("/print", authValidator.RequireAdmin, printController.PrintHandler)
|
||||||
|
|
||||||
viewRoutes.GET("/tags", authValidator.RequireAdmin, shopItemController.TagView)
|
viewRoutes.GET("/config", authValidator.RequireAdmin, configController.ConfigView)
|
||||||
viewRoutes.POST("/tags/:id", authValidator.RequireAdmin, shopItemController.TagHandler)
|
viewRoutes.POST("/config/:id", authValidator.RequireAdmin, configController.ConfigHandler)
|
||||||
|
viewRoutes.POST("/config", authValidator.RequireAdmin, configController.AddConfigHandler)
|
||||||
|
|
||||||
|
viewRoutes.GET("/tags", authValidator.RequireAdmin, configController.TagView)
|
||||||
|
viewRoutes.POST("/tags/:id", authValidator.RequireAdmin, configController.TagHandler)
|
||||||
viewRoutes.GET("/tags/:id", userController.TagView)
|
viewRoutes.GET("/tags/:id", userController.TagView)
|
||||||
viewRoutes.POST("/tags", authValidator.RequireAdmin, shopItemController.AddTagHandler)
|
viewRoutes.POST("/tags", authValidator.RequireAdmin, configController.AddTagHandler)
|
||||||
|
|
||||||
|
viewRoutes.GET("/paper", authValidator.RequireAdmin, configController.PaperView)
|
||||||
|
viewRoutes.POST("/paper/:id", authValidator.RequireAdmin, configController.PaperHandler)
|
||||||
|
viewRoutes.GET("/paper/:id", userController.TagView)
|
||||||
|
viewRoutes.POST("/paper", authValidator.RequireAdmin, configController.AddPaperHandler)
|
||||||
|
|
||||||
viewRoutes.GET("/cart", authValidator.RequireAuth, cartItemController.CartItemView)
|
viewRoutes.GET("/cart", authValidator.RequireAuth, cartItemController.CartItemView)
|
||||||
viewRoutes.POST("/cart", authValidator.RequireAuth, cartItemController.AddItemHandler)
|
viewRoutes.POST("/cart", authValidator.RequireAuth, cartItemController.AddItemHandler)
|
||||||
viewRoutes.POST("/cart/delete", authValidator.RequireAuth, cartItemController.DeleteItemHandler)
|
viewRoutes.POST("/cart/delete", authValidator.RequireAuth, cartItemController.DeleteItemHandler)
|
||||||
|
|||||||
11
models/config.go
Normal file
11
models/config.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
gorm.Model
|
||||||
|
Key string `json:"key" binding:"required" gorm:"unique;not null"`
|
||||||
|
Value string `json:"value" binding:"required"`
|
||||||
|
}
|
||||||
83
models/paper.go
Normal file
83
models/paper.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PaperSize string
|
||||||
|
|
||||||
|
const (
|
||||||
|
A3 PaperSize = "A3"
|
||||||
|
A4 PaperSize = "A4"
|
||||||
|
A5 PaperSize = "A5"
|
||||||
|
SRA3 PaperSize = "SRA3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseSize(s string) (c PaperSize, err error) {
|
||||||
|
s = strings.ToUpper(s)
|
||||||
|
if s == "A3" {
|
||||||
|
return A3, nil
|
||||||
|
} else if s == "A4" {
|
||||||
|
return A4, nil
|
||||||
|
} else if s == "A5" {
|
||||||
|
return A5, nil
|
||||||
|
} else if s == "SRA3" {
|
||||||
|
return SRA3, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, fmt.Errorf("Cannot parse category %s", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Paper struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string `json:"name" binding:"required" gorm:"not null"`
|
||||||
|
Brand string `json:"brand" binding:"required"`
|
||||||
|
Size PaperSize `json:"size" binding:"required"`
|
||||||
|
Weight int `json:"weight" binding:"required"`
|
||||||
|
Price float64 `json:"price" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPaper(ctx *gin.Context) (Paper, error) {
|
||||||
|
name := ctx.PostForm("name")
|
||||||
|
brand := ctx.PostForm("brand")
|
||||||
|
sizeTmp := ctx.PostForm("size")
|
||||||
|
weightTmp := ctx.PostForm("weight")
|
||||||
|
priceTmp := ctx.PostForm("price")
|
||||||
|
|
||||||
|
size, err := ParseSize(sizeTmp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Paper{}, fmt.Errorf("Couldnt parse Size")
|
||||||
|
}
|
||||||
|
|
||||||
|
weight, err := strconv.Atoi(weightTmp)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Paper{}, fmt.Errorf("Couldnt parse Weight")
|
||||||
|
}
|
||||||
|
|
||||||
|
price, err := strconv.ParseFloat(priceTmp, 64)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return Paper{}, fmt.Errorf("Couldnt parse Price")
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "" || brand == "" {
|
||||||
|
return Paper{}, fmt.Errorf("Name or brand empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the price string to float64
|
||||||
|
tag := Paper{
|
||||||
|
Name: name,
|
||||||
|
Brand: brand,
|
||||||
|
Size: size,
|
||||||
|
Weight: weight,
|
||||||
|
Price: price,
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, nil
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ const (
|
|||||||
LongEdge PrintOption = ""
|
LongEdge PrintOption = ""
|
||||||
ShortEdge PrintOption = "-o Binding=TopBinding"
|
ShortEdge PrintOption = "-o Binding=TopBinding"
|
||||||
CreateBooklet PrintOption = "-o Combination=Booklet -o PageSize=A5"
|
CreateBooklet PrintOption = "-o Combination=Booklet -o PageSize=A5"
|
||||||
TriFold PrintOption = "-o Fold=TriFold"
|
TriFold PrintOption = "-o Fold=TriFold -o Binding=TopBinding"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PrintJob struct {
|
type PrintJob struct {
|
||||||
|
|||||||
81
repositories/configRepository.go
Normal file
81
repositories/configRepository.go
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConfigRepository interface {
|
||||||
|
Create(models.Config) (models.Config, error)
|
||||||
|
GetAll() ([]models.Config, error)
|
||||||
|
GetById(string) (models.Config, error)
|
||||||
|
Update(models.Config) (models.Config, error)
|
||||||
|
DeleteById(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMConfigRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMConfigRepository(db *gorm.DB) ConfigRepository {
|
||||||
|
return &GORMConfigRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMConfigRepository) Create(config models.Config) (models.Config, error) {
|
||||||
|
result := t.DB.Create(&config)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Config{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMConfigRepository) GetAll() ([]models.Config, error) {
|
||||||
|
var configs []models.Config
|
||||||
|
result := t.DB.Find(&configs)
|
||||||
|
|
||||||
|
return configs, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMConfigRepository) GetById(id string) (models.Config, error) {
|
||||||
|
configId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return models.Config{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var config models.Config
|
||||||
|
result := t.DB.First(&config, uint(configId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Config{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMConfigRepository) Update(config models.Config) (models.Config, error) {
|
||||||
|
result := t.DB.Save(&config)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Config{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMConfigRepository) DeleteById(id string) error {
|
||||||
|
configId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := t.DB.Delete(&models.Config{}, configId)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
82
repositories/paperRepository.go
Normal file
82
repositories/paperRepository.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PaperRepository interface {
|
||||||
|
Create(models.Paper) (models.Paper, error)
|
||||||
|
GetAll() ([]models.Paper, error)
|
||||||
|
GetById(string) (models.Paper, error)
|
||||||
|
//GetByShopItemId(string) (models.Paper, error)
|
||||||
|
Update(models.Paper) (models.Paper, error)
|
||||||
|
DeleteById(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMPaperRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMPaperRepository(db *gorm.DB) PaperRepository {
|
||||||
|
return &GORMPaperRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPaperRepository) Create(tag models.Paper) (models.Paper, error) {
|
||||||
|
result := t.DB.Create(&tag)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Paper{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPaperRepository) GetAll() ([]models.Paper, error) {
|
||||||
|
var tags []models.Paper
|
||||||
|
result := t.DB.Find(&tags)
|
||||||
|
|
||||||
|
return tags, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPaperRepository) GetById(id string) (models.Paper, error) {
|
||||||
|
tagId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return models.Paper{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var tag models.Paper
|
||||||
|
result := t.DB.First(&tag, uint(tagId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Paper{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPaperRepository) Update(tag models.Paper) (models.Paper, error) {
|
||||||
|
result := t.DB.Save(&tag)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Paper{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPaperRepository) DeleteById(id string) error {
|
||||||
|
tagId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := t.DB.Delete(&models.Paper{}, tagId)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
@@ -9,12 +9,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ShopItems ShopItemRepository
|
ShopItems ShopItemRepository
|
||||||
Users UserRepository
|
Users UserRepository
|
||||||
Tags TagRepository
|
Tags TagRepository
|
||||||
CartItems CartItemRepository
|
CartItems CartItemRepository
|
||||||
Orders OrderRepository
|
Orders OrderRepository
|
||||||
Tokens RegisterTokenRepository
|
Tokens RegisterTokenRepository
|
||||||
|
ConfigOptions ConfigRepository
|
||||||
|
Papers PaperRepository
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitRepositories() {
|
func InitRepositories() {
|
||||||
@@ -29,6 +31,8 @@ func InitRepositories() {
|
|||||||
&models.Tag{},
|
&models.Tag{},
|
||||||
&models.CartItem{},
|
&models.CartItem{},
|
||||||
&models.Order{},
|
&models.Order{},
|
||||||
|
&models.Config{},
|
||||||
|
&models.Paper{},
|
||||||
&models.RegisterToken{})
|
&models.RegisterToken{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -41,4 +45,6 @@ func InitRepositories() {
|
|||||||
CartItems = NewGORMCartItemRepository(db)
|
CartItems = NewGORMCartItemRepository(db)
|
||||||
Orders = NewGORMOrderRepository(db)
|
Orders = NewGORMOrderRepository(db)
|
||||||
Tokens = NewGORMRegisterTokenRepository(db)
|
Tokens = NewGORMRegisterTokenRepository(db)
|
||||||
|
ConfigOptions = NewGORMConfigRepository(db)
|
||||||
|
Papers = NewGORMPaperRepository(db)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -674,6 +674,10 @@ video {
|
|||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mb-3 {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@@ -810,14 +814,34 @@ video {
|
|||||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-cols-2 {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-cols-4 {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.grid-cols-6 {
|
.grid-cols-6 {
|
||||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-cols-3 {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.flex-col {
|
.flex-col {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex-wrap {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-stretch {
|
||||||
|
align-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
.items-center {
|
.items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -830,6 +854,10 @@ video {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.gap-2 {
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.gap-4 {
|
.gap-4 {
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
@@ -974,6 +1002,11 @@ video {
|
|||||||
background-color: rgb(219 234 254 / var(--tw-bg-opacity, 1));
|
background-color: rgb(219 234 254 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-blue-500 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(59 130 246 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-blue-600 {
|
.bg-blue-600 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
|
background-color: rgb(37 99 235 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1049,6 +1082,11 @@ video {
|
|||||||
background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));
|
background-color: rgb(220 252 231 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-green-500 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(34 197 94 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-green-600 {
|
.bg-green-600 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1));
|
background-color: rgb(22 163 74 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1134,6 +1172,11 @@ video {
|
|||||||
background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));
|
background-color: rgb(254 226 226 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-red-500 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.bg-red-800 {
|
.bg-red-800 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(153 27 27 / var(--tw-bg-opacity, 1));
|
background-color: rgb(153 27 27 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1229,6 +1272,16 @@ video {
|
|||||||
background-color: rgb(24 24 27 / var(--tw-bg-opacity, 1));
|
background-color: rgb(24 24 27 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-gray-700 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(55 65 81 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-gray-500 {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(107 114 128 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.fill-red-50 {
|
.fill-red-50 {
|
||||||
fill: #fef2f2;
|
fill: #fef2f2;
|
||||||
}
|
}
|
||||||
@@ -1329,6 +1382,16 @@ video {
|
|||||||
padding-bottom: 2rem;
|
padding-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.py-20 {
|
||||||
|
padding-top: 5rem;
|
||||||
|
padding-bottom: 5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.px-8 {
|
||||||
|
padding-left: 2rem;
|
||||||
|
padding-right: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pb-3 {
|
.pb-3 {
|
||||||
padding-bottom: 0.75rem;
|
padding-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
@@ -1353,6 +1416,10 @@ video {
|
|||||||
padding-top: 1.25rem;
|
padding-top: 1.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pb-4 {
|
||||||
|
padding-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.text-left {
|
.text-left {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@@ -1717,17 +1784,39 @@ video {
|
|||||||
color: rgb(39 39 42 / var(--tw-text-opacity, 1));
|
color: rgb(39 39 42 / var(--tw-text-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.underline {
|
||||||
|
text-decoration-line: underline;
|
||||||
|
}
|
||||||
|
|
||||||
.antialiased {
|
.antialiased {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shadow-2xl {
|
||||||
|
--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||||
|
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
.shadow-sm {
|
.shadow-sm {
|
||||||
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
|
||||||
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.shadow-xl {
|
||||||
|
--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
|
||||||
|
--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.shadow-md {
|
||||||
|
--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||||
|
--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
|
||||||
|
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
||||||
|
}
|
||||||
|
|
||||||
.outline {
|
.outline {
|
||||||
outline-style: solid;
|
outline-style: solid;
|
||||||
}
|
}
|
||||||
@@ -1832,6 +1921,11 @@ video {
|
|||||||
background-color: rgb(67 56 202 / var(--tw-bg-opacity, 1));
|
background-color: rgb(67 56 202 / var(--tw-bg-opacity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hover\:bg-red-700:hover {
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgb(185 28 28 / var(--tw-bg-opacity, 1));
|
||||||
|
}
|
||||||
|
|
||||||
.hover\:bg-red-900:hover {
|
.hover\:bg-red-900:hover {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1));
|
background-color: rgb(127 29 29 / var(--tw-bg-opacity, 1));
|
||||||
@@ -1998,6 +2092,10 @@ video {
|
|||||||
max-width: 24rem;
|
max-width: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sm\:grid-cols-2 {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.sm\:items-center {
|
.sm\:items-center {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
@@ -2041,6 +2139,10 @@ video {
|
|||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.md\:grid-cols-3 {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.md\:flex-row {
|
.md\:flex-row {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
}
|
||||||
@@ -2089,6 +2191,14 @@ video {
|
|||||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lg\:grid-cols-4 {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.lg\:grid-cols-2 {
|
||||||
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.lg\:p-8 {
|
.lg\:p-8 {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
}
|
}
|
||||||
@@ -2112,9 +2222,17 @@ video {
|
|||||||
.xl\:grid-cols-4 {
|
.xl\:grid-cols-4 {
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.xl\:grid-cols-3 {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1536px) {
|
@media (min-width: 1536px) {
|
||||||
|
.\32xl\:grid-cols-4 {
|
||||||
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.\32xl\:px-0 {
|
.\32xl\:px-0 {
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
padding-right: 0px;
|
padding-right: 0px;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateSessionId(length int) string {
|
func GenerateSessionId(length int) string {
|
||||||
@@ -17,3 +20,41 @@ func GenerateSessionId(length int) string {
|
|||||||
func GenerateToken() string {
|
func GenerateToken() string {
|
||||||
return GenerateSessionId(16)
|
return GenerateSessionId(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const match = "/Page\x00"
|
||||||
|
|
||||||
|
// Pages reads the given io.ByteReader until EOF is reached, returning the
|
||||||
|
// number of pages encountered.
|
||||||
|
func Pages(reader io.ByteReader) (pages int) {
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
b, err := reader.ReadByte()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
check:
|
||||||
|
switch match[i] {
|
||||||
|
case 0:
|
||||||
|
if !(b >= 'A' && b <= 'Z' || b >= 'a' && b <= 'z') {
|
||||||
|
pages++
|
||||||
|
}
|
||||||
|
i = 0
|
||||||
|
goto check
|
||||||
|
case b:
|
||||||
|
i++
|
||||||
|
default:
|
||||||
|
i = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PagesAtPath opens a PDF file at the given file path, returning the number
|
||||||
|
// of pages found.
|
||||||
|
func CountPagesAtPath(path string) (pages int) {
|
||||||
|
if reader, err := os.Open(path); err == nil {
|
||||||
|
reader.Chdir()
|
||||||
|
pages = Pages(bufio.NewReader(reader))
|
||||||
|
reader.Close()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
33
views/configview.html
Normal file
33
views/configview.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{{ 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/logo-black.png" alt="Your Company">
|
||||||
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Edit config options</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
{{ range .data.configOptions }}
|
||||||
|
<form action="/config/{{ .ID }}" method="POST">
|
||||||
|
<div class="max-w-md mx-auto mt-4">
|
||||||
|
<div class="flex">
|
||||||
|
|
||||||
|
<input type="text" id="key" name="key" value="{{ .Key }}" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
<input type="text" id="value" name="value" value="{{ .Value }}" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
<button type="submit" name="action" value="update" class="bg-blue-600 text-white ml-4 mr-4 rounded px-4 hover:bg-blue-700">Update</button>
|
||||||
|
<button type="submit" name="action" value="delete" class="bg-red-800 text-white rounded px-4 hover:bg-red-900">Delete</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{{ end }}
|
||||||
|
<form action="/config" method="POST">
|
||||||
|
<div class="max-w-md mx-auto mt-4">
|
||||||
|
<div class="flex">
|
||||||
|
<input type="text" id="key" name="key" placeholder="" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
<input type="text" id="value" name="value" placeholder="" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
<button type="submit" class="bg-green-600 text-white ml-4 mr-4 rounded px-4 hover:bg-green-700">Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{ template "footer.html" . }}
|
||||||
@@ -38,6 +38,10 @@
|
|||||||
hover:text-white">Print</a>
|
hover:text-white">Print</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
|
<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>
|
hover:text-white">Cart</a>
|
||||||
|
<a href="/config" 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">Config</a>
|
||||||
|
<a href="/paper" 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">Paper</a>
|
||||||
<a href="/logout" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-red-300 hover:bg-gray-700 hover:text-white">Logout</a>
|
<a href="/logout" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-red-300 hover:bg-gray-700 hover:text-white">Logout</a>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
82
views/paperview.html
Normal file
82
views/paperview.html
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
{{ 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/logo-black.png" alt="Your Company">
|
||||||
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Edit Paper</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 ">
|
||||||
|
<div class="w-full grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 2xl:grid-cols-4 gap-4">
|
||||||
|
{{ range .data.paper }}
|
||||||
|
<form action="/paper/{{ .ID }}" method="POST">
|
||||||
|
<div class="max-w-md mx-auto p-4 m-4 bg-gray-100 flex flex-wrap border rounded shadow-md">
|
||||||
|
<div class="font-bold text-center mb-4">
|
||||||
|
{{ .Brand }} - {{ .Name }}: {{ .Size }} {{ .Weight }}g/m2
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Name</label>
|
||||||
|
<input type="text" id="name" name="name" value="{{ .Name }}" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Brand</label>
|
||||||
|
<input type="text" id="brand" name="brand" value="{{ .Brand }}" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">DIN Size</label>
|
||||||
|
<input type="text" id="size" name="size" value="{{ .Size }}" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Weight</label>
|
||||||
|
<input type="text" id="weight" name="weight" value="{{ .Weight }}" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Price per Sheet</label>
|
||||||
|
<input type="number" step="0.0001" min="0.0000" id="price" name="price" value="{{ .Price }}" class="w-full flex-grow border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 mt-4 flex flex-wrap gap-2 w-full">
|
||||||
|
<button type="submit" name="action" value="update" class="bg-blue-500 hover:bg-blue-700 text-white text-sm/6 font-bold py-2 px-4 rounded">Update</button>
|
||||||
|
<button type="submit" name="action" value="delete" class="bg-red-500 hover:bg-red-700 text-white text-sm/6 font-bold py-2 px-4 rounded">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<form action="/paper" method="POST">
|
||||||
|
<div class="max-w-md mx-auto p-4 flex flex-wrap border rounded shadow-md">
|
||||||
|
<div class="font-bold text-center mb-4">
|
||||||
|
Add new Paper
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Name</label>
|
||||||
|
<input type="text" id="name" name="name" placeholder="name" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Brand</label>
|
||||||
|
<input type="text" id="brand" name="brand" placeholder="brand" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">DIN Size</label>
|
||||||
|
<input type="text" id="size" name="size" placeholder="size" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Weight</label>
|
||||||
|
<input type="text" id="weight" name="weight" placeholder="Weight" class="w-full border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Price per Sheet</label>
|
||||||
|
<input type="number" step="0.0001" min="0.0000" id="price" name="price" placeholder="price per sheet"
|
||||||
|
class="w-full flex-grow border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-4 mt-4 flex flex-wrap gap-2 w-full">
|
||||||
|
<button type="submit" class="bg-green-500 hover:bg-green-700 text-white text-sm/6 font-bold py-2 px-4 rounded">Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{ template "footer.html" . }}
|
||||||
@@ -37,10 +37,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td class="whitespace-nowrap py-4">
|
||||||
|
<select name="variant-papertype[]" required class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
||||||
|
{{ range $.data.paper }}
|
||||||
|
<option value="{{ .ID }}">{{ .Brand }} - {{ .Name }}: {{ .Size }} {{ .Weight }}g/m2</option>
|
||||||
|
{{ end}}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td class="whitespace-nowrap py-4">
|
<td class="whitespace-nowrap py-4">
|
||||||
<select name="variant-coverpage[]" required class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
<select name="variant-coverpage[]" required class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
|
||||||
<option selected value="0">Normal</option>
|
<option selected value="0">None</option>
|
||||||
<option value="1">CoverPage</option>
|
{{ range $.data.paper }}
|
||||||
|
<option value="{{ .ID }}">{{ .Brand }} - {{ .Name }}: {{ .Size }} {{ .Weight }}g/m2</option>
|
||||||
|
{{ end}}
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap py-4">
|
<td class="whitespace-nowrap py-4">
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<div class="myClass group relative">
|
<div class="myClass group relative">
|
||||||
<a href="/shopitems/{{ .ID }}">
|
<a href="/shopitems/{{ .ID }}">
|
||||||
<img loading="lazy" src="/{{ .Image }}" alt="Product Image" class="aspect-4/5 mx-auto rounded bg-gray-200 object-cover group-hover:opacity-75 lg:aspect-auto lg:h-80">
|
<img loading="lazy" src="/{{ .Image }}" alt="Product Image" class="shadow-2xl aspect-4/5 mx-auto rounded bg-gray-200 object-cover group-hover:opacity-75 lg:aspect-auto lg:h-80">
|
||||||
</a>
|
</a>
|
||||||
<div class="mt-4 flex justify-between">
|
<div class="mt-4 flex justify-between">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user