Compare commits
60 Commits
37ffeaa0f3
...
priceCalcu
| Author | SHA1 | Date | |
|---|---|---|---|
|
249cccd240
|
|||
|
db3dc9ecd1
|
|||
|
b75c46ec2f
|
|||
|
16c68cd0f8
|
|||
|
ad5573ee2c
|
|||
|
6c0440f06d
|
|||
|
9e638dcfc2
|
|||
|
6c59d1233f
|
|||
|
7025f526c1
|
|||
|
992b9c17c3
|
|||
|
4b0649439c
|
|||
|
8ce01417e7
|
|||
|
8e1df934b3
|
|||
|
17a1ef0123
|
|||
|
6330a990f5
|
|||
| f4faeb351d | |||
| 861b18651b | |||
|
5f53d66bc4
|
|||
|
459c873986
|
|||
|
ef2e6c99a7
|
|||
|
e29287c29d
|
|||
| f55470636f | |||
|
8f89c14961
|
|||
|
6f5c0354cc
|
|||
|
6ef7c53001
|
|||
|
d4e7401586
|
|||
|
1688e61ccb
|
|||
|
861343b338
|
|||
|
68c8654bf3
|
|||
|
e62a45372f
|
|||
|
d17c33f6ee
|
|||
|
ae36903e73
|
|||
|
1a5df21fa8
|
|||
|
9c15514758
|
|||
|
27cf7c37cf
|
|||
|
03f1ce361a
|
|||
| c55cf4480b | |||
|
bcbb091dfb
|
|||
|
adfb3df283
|
|||
|
1525f44687
|
|||
|
3955d8626a
|
|||
|
6d63e53200
|
|||
|
cca0b2775c
|
|||
|
98c75c111f
|
|||
|
b2735e178f
|
|||
|
1c9fc230b1
|
|||
|
6c2b3964fe
|
|||
|
19ce41aca7
|
|||
|
763bb35a45
|
|||
|
6130843aa7
|
|||
|
667c3eba13
|
|||
|
e22cc0b243
|
|||
|
202c845bee
|
|||
|
d839416fdd
|
|||
|
821f4e526f
|
|||
|
9d2819cac4
|
|||
|
fd46f35023
|
|||
|
6943e3c9b7
|
|||
|
a90131c8be
|
|||
|
a04d057bce
|
@@ -1,19 +1,17 @@
|
|||||||
name: "Build"
|
name: Go
|
||||||
on:
|
on: [push]
|
||||||
push:
|
|
||||||
env:
|
|
||||||
HOME: /tmp
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install dependencies for Nix setup action
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
enable_kvm: true
|
go-version: '1.24.x'
|
||||||
extra_nix_config: "system-features = nixos-test benchmark big-parallel kvm"
|
- name: Install dependencies
|
||||||
run: |
|
run: go get .
|
||||||
apt update -y
|
- name: Build
|
||||||
apt install sudo -y
|
run: go build -v ./...
|
||||||
- uses: cachix/install-nix-action@v31
|
|
||||||
- run: nix build .#
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -15,6 +13,7 @@ import (
|
|||||||
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
//"git.dynamicdiscord.de/kalipso/zineshop/services"
|
//"git.dynamicdiscord.de/kalipso/zineshop/services"
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CartItemController interface {
|
type CartItemController interface {
|
||||||
@@ -53,15 +52,6 @@ func getSetCookieValue(c *gin.Context, cookieName string) string {
|
|||||||
return "" // Return empty string if cookie is not found
|
return "" // Return empty string if cookie is not found
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSessionId(length int) string {
|
|
||||||
bytes := make([]byte, length) // 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 {
|
func GetSessionId(ctx *gin.Context) string {
|
||||||
sessionId, err := ctx.Cookie("session_id")
|
sessionId, err := ctx.Cookie("session_id")
|
||||||
|
|
||||||
@@ -73,17 +63,13 @@ func GetSessionId(ctx *gin.Context) string {
|
|||||||
return responseCookie
|
return responseCookie
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionId = generateSessionId(16)
|
sessionId = utils.GenerateSessionId(16)
|
||||||
ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true)
|
ctx.SetCookie("session_id", sessionId, 3600, "/", "", false, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sessionId
|
return sessionId
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateToken() string {
|
|
||||||
return generateSessionId(16)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) {
|
func (rc *cartItemController) NewCartItemFromForm(ctx *gin.Context) (models.CartItem, error) {
|
||||||
sessionId := GetSessionId(ctx)
|
sessionId := GetSessionId(ctx)
|
||||||
shopItemIdStr := ctx.PostForm("ShopItemId")
|
shopItemIdStr := ctx.PostForm("ShopItemId")
|
||||||
@@ -162,7 +148,7 @@ func (rc *cartItemController) NewAddressFromForm(ctx *gin.Context) (models.Addre
|
|||||||
func (rc *cartItemController) NewOrderFromForm(ctx *gin.Context) (models.Order, error) {
|
func (rc *cartItemController) NewOrderFromForm(ctx *gin.Context) (models.Order, error) {
|
||||||
sessionId := GetSessionId(ctx)
|
sessionId := GetSessionId(ctx)
|
||||||
status := models.OrderStatus("AwaitingConfirmation")
|
status := models.OrderStatus("AwaitingConfirmation")
|
||||||
token := GenerateToken()
|
token := utils.GenerateToken()
|
||||||
email := ctx.PostForm("email")
|
email := ctx.PostForm("email")
|
||||||
comment := ctx.PostForm("comment")
|
comment := ctx.PostForm("comment")
|
||||||
firstName := ctx.PostForm("firstName")
|
firstName := ctx.PostForm("firstName")
|
||||||
@@ -337,6 +323,27 @@ func (rc *cartItemController) EditItemHandler(c *gin.Context) {
|
|||||||
|
|
||||||
action := c.PostForm("action")
|
action := c.PostForm("action")
|
||||||
|
|
||||||
|
if action == "setAmount" {
|
||||||
|
amountStr := c.PostForm("amount")
|
||||||
|
amount, err := strconv.Atoi(amountStr)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if amount < 0 {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "amount cant be negative"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if amount > 500 {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": "amount cant be over 500"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cartItem.Quantity = amount
|
||||||
|
}
|
||||||
|
|
||||||
if action == "increase" {
|
if action == "increase" {
|
||||||
cartItem.Quantity += 1
|
cartItem.Quantity += 1
|
||||||
}
|
}
|
||||||
|
|||||||
350
controllers/configController.go
Normal file
350
controllers/configController.go
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
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)
|
||||||
|
|
||||||
|
InvoiceView(*gin.Context)
|
||||||
|
InvoiceHandler(*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) InvoiceView(c *gin.Context) {
|
||||||
|
invoices, err := repositories.Invoices.GetAllNewestFirst()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "invoiceview.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"invoices": invoices,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "invoiceview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "invoiceview.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *configController) InvoiceHandler(ctx *gin.Context) {
|
||||||
|
action := ctx.PostForm("action")
|
||||||
|
if action == "delete" {
|
||||||
|
repositories.Invoices.DeleteById(ctx.Param("id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.InvoiceView(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
@@ -63,7 +63,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 +85,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 +104,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) {
|
||||||
@@ -98,6 +113,7 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var printJobs []models.PrintJob
|
var printJobs []models.PrintJob
|
||||||
|
priceTotal := 0.0
|
||||||
for idx := range variantIds {
|
for idx := range variantIds {
|
||||||
variant, err := repositories.ShopItems.GetVariantById(variantIds[idx])
|
variant, err := repositories.ShopItems.GetVariantById(variantIds[idx])
|
||||||
|
|
||||||
@@ -113,9 +129,21 @@ 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
|
||||||
|
if variantCoverPages[idx] != "0" {
|
||||||
|
coverPageTmp, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
coverPage = &coverPageTmp
|
||||||
}
|
}
|
||||||
|
|
||||||
variantAmount, err := strconv.Atoi(variantAmounts[idx])
|
variantAmount, err := strconv.Atoi(variantAmounts[idx])
|
||||||
@@ -124,23 +152,56 @@ func (rc *printController) PrintHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
printJob, err := models.NewPrintJob(shopItem, variant, coverPage, uint(variantAmount))
|
fmt.Println("Printing Costs:")
|
||||||
|
|
||||||
|
printJob, err := models.NewPrintJob(shopItem, variant, paperType, coverPage, uint(variantAmount))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
printJob.CalculatePrintCosts()
|
||||||
|
priceTotal += printJob.PriceTotal
|
||||||
|
printJobs = append(printJobs, printJob)
|
||||||
|
}
|
||||||
|
|
||||||
|
invoice := models.Invoice{
|
||||||
|
PrintJobs: printJobs,
|
||||||
|
PricePerClick: 0.002604,
|
||||||
|
PartCosts: 0.0067,
|
||||||
|
PriceTotal: priceTotal,
|
||||||
|
}
|
||||||
|
invoice, err := repositories.Invoices.Create(invoice)
|
||||||
|
|
||||||
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}})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
printJobs = append(printJobs, printJob)
|
|
||||||
}
|
|
||||||
|
|
||||||
executeJobs := func() {
|
executeJobs := func() {
|
||||||
for _, printJob := range printJobs {
|
for _, printJob := range printJobs {
|
||||||
printJob.Execute()
|
err := printJob.Execute()
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
printJob.ShopItem.WasPrinted = true
|
||||||
|
_, err = repositories.ShopItems.Update(printJob.ShopItem)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go executeJobs()
|
go executeJobs()
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "index.html", nil)
|
fmt.Println(invoice)
|
||||||
|
data := CreateSessionData(c, gin.H{
|
||||||
|
"invoice": invoice,
|
||||||
|
})
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "printstarted.html", data)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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{}
|
||||||
@@ -68,6 +63,9 @@ func (rc *shopItemController) GetById(c *gin.Context) {
|
|||||||
ReplyOK(c, shopItem)
|
ReplyOK(c, shopItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this currently creates quite big preview images
|
||||||
|
// workaround is running the following command in the uploads folder:
|
||||||
|
// for file in *.png; do convert "$file" -resize 35% "$file"; done
|
||||||
func (rc *shopItemController) NewShopItemFromForm(ctx *gin.Context) (models.ShopItem, error) {
|
func (rc *shopItemController) NewShopItemFromForm(ctx *gin.Context) (models.ShopItem, error) {
|
||||||
defaultImagePath := "static/img/zine.jpg"
|
defaultImagePath := "static/img/zine.jpg"
|
||||||
name := ctx.PostForm("name")
|
name := ctx.PostForm("name")
|
||||||
@@ -106,6 +104,14 @@ func (rc *shopItemController) NewShopItemFromForm(ctx *gin.Context) (models.Shop
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error during pdftoppm: ", err.Error())
|
fmt.Println("Error during pdftoppm: ", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd2 := exec.Command("convert", dstImage, "-resize", "35%", dstImage)
|
||||||
|
_, err = cmd2.Output()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error during resizing preview image: ", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -155,6 +161,7 @@ func (rc *shopItemController) NewShopItemFromForm(ctx *gin.Context) (models.Shop
|
|||||||
Pdf: dstPdf,
|
Pdf: dstPdf,
|
||||||
Variants: variants,
|
Variants: variants,
|
||||||
PrintMode: printMode,
|
PrintMode: printMode,
|
||||||
|
WasPrinted: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Creating Shopitem: ", shopItem)
|
fmt.Println("Creating Shopitem: ", shopItem)
|
||||||
@@ -249,14 +256,16 @@ func (rc *shopItemController) ShopItemView(c *gin.Context) {
|
|||||||
shopItem, err := repositories.ShopItems.GetById(c.Param("id"))
|
shopItem, err := repositories.ShopItems.GetById(c.Param("id"))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "shopitem.html", gin.H{"data": gin.H{"error": err}})
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": "Item does not exist"}})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: get tags by item
|
//TODO: get tags by item
|
||||||
tags, err := repositories.Tags.GetAll()
|
tags, err := repositories.Tags.GetAll()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "shopitem.html", gin.H{"data": gin.H{"error": err}})
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"data": gin.H{"error": err}})
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
data := CreateSessionData(c, gin.H{
|
||||||
@@ -264,10 +273,6 @@ func (rc *shopItemController) ShopItemView(c *gin.Context) {
|
|||||||
"tags": tags,
|
"tags": tags,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
c.HTML(http.StatusBadRequest, "shopitem.html", data)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "shopitem.html", data)
|
c.HTML(http.StatusOK, "shopitem.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,6 +370,13 @@ func (rc *shopItemController) AddItemsHandler(c *gin.Context) {
|
|||||||
fmt.Println("Error during pdftoppm: ", err.Error())
|
fmt.Println("Error during pdftoppm: ", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd2 := exec.Command("convert", dstImage, "-resize", "35%", dstImage)
|
||||||
|
_, err = cmd2.Output()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error during resizing preview image: ", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
category, err := models.ParseCategory("Zine")
|
category, err := models.ParseCategory("Zine")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorHandler(err)
|
errorHandler(err)
|
||||||
@@ -389,6 +401,7 @@ func (rc *shopItemController) AddItemsHandler(c *gin.Context) {
|
|||||||
Pdf: dstPdf,
|
Pdf: dstPdf,
|
||||||
Variants: variants,
|
Variants: variants,
|
||||||
PrintMode: "CreateBooklet",
|
PrintMode: "CreateBooklet",
|
||||||
|
WasPrinted: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = repositories.ShopItems.Create(shopItem)
|
_, err = repositories.ShopItems.Create(shopItem)
|
||||||
@@ -414,23 +427,93 @@ func (rc *shopItemController) AddItemsHandler(c *gin.Context) {
|
|||||||
c.HTML(http.StatusOK, "batchupload.html", data)
|
c.HTML(http.StatusOK, "batchupload.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *shopItemController) EditItemView(c *gin.Context) {
|
func GetCheckedTags(item models.ShopItem) ([]models.CheckedTag, error) {
|
||||||
shopItem, err := repositories.ShopItems.GetById(c.Param("id"))
|
allTags, err := repositories.Tags.GetAll()
|
||||||
tags, err := repositories.Tags.GetAll()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "edititem.html", gin.H{"error": err})
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(shopItem)
|
var tags []models.CheckedTag
|
||||||
|
for _, tag := range allTags {
|
||||||
|
tmpTag := models.CheckedTag{
|
||||||
|
Tag: tag,
|
||||||
|
Checked: "",
|
||||||
|
}
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
for _, itemTag := range item.Tags {
|
||||||
|
if itemTag.Name == tmpTag.Name {
|
||||||
|
tmpTag.Checked = "checked"
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = append(tags, tmpTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *shopItemController) getEditTemplatData(shopItem models.ShopItem) (gin.H, error) {
|
||||||
|
tags, err := GetCheckedTags(shopItem)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return gin.H{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
priceBW := ""
|
||||||
|
priceColored := ""
|
||||||
|
for _, variant := range shopItem.Variants {
|
||||||
|
if variant.Name == "B/W" {
|
||||||
|
priceBW = fmt.Sprintf("%.2f", variant.Price)
|
||||||
|
}
|
||||||
|
|
||||||
|
if variant.Name == "Colored" {
|
||||||
|
priceColored = fmt.Sprintf("%.2f", variant.Price)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
templateData := gin.H{
|
||||||
"error": "",
|
"error": "",
|
||||||
"success": "",
|
"success": "",
|
||||||
"shopItem": shopItem,
|
"shopItem": shopItem,
|
||||||
"tags": tags,
|
"tags": tags,
|
||||||
})
|
"priceBW": priceBW,
|
||||||
|
"priceColored": priceColored,
|
||||||
|
}
|
||||||
|
|
||||||
|
id := fmt.Sprintf("%d", shopItem.ID)
|
||||||
|
nextShopItem, err := repositories.ShopItems.GetNextOfId(id)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
fmt.Println("Setting nextitem")
|
||||||
|
fmt.Println(nextShopItem)
|
||||||
|
templateData["nextShopItem"] = nextShopItem
|
||||||
|
}
|
||||||
|
|
||||||
|
previousShopItem, err := repositories.ShopItems.GetPreviousOfId(id)
|
||||||
|
if err == nil {
|
||||||
|
templateData["previousShopItem"] = previousShopItem
|
||||||
|
}
|
||||||
|
|
||||||
|
return templateData, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *shopItemController) EditItemView(c *gin.Context) {
|
||||||
|
id := c.Param("id")
|
||||||
|
shopItem, err := repositories.ShopItems.GetById(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
||||||
|
}
|
||||||
|
|
||||||
|
templateData, err := rc.getEditTemplatData(shopItem)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := CreateSessionData(c, templateData)
|
||||||
c.HTML(http.StatusOK, "edititem.html", data)
|
c.HTML(http.StatusOK, "edititem.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,35 +539,38 @@ func (rc *shopItemController) EditItemHandler(c *gin.Context) {
|
|||||||
newShopItem.Variants = shopItem.Variants
|
newShopItem.Variants = shopItem.Variants
|
||||||
newShopItem.BasePrice = shopItem.BasePrice
|
newShopItem.BasePrice = shopItem.BasePrice
|
||||||
newShopItem.IsPublic = shopItem.IsPublic
|
newShopItem.IsPublic = shopItem.IsPublic
|
||||||
|
newShopItem.WasPrinted = false
|
||||||
|
|
||||||
|
if len(shopItem.Tags) != 0 {
|
||||||
newShopItem.Tags = shopItem.Tags
|
newShopItem.Tags = shopItem.Tags
|
||||||
|
}
|
||||||
|
|
||||||
|
if shopItem.Image != "static/img/zine.jpg" {
|
||||||
newShopItem.Image = shopItem.Image
|
newShopItem.Image = shopItem.Image
|
||||||
|
}
|
||||||
|
|
||||||
|
if shopItem.Pdf != "" {
|
||||||
newShopItem.Pdf = shopItem.Pdf
|
newShopItem.Pdf = shopItem.Pdf
|
||||||
|
}
|
||||||
|
|
||||||
newShopItem.PrintMode = shopItem.PrintMode
|
newShopItem.PrintMode = shopItem.PrintMode
|
||||||
|
|
||||||
tags, err := repositories.Tags.GetAll()
|
templateData, err := rc.getEditTemplatData(newShopItem)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.HTML(http.StatusBadRequest, "edititem.html", gin.H{"error": err})
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = repositories.ShopItems.Update(newShopItem)
|
_, err = repositories.ShopItems.Update(newShopItem)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
data := CreateSessionData(c, gin.H{
|
templateData["error"] = err
|
||||||
"error": err,
|
data := CreateSessionData(c, templateData)
|
||||||
"success": "",
|
|
||||||
"tags": tags,
|
|
||||||
})
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "edititem.html", data)
|
c.HTML(http.StatusOK, "edititem.html", data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
templateData["success"] = fmt.Sprintf("Item '%s' Updated", newShopItem.Name)
|
||||||
"error": "",
|
data := CreateSessionData(c, templateData)
|
||||||
"success": fmt.Sprintf("Item '%s' Updated", newShopItem.Name),
|
|
||||||
"tags": tags,
|
|
||||||
})
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "edititem.html", data)
|
c.HTML(http.StatusOK, "edititem.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,113 +619,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")
|
|
||||||
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, 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()})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
||||||
@@ -36,7 +37,7 @@ func (uc *UserController) Register(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = services.Users.Register(body.Name, body.Email, body.Password)
|
_, err = services.Users.Register(body.Name, body.Email, body.Password, false)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Error: ", err)
|
fmt.Println("Error: ", err)
|
||||||
@@ -140,10 +141,12 @@ func (rc *UserController) LoginHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateSessionData(c *gin.Context, extra any) gin.H {
|
func CreateSessionData(c *gin.Context, extra any) gin.H {
|
||||||
_, exists := c.Get("user")
|
user, exists := c.Get("user")
|
||||||
|
userImpl, _ := user.(models.User)
|
||||||
|
|
||||||
return gin.H{
|
return gin.H{
|
||||||
"loggedIn": exists,
|
"loggedIn": exists,
|
||||||
|
"isAdmin": userImpl.IsAdmin,
|
||||||
"data": extra,
|
"data": extra,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,18 +156,78 @@ func (rc *UserController) RegisterHandler(c *gin.Context) {
|
|||||||
email := c.PostForm("email")
|
email := c.PostForm("email")
|
||||||
password := c.PostForm("password")
|
password := c.PostForm("password")
|
||||||
|
|
||||||
_, err := services.Users.Register(name, email, password)
|
//first registered user is admin
|
||||||
|
isEmpty, _ := repositories.Users.IsEmpty()
|
||||||
|
if isEmpty {
|
||||||
|
_, err := services.Users.Register(name, email, password, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
data := gin.H{
|
data := gin.H{
|
||||||
"error": "Registering Failed.",
|
"error": "Registering Failed.",
|
||||||
"success": "",
|
"success": "",
|
||||||
}
|
}
|
||||||
|
c.HTML(http.StatusOK, "register.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data := gin.H{
|
||||||
|
"error": "",
|
||||||
|
"success": "You successfully registered as Admin. Try logging in.",
|
||||||
|
}
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "register.html", data)
|
c.HTML(http.StatusOK, "register.html", data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//for any other user token is required
|
||||||
|
token := c.PostForm("token")
|
||||||
|
|
||||||
|
if token == "" {
|
||||||
|
data := gin.H{
|
||||||
|
"error": "No token. No register.",
|
||||||
|
"success": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "register.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenExists, err := repositories.Tokens.Exists(token)
|
||||||
|
|
||||||
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
data := gin.H{
|
||||||
|
"error": err,
|
||||||
|
"success": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "register.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tokenExists {
|
||||||
|
data := gin.H{
|
||||||
|
"error": "Invalid Token.",
|
||||||
|
"success": "",
|
||||||
|
}
|
||||||
|
c.HTML(http.StatusOK, "register.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = services.Users.Register(name, email, password, false)
|
||||||
|
if err != nil {
|
||||||
|
data := gin.H{
|
||||||
|
"error": "Registering Failed.",
|
||||||
|
"success": "",
|
||||||
|
}
|
||||||
|
c.HTML(http.StatusOK, "register.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repositories.Tokens.Delete(token)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Could not delete RegisterToken: ", err)
|
||||||
|
}
|
||||||
|
|
||||||
data := gin.H{
|
data := gin.H{
|
||||||
"error": "",
|
"error": "",
|
||||||
"success": "You successfully registered. Try logging in.",
|
"success": "You successfully registered. Try logging in.",
|
||||||
@@ -174,6 +237,39 @@ func (rc *UserController) RegisterHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (rc *UserController) RegisterView(c *gin.Context) {
|
func (rc *UserController) RegisterView(c *gin.Context) {
|
||||||
|
data := gin.H{
|
||||||
|
"error": "",
|
||||||
|
"success": "",
|
||||||
|
"token": c.Param("token"),
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "registertoken.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *UserController) InitAdmin(c *gin.Context) {
|
||||||
|
isEmpty, err := repositories.Users.IsEmpty()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
data := gin.H{
|
||||||
|
"error": err,
|
||||||
|
"success": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusInternalServerError, "error.html", data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isEmpty {
|
||||||
|
data := gin.H{
|
||||||
|
"error": "Registration is closed",
|
||||||
|
"success": "",
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusInternalServerError, "error.html", data)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
data := gin.H{
|
data := gin.H{
|
||||||
"error": "",
|
"error": "",
|
||||||
"success": "",
|
"success": "",
|
||||||
@@ -204,80 +300,71 @@ func (rc *UserController) ResetHandler(c *gin.Context) {
|
|||||||
c.HTML(http.StatusOK, "passwordreset.html", data)
|
c.HTML(http.StatusOK, "passwordreset.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rc *UserController) InviteView(c *gin.Context) {
|
||||||
|
tokens, _ := repositories.Tokens.GetAll()
|
||||||
|
fmt.Println(tokens)
|
||||||
|
|
||||||
|
data := gin.H{
|
||||||
|
"tokens": tokens,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.HTML(http.StatusOK, "invites.html", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *UserController) InviteHandler(c *gin.Context) {
|
||||||
|
action := c.PostForm("action")
|
||||||
|
|
||||||
|
if action == "create" {
|
||||||
|
_, err := repositories.Tokens.Create()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
c.HTML(http.StatusBadRequest, "error.html", gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if action == "delete" {
|
||||||
|
token := c.PostForm("token")
|
||||||
|
repositories.Tokens.Delete(token)
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.InviteView(c)
|
||||||
|
}
|
||||||
|
|
||||||
func (rc *UserController) MainView(c *gin.Context) {
|
func (rc *UserController) MainView(c *gin.Context) {
|
||||||
shopItems, _ := repositories.ShopItems.GetAll()
|
itemOrder := c.Query("order")
|
||||||
fmt.Println(len(shopItems))
|
|
||||||
|
var shopItems []models.ShopItem
|
||||||
|
if itemOrder == "newestFirst" {
|
||||||
|
shopItems, _ = repositories.ShopItems.GetAllNewestFirst()
|
||||||
|
} else if itemOrder == "oldestFirst" {
|
||||||
|
shopItems, _ = repositories.ShopItems.GetAllNewestLast()
|
||||||
|
} else if itemOrder == "az" {
|
||||||
|
shopItems, _ = repositories.ShopItems.GetAllLexicalFirst()
|
||||||
|
} else if itemOrder == "za" {
|
||||||
|
shopItems, _ = repositories.ShopItems.GetAllLexicalLast()
|
||||||
|
} else {
|
||||||
|
shopItems, _ = repositories.ShopItems.GetAllNewestFirst()
|
||||||
|
}
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
data := CreateSessionData(c, gin.H{
|
||||||
"title": "shopItem Page",
|
"title": "shopItem Page",
|
||||||
"shopItems": shopItems,
|
"shopItems": shopItems,
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println(data)
|
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "index.html", data)
|
c.HTML(http.StatusOK, "index.html", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
type booking struct {
|
func (rc *UserController) TagView(c *gin.Context) {
|
||||||
Booked bool
|
shopItems, _ := repositories.ShopItems.GetByTagId(c.Param("id"))
|
||||||
}
|
|
||||||
|
|
||||||
type calendarbooking struct {
|
|
||||||
Time string
|
|
||||||
Bookings []booking
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rc *UserController) CalendarView(c *gin.Context) {
|
|
||||||
shopItems, _ := repositories.ShopItems.GetAll()
|
|
||||||
fmt.Println(len(shopItems))
|
|
||||||
|
|
||||||
generateBookings := func(amountShopItems int) []calendarbooking {
|
|
||||||
var result []calendarbooking
|
|
||||||
time := 6
|
|
||||||
for _ = range 18 {
|
|
||||||
book := calendarbooking{
|
|
||||||
Time: fmt.Sprintf("%d:00", time),
|
|
||||||
Bookings: []booking{},
|
|
||||||
}
|
|
||||||
for _ = range amountShopItems {
|
|
||||||
book.Bookings = append(book.Bookings, booking{Booked: rand.Float32() < 0.5})
|
|
||||||
}
|
|
||||||
|
|
||||||
time += 1
|
|
||||||
result = append(result, book)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
bookings := gin.H{
|
|
||||||
"head": []string{
|
|
||||||
"malobeo",
|
|
||||||
"hole of fame",
|
|
||||||
"BK",
|
|
||||||
"AZ Conni",
|
|
||||||
},
|
|
||||||
"bookings": generateBookings(4),
|
|
||||||
//"bookings": []calendarbooking{
|
|
||||||
// {
|
|
||||||
// Time: "10:00",
|
|
||||||
// Bookings: []booking{
|
|
||||||
// { Booked: true },
|
|
||||||
// { Booked: false },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
//},
|
|
||||||
}
|
|
||||||
|
|
||||||
data := CreateSessionData(c, gin.H{
|
data := CreateSessionData(c, gin.H{
|
||||||
"title": "shopItem Page",
|
"title": "shopItem Page",
|
||||||
"bookings": bookings,
|
"shopItems": shopItems,
|
||||||
"shopItemcount": len(bookings["head"].([]string)) + 1,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
fmt.Println(data)
|
c.HTML(http.StatusOK, "index.html", data)
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "calendar.html", data)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rc *UserController) Logout(c *gin.Context) {
|
func (rc *UserController) Logout(c *gin.Context) {
|
||||||
|
|||||||
6
flake.lock
generated
6
flake.lock
generated
@@ -2,11 +2,11 @@
|
|||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742669843,
|
"lastModified": 1744463964,
|
||||||
"narHash": "sha256-G5n+FOXLXcRx+3hCJ6Rt6ZQyF1zqQ0DL0sWAMn2Nk0w=",
|
"narHash": "sha256-LWqduOgLHCFxiTNYi3Uj5Lgz0SR+Xhw3kr/3Xd0GPTM=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "1e5b653dff12029333a6546c11e108ede13052eb",
|
"rev": "2631b0b7abcea6e640ce31cd78ea58910d31e650",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
go
|
go
|
||||||
gotools
|
gotools
|
||||||
poppler_utils #get first pdf page to png
|
poppler_utils #get first pdf page to png
|
||||||
|
cups
|
||||||
|
imagemagick
|
||||||
tailwindcss
|
tailwindcss
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -71,6 +73,8 @@
|
|||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
zineshop-pkg
|
zineshop-pkg
|
||||||
pkgs.poppler_utils #get first pdf page to png
|
pkgs.poppler_utils #get first pdf page to png
|
||||||
|
pkgs.cups
|
||||||
|
pkgs.imagemagick
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
@@ -100,7 +104,7 @@
|
|||||||
WorkingDirectory = "/var/lib/zineshop";
|
WorkingDirectory = "/var/lib/zineshop";
|
||||||
ExecStart = pkgs.writeScript "start-zineshop" ''
|
ExecStart = pkgs.writeScript "start-zineshop" ''
|
||||||
#! ${pkgs.bash}/bin/bash
|
#! ${pkgs.bash}/bin/bash
|
||||||
PATH="$PATH:${lib.makeBinPath [ pkgs.poppler_utils ]}"
|
PATH="$PATH:${lib.makeBinPath [ pkgs.poppler_utils pkgs.cups pkgs.imagemagick ]}"
|
||||||
${zineshop-pkg}/bin/zineshop
|
${zineshop-pkg}/bin/zineshop
|
||||||
'';
|
'';
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
|
|||||||
15
go.mod
15
go.mod
@@ -6,7 +6,8 @@ require (
|
|||||||
github.com/gin-gonic/gin v1.10.0
|
github.com/gin-gonic/gin v1.10.0
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
golang.org/x/crypto v0.23.0
|
github.com/pdfcpu/pdfcpu v0.11.0
|
||||||
|
golang.org/x/crypto v0.38.0
|
||||||
gorm.io/driver/sqlite v1.5.7
|
gorm.io/driver/sqlite v1.5.7
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
)
|
)
|
||||||
@@ -22,22 +23,30 @@ require (
|
|||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||||
github.com/goccy/go-json v0.10.2 // indirect
|
github.com/goccy/go-json v0.10.2 // indirect
|
||||||
|
github.com/hhrutter/lzw v1.0.0 // indirect
|
||||||
|
github.com/hhrutter/pkcs7 v0.2.0 // indirect
|
||||||
|
github.com/hhrutter/tiff v1.0.2 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
github.com/mattn/go-sqlite3 v1.14.22 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
|
golang.org/x/image v0.27.0 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
golang.org/x/sys v0.20.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
golang.org/x/text v0.15.0 // indirect
|
golang.org/x/text v0.25.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.1 // indirect
|
google.golang.org/protobuf v1.34.1 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
31
go.sum
31
go.sum
@@ -30,6 +30,12 @@ github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI
|
|||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
|
||||||
|
github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
|
||||||
|
github.com/hhrutter/pkcs7 v0.2.0 h1:i4HN2XMbGQpZRnKBLsUwO3dSckzgX142TNqY/KfXg+I=
|
||||||
|
github.com/hhrutter/pkcs7 v0.2.0/go.mod h1:aEzKz0+ZAlz7YaEMY47jDHL14hVWD6iXt0AgqgAvWgE=
|
||||||
|
github.com/hhrutter/tiff v1.0.2 h1:7H3FQQpKu/i5WaSChoD1nnJbGx4MxU5TlNqqpxw55z8=
|
||||||
|
github.com/hhrutter/tiff v1.0.2/go.mod h1:pcOeuK5loFUE7Y/WnzGw20YxUdnqjY1P0Jlcieb/cCw=
|
||||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
@@ -46,6 +52,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
|||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -53,10 +61,17 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
|||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/pdfcpu/pdfcpu v0.11.0 h1:mL18Y3hSHzSezmnrzA21TqlayBOXuAx7BUzzZyroLGM=
|
||||||
|
github.com/pdfcpu/pdfcpu v0.11.0/go.mod h1:F1ca4GIVFdPtmgvIdvXAycAm88noyNxZwzr9CpTy+Mw=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
@@ -76,22 +91,26 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ
|
|||||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
91
main.go
91
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{}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -55,65 +56,63 @@ func main() {
|
|||||||
server.Static("/static", os.Getenv("STATIC"))
|
server.Static("/static", os.Getenv("STATIC"))
|
||||||
server.LoadHTMLGlob(fmt.Sprintf("%s/*.html", os.Getenv("VIEWS")))
|
server.LoadHTMLGlob(fmt.Sprintf("%s/*.html", os.Getenv("VIEWS")))
|
||||||
|
|
||||||
apiRoutes := server.Group("/api")
|
|
||||||
//apiRoutes.Use(middlewares.BasicAuth())
|
|
||||||
{
|
|
||||||
apiRoutes.POST("/tags", authValidator.RequireAuth, shopItemController.CreateTag)
|
|
||||||
apiRoutes.GET("/tags", authValidator.OptionalAuth, shopItemController.GetAllTags)
|
|
||||||
apiRoutes.POST("/shopitems", authValidator.RequireAuth, shopItemController.Create)
|
|
||||||
apiRoutes.GET("/shopitems", authValidator.OptionalAuth, shopItemController.GetAll)
|
|
||||||
apiRoutes.GET("/shopitems/:id", authValidator.OptionalAuth, shopItemController.GetById)
|
|
||||||
apiRoutes.PUT("/shopitems/:id", authValidator.RequireAuth, shopItemController.Update)
|
|
||||||
apiRoutes.DELETE("/shopitems/:id", authValidator.RequireAuth, shopItemController.Delete)
|
|
||||||
|
|
||||||
//apiRoutes.GET("/rooms/:id/users", authValidator.RequireAuth, authValidator.RequireRoomAdmin, shopItemController.GetUsers)
|
|
||||||
//apiRoutes.POST("/rooms/:id/users", authValidator.RequireAuth, shopItemController.AddUser)
|
|
||||||
|
|
||||||
apiRoutes.POST("/users/register", userController.Register)
|
|
||||||
apiRoutes.POST("/users/login", userController.Login)
|
|
||||||
apiRoutes.GET("/users/validate", authValidator.OptionalAuth, userController.Validate)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewRoutes := server.Group("/", authValidator.OptionalAuth)
|
viewRoutes := server.Group("/", authValidator.OptionalAuth)
|
||||||
{
|
{
|
||||||
viewRoutes.GET("/", userController.MainView)
|
viewRoutes.GET("/", userController.MainView)
|
||||||
viewRoutes.GET("/shopitems/:id", shopItemController.ShopItemView)
|
viewRoutes.GET("/shopitems/:id", shopItemController.ShopItemView)
|
||||||
viewRoutes.GET("/shopitems/:id/edit", authValidator.RequireAuth, shopItemController.EditItemView)
|
viewRoutes.GET("/shopitems/:id/edit", authValidator.RequireAdmin, shopItemController.EditItemView)
|
||||||
viewRoutes.POST("/shopitems/:id/edit", authValidator.RequireAuth, shopItemController.EditItemHandler)
|
viewRoutes.POST("/shopitems/:id/edit", authValidator.RequireAdmin, shopItemController.EditItemHandler)
|
||||||
viewRoutes.GET("/shopitems/:id/delete", authValidator.RequireAuth, shopItemController.DeleteItemView)
|
viewRoutes.GET("/shopitems/:id/delete", authValidator.RequireAdmin, shopItemController.DeleteItemView)
|
||||||
viewRoutes.POST("/shopitems/:id/delete", authValidator.RequireAuth, shopItemController.DeleteItemHandler)
|
viewRoutes.POST("/shopitems/:id/delete", authValidator.RequireAdmin, shopItemController.DeleteItemHandler)
|
||||||
viewRoutes.GET("/variant/:id/print", authValidator.RequireAuth, printController.PrintVariantView)
|
viewRoutes.GET("/variant/:id/print", authValidator.RequireAdmin, printController.PrintVariantView)
|
||||||
viewRoutes.GET("/cart/print", authValidator.RequireAuth, printController.PrintCartView)
|
viewRoutes.GET("/cart/print", authValidator.RequireAdmin, printController.PrintCartView)
|
||||||
viewRoutes.POST("/print", authValidator.RequireAuth, printController.PrintHandler)
|
viewRoutes.POST("/print", authValidator.RequireAdmin, printController.PrintHandler)
|
||||||
|
|
||||||
viewRoutes.GET("/tags", authValidator.RequireAuth, shopItemController.TagView)
|
viewRoutes.GET("/config", authValidator.RequireAdmin, configController.ConfigView)
|
||||||
viewRoutes.POST("/tags/:id", authValidator.RequireAuth, shopItemController.TagHandler)
|
viewRoutes.POST("/config/:id", authValidator.RequireAdmin, configController.ConfigHandler)
|
||||||
viewRoutes.POST("/tags", authValidator.RequireAuth, shopItemController.AddTagHandler)
|
viewRoutes.POST("/config", authValidator.RequireAdmin, configController.AddConfigHandler)
|
||||||
viewRoutes.GET("/cart", cartItemController.CartItemView)
|
|
||||||
viewRoutes.POST("/cart", cartItemController.AddItemHandler)
|
viewRoutes.GET("/tags", authValidator.RequireAdmin, configController.TagView)
|
||||||
viewRoutes.POST("/cart/delete", cartItemController.DeleteItemHandler)
|
viewRoutes.POST("/tags/:id", authValidator.RequireAdmin, configController.TagHandler)
|
||||||
viewRoutes.POST("/cart/edit", cartItemController.EditItemHandler)
|
viewRoutes.GET("/tags/:id", userController.TagView)
|
||||||
viewRoutes.GET("/checkout", cartItemController.CheckoutView)
|
viewRoutes.POST("/tags", authValidator.RequireAdmin, configController.AddTagHandler)
|
||||||
viewRoutes.POST("/checkout", cartItemController.CheckoutHandler)
|
|
||||||
viewRoutes.POST("/order", cartItemController.OrderHandler)
|
viewRoutes.GET("/paper", authValidator.RequireAdmin, configController.PaperView)
|
||||||
viewRoutes.GET("/order/:token", cartItemController.OrderView)
|
viewRoutes.POST("/paper/:id", authValidator.RequireAdmin, configController.PaperHandler)
|
||||||
|
viewRoutes.GET("/paper/:id", userController.TagView)
|
||||||
|
viewRoutes.POST("/paper", authValidator.RequireAdmin, configController.AddPaperHandler)
|
||||||
|
|
||||||
|
viewRoutes.GET("/invoice", authValidator.RequireAdmin, configController.InvoiceView)
|
||||||
|
viewRoutes.POST("/invoice/:id", authValidator.RequireAdmin, configController.InvoiceHandler)
|
||||||
|
|
||||||
|
viewRoutes.GET("/cart", authValidator.RequireAuth, cartItemController.CartItemView)
|
||||||
|
viewRoutes.POST("/cart", authValidator.RequireAuth, cartItemController.AddItemHandler)
|
||||||
|
viewRoutes.POST("/cart/delete", authValidator.RequireAuth, cartItemController.DeleteItemHandler)
|
||||||
|
viewRoutes.POST("/cart/edit", authValidator.RequireAuth, cartItemController.EditItemHandler)
|
||||||
|
viewRoutes.GET("/checkout", authValidator.RequireAuth, cartItemController.CheckoutView)
|
||||||
|
viewRoutes.POST("/checkout", authValidator.RequireAuth, cartItemController.CheckoutHandler)
|
||||||
|
viewRoutes.POST("/order", authValidator.RequireAuth, cartItemController.OrderHandler)
|
||||||
|
viewRoutes.GET("/order/:token", authValidator.RequireAuth, cartItemController.OrderView)
|
||||||
viewRoutes.GET("/order/:token/print", authValidator.RequireAuth, printController.PrintOrderView)
|
viewRoutes.GET("/order/:token/print", authValidator.RequireAuth, printController.PrintOrderView)
|
||||||
|
|
||||||
viewRoutes.GET("/orders", authValidator.RequireAuth, cartItemController.OrdersView)
|
viewRoutes.GET("/orders", authValidator.RequireAdmin, cartItemController.OrdersView)
|
||||||
viewRoutes.POST("/order/:token/edit", authValidator.RequireAuth, cartItemController.OrdersHandler)
|
viewRoutes.POST("/order/:token/edit", authValidator.RequireAdmin, cartItemController.OrdersHandler)
|
||||||
|
|
||||||
//write middleware that redirects to homescreen on register/login/reset for logged in users
|
//write middleware that redirects to homescreen on register/login/reset for logged in users
|
||||||
viewRoutes.GET("/login", userController.LoginView)
|
viewRoutes.GET("/login", userController.LoginView)
|
||||||
viewRoutes.GET("/logout", userController.Logout)
|
viewRoutes.GET("/logout", userController.Logout)
|
||||||
viewRoutes.GET("/register", userController.RegisterView)
|
viewRoutes.GET("/register", userController.InitAdmin)
|
||||||
viewRoutes.GET("/passwordreset", userController.ResetView)
|
viewRoutes.GET("/register/:token", userController.RegisterView)
|
||||||
viewRoutes.GET("/additem", authValidator.RequireAuth, shopItemController.AddItemView)
|
viewRoutes.GET("/invites", authValidator.RequireAdmin, userController.InviteView)
|
||||||
viewRoutes.GET("/batchupload", authValidator.RequireAuth, shopItemController.AddItemsView)
|
viewRoutes.POST("/invites", authValidator.RequireAdmin, userController.InviteHandler)
|
||||||
|
viewRoutes.GET("/passwordreset", authValidator.RequireAuth, userController.ResetView)
|
||||||
|
viewRoutes.GET("/additem", authValidator.RequireAdmin, shopItemController.AddItemView)
|
||||||
|
viewRoutes.GET("/batchupload", authValidator.RequireAdmin, shopItemController.AddItemsView)
|
||||||
viewRoutes.POST("/login", userController.LoginHandler)
|
viewRoutes.POST("/login", userController.LoginHandler)
|
||||||
viewRoutes.POST("/register", userController.RegisterHandler)
|
viewRoutes.POST("/register", userController.RegisterHandler)
|
||||||
viewRoutes.POST("/additem", authValidator.RequireAuth, shopItemController.AddItemHandler)
|
viewRoutes.POST("/additem", authValidator.RequireAdmin, shopItemController.AddItemHandler)
|
||||||
viewRoutes.POST("/batchupload", authValidator.RequireAuth, shopItemController.AddItemsHandler)
|
viewRoutes.POST("/batchupload", authValidator.RequireAdmin, shopItemController.AddItemsHandler)
|
||||||
viewRoutes.POST("/passwordreset", userController.ResetHandler)
|
viewRoutes.POST("/passwordreset", authValidator.RequireAuth, userController.ResetHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Run(":" + os.Getenv("PORT"))
|
server.Run(":" + os.Getenv("PORT"))
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package middlewares
|
package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
//"strconv"
|
//"strconv"
|
||||||
"net/http"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
//"git.dynamicdiscord.de/kalipso/zineshop/models"
|
//"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
"git.dynamicdiscord.de/kalipso/zineshop/repositories"
|
||||||
@@ -98,6 +98,63 @@ func (av *AuthValidator) RequireAuth(c *gin.Context) {
|
|||||||
c.AbortWithStatus(http.StatusUnauthorized)
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (av *AuthValidator) RequireAdmin(c *gin.Context) {
|
||||||
|
// Get Cookie
|
||||||
|
tokenString, err := c.Cookie("Authorization")
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validate
|
||||||
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
// Don't forget to validate the alg is what you expect:
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
|
||||||
|
return []byte(os.Getenv("SECRET")), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := token.Claims.(jwt.MapClaims); ok {
|
||||||
|
//Check Expiration
|
||||||
|
if float64(time.Now().Unix()) > claims["exp"].(float64) {
|
||||||
|
//expired
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find user
|
||||||
|
user, err := repositories.Users.GetById(claims["sub"])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !user.IsAdmin {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Attach to req
|
||||||
|
c.Set("user", user)
|
||||||
|
|
||||||
|
// Coninue
|
||||||
|
c.Next()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
func (av *AuthValidator) OptionalAuth(c *gin.Context) {
|
func (av *AuthValidator) OptionalAuth(c *gin.Context) {
|
||||||
defer c.Next()
|
defer c.Next()
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"math"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -15,14 +18,39 @@ 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 -o Binding=TopBinding"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PrintJob struct {
|
type OldPrintJob struct {
|
||||||
Pdf string
|
Pdf string
|
||||||
Amount uint
|
Amount uint
|
||||||
Options []PrintOption
|
Options []PrintOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Invoice struct {
|
||||||
|
gorm.Model
|
||||||
|
PrintJobs []PrintJob
|
||||||
|
PricePerClick float64
|
||||||
|
PartCosts float64
|
||||||
|
PriceTotal float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrintJob struct {
|
||||||
|
gorm.Model
|
||||||
|
ShopItemID uint
|
||||||
|
ShopItem ShopItem
|
||||||
|
VariantID uint
|
||||||
|
Variant ItemVariant
|
||||||
|
PaperTypeId uint
|
||||||
|
PaperType Paper `gorm:"foreignKey:PaperTypeId"`
|
||||||
|
CoverPaperTypeId *uint
|
||||||
|
CoverPaperType *Paper `gorm:"foreignKey:CoverPaperTypeId"`
|
||||||
|
Amount uint
|
||||||
|
PricePerPiece float64
|
||||||
|
PriceTotal float64
|
||||||
|
InvoiceID uint
|
||||||
|
}
|
||||||
|
|
||||||
func GetPrintMode(mode string) PrintOption {
|
func GetPrintMode(mode string) PrintOption {
|
||||||
if mode == "LongEdge" {
|
if mode == "LongEdge" {
|
||||||
return LongEdge
|
return LongEdge
|
||||||
@@ -32,10 +60,14 @@ func GetPrintMode(mode string) PrintOption {
|
|||||||
return ShortEdge
|
return ShortEdge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mode == "TriFold" {
|
||||||
|
return TriFold
|
||||||
|
}
|
||||||
|
|
||||||
return CreateBooklet
|
return CreateBooklet
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrintJob(shopItem ShopItem, variant ItemVariant, coverPage bool, amount uint) (PrintJob, error) {
|
func NewPrintJob(shopItem ShopItem, variant ItemVariant, paperType Paper, coverPaperType *Paper, amount uint) (PrintJob, error) {
|
||||||
if shopItem.Pdf == "" {
|
if shopItem.Pdf == "" {
|
||||||
return PrintJob{}, fmt.Errorf("ShopItem has no PDF assigned")
|
return PrintJob{}, fmt.Errorf("ShopItem has no PDF assigned")
|
||||||
}
|
}
|
||||||
@@ -44,32 +76,44 @@ func NewPrintJob(shopItem ShopItem, variant ItemVariant, coverPage bool, amount
|
|||||||
return PrintJob{}, fmt.Errorf("Amount to big. This is denied for security reasons")
|
return PrintJob{}, fmt.Errorf("Amount to big. This is denied for security reasons")
|
||||||
}
|
}
|
||||||
|
|
||||||
var result PrintJob
|
result := PrintJob{
|
||||||
result.Pdf = shopItem.Pdf
|
ShopItem: shopItem,
|
||||||
result.Amount = amount
|
Variant: variant,
|
||||||
|
PaperType: paperType,
|
||||||
if variant.Name == "Colored" {
|
CoverPaperType: coverPaperType,
|
||||||
result.Options = append(result.Options, Colored)
|
Amount: amount,
|
||||||
}
|
}
|
||||||
|
|
||||||
if coverPage {
|
|
||||||
result.Options = append(result.Options, CoverPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
result.Options = append(result.Options, GetPrintMode(shopItem.PrintMode))
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PrintJob) IsColored() bool {
|
||||||
|
return p.Variant.Name == "Colored"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PrintJob) GeneratePrintOptions() []PrintOption {
|
||||||
|
var result []PrintOption
|
||||||
|
if p.Variant.Name == "Colored" {
|
||||||
|
result = append(result, Colored)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.CoverPaperType != nil {
|
||||||
|
result = append(result, CoverPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, GetPrintMode(p.ShopItem.PrintMode))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
func (p *PrintJob) Execute() error {
|
func (p *PrintJob) Execute() error {
|
||||||
baseCommand := "lp -d KONICA_MINOLTA_KONICA_MINOLTA_bizhub_C258/BookletPrint"
|
baseCommand := "lp -d KonicaBooklet"
|
||||||
baseCommand += fmt.Sprintf(" -n %v ", p.Amount)
|
baseCommand += fmt.Sprintf(" -n %v ", p.Amount)
|
||||||
|
|
||||||
for _, option := range p.Options {
|
for _, option := range p.GeneratePrintOptions() {
|
||||||
baseCommand += fmt.Sprintf(" %v ", option)
|
baseCommand += fmt.Sprintf(" %v ", option)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseCommand += fmt.Sprintf(" -- %s", p.Pdf)
|
baseCommand += fmt.Sprintf(" -- %s", p.ShopItem.Pdf)
|
||||||
|
|
||||||
parts := strings.Fields(baseCommand)
|
parts := strings.Fields(baseCommand)
|
||||||
|
|
||||||
@@ -86,3 +130,51 @@ func (p *PrintJob) Execute() error {
|
|||||||
fmt.Printf("Output:\n%s\n", output)
|
fmt.Printf("Output:\n%s\n", output)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PrintJob) CalculatePrintCosts() (float64, error) {
|
||||||
|
pageCount := utils.CountPagesAtPath(p.ShopItem.Pdf)
|
||||||
|
|
||||||
|
if pageCount == 0 {
|
||||||
|
fmt.Println("Pagecount of 0 - something is wrong here.")
|
||||||
|
return 0, fmt.Errorf("Cant calculate price, pdf seems to be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
printMode := GetPrintMode(p.ShopItem.PrintMode)
|
||||||
|
|
||||||
|
//Get actual pagecount depending on printmode
|
||||||
|
actualPageCount := pageCount
|
||||||
|
fmt.Println("PagCount: ", actualPageCount)
|
||||||
|
|
||||||
|
if printMode == CreateBooklet {
|
||||||
|
dividedCount := float64(pageCount) / 4.0
|
||||||
|
actualPageCount = int(math.Ceil(dividedCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
if printMode == LongEdge || printMode == ShortEdge {
|
||||||
|
dividedCount := float64(pageCount) / 2.0
|
||||||
|
actualPageCount = int(math.Ceil(dividedCount))
|
||||||
|
}
|
||||||
|
|
||||||
|
PPC := 0.002604
|
||||||
|
partCost := 0.0067
|
||||||
|
if p.IsColored() {
|
||||||
|
partCost = 0.0478
|
||||||
|
}
|
||||||
|
|
||||||
|
printingCosts := float64(actualPageCount-1) * p.PaperType.Price
|
||||||
|
|
||||||
|
if p.CoverPaperType != nil {
|
||||||
|
printingCosts += p.CoverPaperType.Price
|
||||||
|
} else {
|
||||||
|
printingCosts += p.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(p.Amount))
|
||||||
|
p.PricePerPiece = printingCosts
|
||||||
|
p.PriceTotal = printingCosts * float64(p.Amount)
|
||||||
|
return printingCosts, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type ItemVariant struct {
|
|||||||
type ShopItem struct {
|
type ShopItem struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
||||||
Abstract string `json:"Abstract" binding:"required"`
|
Abstract string `json:"abstract" binding:"required"`
|
||||||
Description string `json:"description" binding:"required"`
|
Description string `json:"description" binding:"required"`
|
||||||
Category Category `json:"category"`
|
Category Category `json:"category"`
|
||||||
Variants []ItemVariant `json:"variant"`
|
Variants []ItemVariant `json:"variant"`
|
||||||
@@ -53,4 +53,5 @@ type ShopItem struct {
|
|||||||
Image string
|
Image string
|
||||||
Pdf string
|
Pdf string
|
||||||
PrintMode string `json:"printMode" gorm:"default:CreateBooklet"`
|
PrintMode string `json:"printMode" gorm:"default:CreateBooklet"`
|
||||||
|
WasPrinted bool `gorm:"default:false"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,22 +2,56 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"gorm.io/gorm"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Name string `json:"name" binding:"required" gorm:"not null"`
|
Name string `json:"name" binding:"required" gorm:"not null"`
|
||||||
|
Color string `json:"color" binding:"required" gorm:"default:pink"`
|
||||||
ShopItems []ShopItem `gorm:"many2many:item_tags;"`
|
ShopItems []ShopItem `gorm:"many2many:item_tags;"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CheckedTag struct {
|
||||||
|
Tag
|
||||||
|
Checked string
|
||||||
|
}
|
||||||
|
|
||||||
func NewTag(ctx *gin.Context) (Tag, error) {
|
func NewTag(ctx *gin.Context) (Tag, error) {
|
||||||
|
colors := []string{
|
||||||
|
"red",
|
||||||
|
"orange",
|
||||||
|
"amber",
|
||||||
|
"yellow",
|
||||||
|
"lime",
|
||||||
|
"green",
|
||||||
|
"emerald",
|
||||||
|
"teal",
|
||||||
|
"cyan",
|
||||||
|
"sky",
|
||||||
|
"blue",
|
||||||
|
"indigo",
|
||||||
|
"violet",
|
||||||
|
"purple",
|
||||||
|
"fuchsia",
|
||||||
|
"pink",
|
||||||
|
"rose",
|
||||||
|
"slate",
|
||||||
|
"gray",
|
||||||
|
"zinc",
|
||||||
|
"neutral",
|
||||||
|
"stone",
|
||||||
|
}
|
||||||
|
n := rand.Int() % len(colors)
|
||||||
|
|
||||||
name := ctx.PostForm("name")
|
name := ctx.PostForm("name")
|
||||||
|
|
||||||
// Convert the price string to float64
|
// Convert the price string to float64
|
||||||
tag := Tag{
|
tag := Tag{
|
||||||
Name: name,
|
Name: name,
|
||||||
|
Color: colors[n],
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
@@ -27,7 +61,6 @@ func NewTag(ctx *gin.Context) (Tag, error) {
|
|||||||
return tag, nil
|
return tag, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func NewTagByJson(ctx *gin.Context) (Tag, error) {
|
func NewTagByJson(ctx *gin.Context) (Tag, error) {
|
||||||
var tag Tag
|
var tag Tag
|
||||||
err := ctx.ShouldBindJSON(&tag)
|
err := ctx.ShouldBindJSON(&tag)
|
||||||
|
|||||||
@@ -4,9 +4,15 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RegisterToken struct {
|
||||||
|
gorm.Model
|
||||||
|
Token string `json:"token" binding:"required" gorm:"unique;not null"`
|
||||||
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
Name string `json:"name" binding:"required" gorm:"unique;not null"`
|
||||||
Password string `json:"password" binding:"required" gorm:"not null"`
|
Password string `json:"password" binding:"required" gorm:"not null"`
|
||||||
Email string `json:"email" binding:"required,email" gorm:"unique;not null"`
|
Email string `json:"email" binding:"required,email" gorm:"unique;not null"`
|
||||||
|
IsAdmin bool `json:"isAdmin" gorm:"default:false;not null"`
|
||||||
}
|
}
|
||||||
|
|||||||
100
repositories/InvoiceRepository.go
Normal file
100
repositories/InvoiceRepository.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InvoiceRepository interface {
|
||||||
|
Create(models.Invoice) (models.Invoice, error)
|
||||||
|
GetAll() ([]models.Invoice, error)
|
||||||
|
GetAllSorted(string) ([]models.Invoice, error)
|
||||||
|
GetAllNewestFirst() ([]models.Invoice, error)
|
||||||
|
GetAllNewestLast() ([]models.Invoice, error)
|
||||||
|
GetById(string) (models.Invoice, error)
|
||||||
|
//GetByInvoiceId(string) (models.Invoice, error)
|
||||||
|
Update(models.Invoice) (models.Invoice, error)
|
||||||
|
DeleteById(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMInvoiceRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMInvoiceRepository(db *gorm.DB) InvoiceRepository {
|
||||||
|
return &GORMInvoiceRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) Create(invoice models.Invoice) (models.Invoice, error) {
|
||||||
|
result := t.DB.Create(&invoice)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Invoice{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) GetAll() ([]models.Invoice, error) {
|
||||||
|
var invoice []models.Invoice
|
||||||
|
result := t.DB.Preload("PrintJobs.ShopItem").Preload("PrintJobs.Variant").Preload("PrintJobs.PaperType").Preload("PrintJobs.CoverPaperType").Preload("PrintJobs").Find(&invoice)
|
||||||
|
|
||||||
|
return invoice, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) GetAllSorted(sortString string) ([]models.Invoice, error) {
|
||||||
|
var invoices []models.Invoice
|
||||||
|
result := t.DB.Preload("PrintJobs.ShopItem").Preload("PrintJobs.Variant").Preload("PrintJobs.PaperType").Preload("PrintJobs.CoverPaperType").Preload("PrintJobs").Order(sortString).Find(&invoices)
|
||||||
|
|
||||||
|
return invoices, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMInvoiceRepository) GetAllNewestFirst() ([]models.Invoice, error) {
|
||||||
|
return r.GetAllSorted("created_at desc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMInvoiceRepository) GetAllNewestLast() ([]models.Invoice, error) {
|
||||||
|
return r.GetAllSorted("created_at asc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) GetById(id string) (models.Invoice, error) {
|
||||||
|
invoiceId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return models.Invoice{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var invoice models.Invoice
|
||||||
|
result := t.DB.Preload("PrintJobs").First(&invoice, uint(invoiceId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Invoice{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) Update(invoice models.Invoice) (models.Invoice, error) {
|
||||||
|
result := t.DB.Save(&invoice)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.Invoice{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return invoice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMInvoiceRepository) DeleteById(id string) error {
|
||||||
|
invoiceId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := t.DB.Delete(&models.Invoice{}, invoiceId)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
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
|
||||||
|
}
|
||||||
82
repositories/printJobRepository.go
Normal file
82
repositories/printJobRepository.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PrintJobRepository interface {
|
||||||
|
Create(models.PrintJob) (models.PrintJob, error)
|
||||||
|
GetAll() ([]models.PrintJob, error)
|
||||||
|
GetById(string) (models.PrintJob, error)
|
||||||
|
//GetByShopItemId(string) (models.PrintJob, error)
|
||||||
|
Update(models.PrintJob) (models.PrintJob, error)
|
||||||
|
DeleteById(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMPrintJobRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMPrintJobRepository(db *gorm.DB) PrintJobRepository {
|
||||||
|
return &GORMPrintJobRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) Create(printJob models.PrintJob) (models.PrintJob, error) {
|
||||||
|
result := t.DB.Create(&printJob)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.PrintJob{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return printJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) GetAll() ([]models.PrintJob, error) {
|
||||||
|
var printJobs []models.PrintJob
|
||||||
|
result := t.DB.Preload("ShopItem").Preload("Variant").Preload("PaperType").Preload("CoverPaperType").Find(&printJobs)
|
||||||
|
|
||||||
|
return printJobs, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) GetById(id string) (models.PrintJob, error) {
|
||||||
|
printJobId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return models.PrintJob{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var printJob models.PrintJob
|
||||||
|
result := t.DB.Preload("ShopItem").Preload("Variant").Preload("PaperType").Preload("CoverPaperType").First(&printJob, uint(printJobId))
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.PrintJob{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return printJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) Update(printJob models.PrintJob) (models.PrintJob, error) {
|
||||||
|
result := t.DB.Save(&printJob)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.PrintJob{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return printJob, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMPrintJobRepository) DeleteById(id string) error {
|
||||||
|
printJobId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := t.DB.Delete(&models.PrintJob{}, printJobId)
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
86
repositories/registerTokenRepository.go
Normal file
86
repositories/registerTokenRepository.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
package repositories
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
|
"git.dynamicdiscord.de/kalipso/zineshop/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RegisterTokenRepository interface {
|
||||||
|
Create() (models.RegisterToken, error)
|
||||||
|
GetAll() ([]models.RegisterToken, error)
|
||||||
|
Exists(string) (bool, error)
|
||||||
|
Delete(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type GORMRegisterTokenRepository struct {
|
||||||
|
DB *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGORMRegisterTokenRepository(db *gorm.DB) RegisterTokenRepository {
|
||||||
|
return &GORMRegisterTokenRepository{
|
||||||
|
DB: db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMRegisterTokenRepository) Create() (models.RegisterToken, error) {
|
||||||
|
token := utils.GenerateToken()
|
||||||
|
|
||||||
|
exists, err := t.Exists(token)
|
||||||
|
if err != nil {
|
||||||
|
return models.RegisterToken{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if exists {
|
||||||
|
return t.Create()
|
||||||
|
}
|
||||||
|
|
||||||
|
newToken := models.RegisterToken{
|
||||||
|
Token: token,
|
||||||
|
}
|
||||||
|
result := t.DB.Create(&newToken)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.RegisterToken{}, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return newToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMRegisterTokenRepository) GetAll() ([]models.RegisterToken, error) {
|
||||||
|
var tokens []models.RegisterToken
|
||||||
|
result := t.DB.Find(&tokens)
|
||||||
|
|
||||||
|
return tokens, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMRegisterTokenRepository) Exists(tokenString string) (bool, error) {
|
||||||
|
var token models.RegisterToken
|
||||||
|
result := t.DB.First(&token, "token = ?", tokenString)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *GORMRegisterTokenRepository) Delete(token string) error {
|
||||||
|
result := t.DB.Where("token = ?", token).Delete(&models.RegisterToken{})
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
} else if result.RowsAffected == 0 {
|
||||||
|
return fmt.Errorf("Token not found, could not be deleted")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -14,6 +14,11 @@ var (
|
|||||||
Tags TagRepository
|
Tags TagRepository
|
||||||
CartItems CartItemRepository
|
CartItems CartItemRepository
|
||||||
Orders OrderRepository
|
Orders OrderRepository
|
||||||
|
Tokens RegisterTokenRepository
|
||||||
|
ConfigOptions ConfigRepository
|
||||||
|
Papers PaperRepository
|
||||||
|
PrintJobs PrintJobRepository
|
||||||
|
Invoices InvoiceRepository
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitRepositories() {
|
func InitRepositories() {
|
||||||
@@ -27,7 +32,12 @@ func InitRepositories() {
|
|||||||
&models.User{},
|
&models.User{},
|
||||||
&models.Tag{},
|
&models.Tag{},
|
||||||
&models.CartItem{},
|
&models.CartItem{},
|
||||||
&models.Order{})
|
&models.Order{},
|
||||||
|
&models.Config{},
|
||||||
|
&models.Paper{},
|
||||||
|
&models.PrintJob{},
|
||||||
|
&models.Invoice{},
|
||||||
|
&models.RegisterToken{})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("failed to migrate database")
|
panic("failed to migrate database")
|
||||||
@@ -38,4 +48,9 @@ func InitRepositories() {
|
|||||||
Tags = NewGORMTagRepository(db)
|
Tags = NewGORMTagRepository(db)
|
||||||
CartItems = NewGORMCartItemRepository(db)
|
CartItems = NewGORMCartItemRepository(db)
|
||||||
Orders = NewGORMOrderRepository(db)
|
Orders = NewGORMOrderRepository(db)
|
||||||
|
Tokens = NewGORMRegisterTokenRepository(db)
|
||||||
|
ConfigOptions = NewGORMConfigRepository(db)
|
||||||
|
Papers = NewGORMPaperRepository(db)
|
||||||
|
PrintJobs = NewGORMPrintJobRepository(db)
|
||||||
|
Invoices = NewGORMInvoiceRepository(db)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package repositories
|
package repositories
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"fmt"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
"git.dynamicdiscord.de/kalipso/zineshop/models"
|
||||||
)
|
)
|
||||||
@@ -10,10 +11,17 @@ import(
|
|||||||
type ShopItemRepository interface {
|
type ShopItemRepository interface {
|
||||||
Create(models.ShopItem) (models.ShopItem, error)
|
Create(models.ShopItem) (models.ShopItem, error)
|
||||||
GetAll() ([]models.ShopItem, error)
|
GetAll() ([]models.ShopItem, error)
|
||||||
|
GetAllSorted(string) ([]models.ShopItem, error)
|
||||||
|
GetAllNewestFirst() ([]models.ShopItem, error)
|
||||||
|
GetAllNewestLast() ([]models.ShopItem, error)
|
||||||
|
GetAllLexicalFirst() ([]models.ShopItem, error)
|
||||||
|
GetAllLexicalLast() ([]models.ShopItem, error)
|
||||||
GetAllPublic() ([]models.ShopItem, error)
|
GetAllPublic() ([]models.ShopItem, error)
|
||||||
GetById(string) (models.ShopItem, error)
|
GetById(string) (models.ShopItem, error)
|
||||||
|
GetNextOfId(string) (models.ShopItem, error)
|
||||||
|
GetPreviousOfId(string) (models.ShopItem, error)
|
||||||
|
GetByTagId(string) ([]models.ShopItem, error)
|
||||||
GetVariantById(string) (models.ItemVariant, error)
|
GetVariantById(string) (models.ItemVariant, error)
|
||||||
//GetByTagId(string) ([]models.ShopItem, error)
|
|
||||||
Update(models.ShopItem) (models.ShopItem, error)
|
Update(models.ShopItem) (models.ShopItem, error)
|
||||||
DeleteById(string) error
|
DeleteById(string) error
|
||||||
}
|
}
|
||||||
@@ -44,6 +52,29 @@ func (r *GORMShopItemRepository) GetAll() ([]models.ShopItem, error) {
|
|||||||
return shopItems, result.Error
|
return shopItems, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetAllSorted(sortString string) ([]models.ShopItem, error) {
|
||||||
|
var shopItems []models.ShopItem
|
||||||
|
result := r.DB.Preload("Tags").Preload("Variants").Order(sortString).Find(&shopItems)
|
||||||
|
|
||||||
|
return shopItems, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetAllNewestFirst() ([]models.ShopItem, error) {
|
||||||
|
return r.GetAllSorted("created_at desc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetAllNewestLast() ([]models.ShopItem, error) {
|
||||||
|
return r.GetAllSorted("created_at asc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetAllLexicalFirst() ([]models.ShopItem, error) {
|
||||||
|
return r.GetAllSorted("name asc")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetAllLexicalLast() ([]models.ShopItem, error) {
|
||||||
|
return r.GetAllSorted("name desc")
|
||||||
|
}
|
||||||
|
|
||||||
func (r *GORMShopItemRepository) GetAllPublic() ([]models.ShopItem, error) {
|
func (r *GORMShopItemRepository) GetAllPublic() ([]models.ShopItem, error) {
|
||||||
var shopItems []models.ShopItem
|
var shopItems []models.ShopItem
|
||||||
result := r.DB.Preload("Tags").Preload("Variants").Where("is_public = 1").Find(&shopItems)
|
result := r.DB.Preload("Tags").Preload("Variants").Where("is_public = 1").Find(&shopItems)
|
||||||
@@ -68,6 +99,47 @@ func (r *GORMShopItemRepository) GetById(id string) (models.ShopItem, error) {
|
|||||||
return shopItem, nil
|
return shopItem, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetNextOfId(id string) (models.ShopItem, error) {
|
||||||
|
var nextItem models.ShopItem
|
||||||
|
if err := r.DB.Where("id > ?", id).Order("id asc").First(&nextItem).Error; err != nil {
|
||||||
|
if err != gorm.ErrRecordNotFound {
|
||||||
|
return models.ShopItem{}, err
|
||||||
|
} else {
|
||||||
|
return models.ShopItem{}, fmt.Errorf("No Item found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nextItem, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetPreviousOfId(id string) (models.ShopItem, error) {
|
||||||
|
var previousItem models.ShopItem
|
||||||
|
if err := r.DB.Where("id < ?", id).Order("id desc").First(&previousItem).Error; err != nil {
|
||||||
|
if err != gorm.ErrRecordNotFound {
|
||||||
|
return models.ShopItem{}, err
|
||||||
|
} else {
|
||||||
|
return models.ShopItem{}, fmt.Errorf("No Item found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return previousItem, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *GORMShopItemRepository) GetByTagId(id string) ([]models.ShopItem, error) {
|
||||||
|
tagId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var shopItems []models.ShopItem
|
||||||
|
result := r.DB.Joins("JOIN item_tags ON item_tags.shop_item_id = shop_items.id").Where("item_tags.tag_id = ?", tagId).Preload("Tags").Preload("Variants").Find(&shopItems)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
return nil, result.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return shopItems, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *GORMShopItemRepository) GetVariantById(id string) (models.ItemVariant, error) {
|
func (r *GORMShopItemRepository) GetVariantById(id string) (models.ItemVariant, error) {
|
||||||
itemVariantId, err := strconv.Atoi(id)
|
itemVariantId, err := strconv.Atoi(id)
|
||||||
|
|
||||||
@@ -85,7 +157,6 @@ func (r *GORMShopItemRepository) GetVariantById(id string) (models.ItemVariant,
|
|||||||
return itemVariant, nil
|
return itemVariant, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (r *GORMShopItemRepository) Update(shopItem models.ShopItem) (models.ShopItem, error) {
|
func (r *GORMShopItemRepository) Update(shopItem models.ShopItem) (models.ShopItem, error) {
|
||||||
err := r.DB.Model(&shopItem).Association("Tags").Replace(shopItem.Tags)
|
err := r.DB.Model(&shopItem).Association("Tags").Replace(shopItem.Tags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type UserRepository interface {
|
|||||||
Create(models.User) (models.User, error)
|
Create(models.User) (models.User, error)
|
||||||
GetByEmail(string) (models.User, error)
|
GetByEmail(string) (models.User, error)
|
||||||
GetById(interface{}) (models.User, error)
|
GetById(interface{}) (models.User, error)
|
||||||
|
IsEmpty() (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type GORMUserRepository struct {
|
type GORMUserRepository struct {
|
||||||
@@ -53,3 +54,18 @@ func (u *GORMUserRepository) GetById(id interface{}) (models.User, error) {
|
|||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *GORMUserRepository) IsEmpty() (bool, error) {
|
||||||
|
var user models.User
|
||||||
|
result := u.DB.First(&user)
|
||||||
|
|
||||||
|
if result.Error != nil {
|
||||||
|
if result.Error == gorm.ErrRecordNotFound {
|
||||||
|
return true, nil
|
||||||
|
} else {
|
||||||
|
return false, result.Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package services
|
package services
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ var(
|
|||||||
|
|
||||||
type UserService struct{}
|
type UserService struct{}
|
||||||
|
|
||||||
func (u *UserService) Register(name string, email string, password string) (models.User, error) {
|
func (u *UserService) Register(name string, email string, password string, isAdmin bool) (models.User, error) {
|
||||||
//hash pw
|
//hash pw
|
||||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ func (u *UserService) Register(name string, email string, password string) (mode
|
|||||||
return models.User{}, err
|
return models.User{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user := models.User{Name: name, Email: email, Password: string(hash)}
|
user := models.User{Name: name, Email: email, Password: string(hash), IsAdmin: isAdmin}
|
||||||
_, err = repositories.Users.Create(user)
|
_, err = repositories.Users.Create(user)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
BIN
static/img/logo-black.png
Normal file
BIN
static/img/logo-black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
BIN
static/img/logo-white.png
Normal file
BIN
static/img/logo-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
File diff suppressed because it is too large
Load Diff
32
utils/utils.go
Normal file
32
utils/utils.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"github.com/pdfcpu/pdfcpu/pkg/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GenerateSessionId(length int) string {
|
||||||
|
bytes := make([]byte, length) // 16 bytes = 128 bits
|
||||||
|
_, err := rand.Read(bytes)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to generate session ID")
|
||||||
|
}
|
||||||
|
return hex.EncodeToString(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateToken() string {
|
||||||
|
return GenerateSessionId(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
func CountPagesAtPath(path string) (pages int) {
|
||||||
|
ctx, err := api.ReadContextFile(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error reading PDF:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pages = ctx.PageCount
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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">
|
<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">Add an Item</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Add an Item</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -131,6 +131,7 @@
|
|||||||
<option selected value="CreateBooklet">Create Booklet</option>
|
<option selected value="CreateBooklet">Create Booklet</option>
|
||||||
<option value="LongEdge">Long Edge</option>
|
<option value="LongEdge">Long Edge</option>
|
||||||
<option value="ShortEdge">Short Edge</option>
|
<option value="ShortEdge">Short Edge</option>
|
||||||
|
<option value="TriFold">Tri-Fold (Flyer)</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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">
|
<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">Add Tag</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Add Tag</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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">
|
<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">Batch Upload</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Batch Upload</h2>
|
||||||
Select multiple files on the upload. For each a new Shop Item will be created with the Filename as Name, Abstract
|
Select multiple files on the upload. For each a new Shop Item will be created with the Filename as Name, Abstract
|
||||||
and Description.<br>
|
and Description.<br>
|
||||||
|
|||||||
@@ -33,26 +33,12 @@
|
|||||||
</p>
|
</p>
|
||||||
<form action="/cart/edit" method="POST">
|
<form action="/cart/edit" method="POST">
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<div class="flex items-center gap-4">
|
|
||||||
<input type="hidden" id="{{ .ID }}" name="id" value="{{ .ID }}">
|
<input type="hidden" id="{{ .ID }}" name="id" value="{{ .ID }}">
|
||||||
<button type="submit" name="action" value="decrease"
|
<div class="flex items-center gap-4">
|
||||||
class="group rounded-[50px] border border-gray-200 shadow-sm shadow-transparent p-2.5 flex items-center justify-center bg-white transition-all duration-500 hover:shadow-gray-200 hover:bg-gray-50 hover:border-gray-300 focus-within:outline-gray-300">
|
<input type="number" name="amount" value="{{ .Quantity }}" step="1" min="0" 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">
|
||||||
<svg class="stroke-gray-900 transition-all duration-500 group-hover:stroke-black"
|
<button type="submit" name="action" value="setAmount"
|
||||||
width="18" height="19" viewBox="0 0 18 19" fill="none"
|
class="block w-full bg-indigo-500 rounded-md px-3 py-1.5 text-base text-white placeholder:text-gray-400 sm:text-sm/6 duration-500 hover:bg-indigo-700">
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
Set Amount
|
||||||
<path d="M4.5 9.5H13.5" stroke="" stroke-width="1.6" stroke-linecap="round"
|
|
||||||
stroke-linejoin="round" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<p class="border border-gray-200 text-center rounded-full w-10 text-gray-900 font-semibold text-sm py-1.5 px-3 bg-gray-100 text-center">{{ .Quantity }}</p>
|
|
||||||
<button type="submit" name="action" value="increase"
|
|
||||||
class="group rounded-[50px] border border-gray-200 shadow-sm shadow-transparent p-2.5 flex items-center justify-center bg-white transition-all duration-500 hover:shadow-gray-200 hover:bg-gray-50 hover:border-gray-300 focus-within:outline-gray-300">
|
|
||||||
<svg class="stroke-gray-900 transition-all duration-500 group-hover:stroke-black"
|
|
||||||
width="18" height="19" viewBox="0 0 18 19" fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M3.75 9.5H14.25M9 14.75V4.25" stroke="" stroke-width="1.6"
|
|
||||||
stroke-linecap="round" stroke-linejoin="round" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<h6 class="text-indigo-600 font-manrope font-bold text-2xl leading-9 text-right">{{ .Quantity}} x {{ .ItemVariant.Price }}€</h6>
|
<h6 class="text-indigo-600 font-manrope font-bold text-2xl leading-9 text-right">{{ .Quantity}} x {{ .ItemVariant.Price }}€</h6>
|
||||||
@@ -88,7 +74,7 @@
|
|||||||
<div class="max-lg:max-w-lg max-lg:mx-auto">
|
<div class="max-lg:max-w-lg max-lg:mx-auto">
|
||||||
<p class="font-normal text-base leading-7 text-gray-500 text-center mb-5 mt-6">Shipping calculated at checkout</p>
|
<p class="font-normal text-base leading-7 text-gray-500 text-center mb-5 mt-6">Shipping calculated at checkout</p>
|
||||||
<button type="submit"
|
<button type="submit"
|
||||||
class="rounded-full py-4 px-6 bg-indigo-600 text-white font-semibold text-lg w-full text-center transition-all duration-500 hover:bg-indigo-700 ">Checkout</button>
|
class="rounded py-4 px-6 bg-indigo-500 text-white font-semibold text-lg w-full text-center transition-all duration-500 hover:bg-indigo-700 ">Checkout</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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="Logo">
|
<img class="mx-auto h-10 w-auto" src="/static/img/logo-black.png" alt="Logo">
|
||||||
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Checkout</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Checkout</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
23
views/colors.html
Normal file
23
views/colors.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<span class="bg-red-100 text-red-800 bg-red-900 text-red-300">FOO</span>
|
||||||
|
<span class="bg-orange-100 text-orange-800 bg-orange-900 text-orange-300">FOO</span>
|
||||||
|
<span class="bg-amber-100 text-amber-800 bg-amber-900 text-amber-300">FOO</span>
|
||||||
|
<span class="bg-yellow-100 text-yellow-800 bg-yellow-900 text-yellow-300">FOO</span>
|
||||||
|
<span class="bg-lime-100 text-lime-800 bg-lime-900 text-lime-300">FOO</span>
|
||||||
|
<span class="bg-green-100 text-green-800 bg-green-900 text-green-300">FOO</span>
|
||||||
|
<span class="bg-emerald-100 text-emerald-800 bg-emerald-900 text-emerald-300">FOO</span>
|
||||||
|
<span class="bg-teal-100 text-teal-800 bg-teal-900 text-teal-300">FOO</span>
|
||||||
|
<span class="bg-cyan-100 text-cyan-800 bg-cyan-900 text-cyan-300">FOO</span>
|
||||||
|
<span class="bg-sky-100 text-sky-800 bg-sky-900 text-sky-300">FOO</span>
|
||||||
|
<span class="bg-blue-100 text-blue-800 bg-blue-900 text-blue-300">FOO</span>
|
||||||
|
<span class="bg-indigo-100 text-indigo-800 bg-indigo-900 text-indigo-300">FOO</span>
|
||||||
|
<span class="bg-violet-100 text-violet-800 bg-violet-900 text-violet-300">FOO</span>
|
||||||
|
<span class="bg-purple-100 text-purple-800 bg-purple-900 text-purple-300">FOO</span>
|
||||||
|
<span class="bg-fuchsia-100 text-fuchsia-800 bg-fuchsia-900 text-fuchsia-300">FOO</span>
|
||||||
|
<span class="bg-pink-100 text-pink-800 bg-pink-900 text-pink-300">FOO</span>
|
||||||
|
<span class="bg-rose-100 text-rose-800 bg-rose-900 text-rose-300">FOO</span>
|
||||||
|
<span class="bg-slate-100 text-slate-800 bg-slate-900 text-slate-300">FOO</span>
|
||||||
|
<span class="bg-gray-100 text-gray-800 bg-gray-900 text-gray-300">FOO</span>
|
||||||
|
<span class="bg-zinc-100 text-zinc-800 bg-zinc-900 text-zinc-300">FOO</span>
|
||||||
|
<span class="bg-neutral-100 text-neutral-800 bg-neutral-900 text-neutral-300">FOO</span>
|
||||||
|
<span class="bg-stone-100 text-stone-800 bg-stone-900 text-stone-300">FOO</span>
|
||||||
|
|
||||||
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" . }}
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
<h3 class="text-lg">{{ .data.shopItem.Name }}</h3>
|
<h3 class="text-lg">{{ .data.shopItem.Name }}</h3>
|
||||||
<i class="text-xs">{{ .data.shopItem.Description }}</i>
|
<i class="text-xs">{{ .data.shopItem.Description }}</i>
|
||||||
<p class="">Price: {{ .data.shopItem.BasePrice }}</p>
|
<p class="">Price: {{ .data.shopItem.BasePrice }}</p>
|
||||||
{{ if .loggedIn }}
|
{{ if .isAdmin }}
|
||||||
|
|
||||||
<p class="mt-10 text-center text-sm/6 text-red-500">
|
<p class="mt-10 text-center text-sm/6 text-red-500">
|
||||||
Do you really want to delete this item??
|
Do you really want to delete this item??
|
||||||
|
|||||||
@@ -1,9 +1,46 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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">
|
<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 Item</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Edit Item</h2>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
|
<a href="/{{ .data.shopItem.Pdf }}" target="_blank">
|
||||||
|
<img src="/{{ .data.shopItem.Image }}" alt="Product Image" class="aspect-4/5 mx-auto rounded-md bg-gray-200 object-cover group-hover:opacity-75 lg:aspect-auto lg:h-80">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="grid grid-cols-6 gap-4 mb-4">
|
||||||
|
<div class="col-span-3">
|
||||||
|
{{ if .data.previousShopItem }}
|
||||||
|
<form action="/shopitems/{{ .data.previousShopItem.ID }}/edit">
|
||||||
|
<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">Previous</button>
|
||||||
|
</form>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
<div class="col-span-3">
|
||||||
|
{{ if .data.nextShopItem }}
|
||||||
|
<form action="/shopitems/{{ .data.nextShopItem.ID }}/edit">
|
||||||
|
<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">Next</button>
|
||||||
|
</form>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -28,12 +65,25 @@
|
|||||||
<textarea id="description" name="description" type="textarea" class="block w-full px-4 py-2 mt-2 text-gray-900 bg-white border border-gray-300 rounded-md dark:bg-gray-800 dark:text-gray-900 dark:border-gray-600 focus:border-blue-500 dark:focus:border-blue-500 focus:outline-none focus:ring">{{ .data.shopItem.Description}}</textarea>
|
<textarea id="description" name="description" type="textarea" class="block w-full px-4 py-2 mt-2 text-gray-900 bg-white border border-gray-300 rounded-md dark:bg-gray-800 dark:text-gray-900 dark:border-gray-600 focus:border-blue-500 dark:focus:border-blue-500 focus:outline-none focus:ring">{{ .data.shopItem.Description}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<label class="block text-sm/6 font-medium text-gray-900">
|
||||||
|
Print Mode
|
||||||
|
</label>
|
||||||
|
<select name="print-mode" required class="bg-white 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="{{ .data.shopItem.PrintMode }}">{{ .data.shopItem.PrintMode }}</option>
|
||||||
|
<option value="CreateBooklet">CreateBooklet</option>
|
||||||
|
<option value="LongEdge">Long Edge</option>
|
||||||
|
<option value="ShortEdge">Short Edge</option>
|
||||||
|
<option value="TriFold">Tri-Fold (Flyer)</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="block text-sm/6 text-gray-900">Select Categories</label>
|
<label class="block text-sm/6 text-gray-900">Select Categories</label>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
{{ range .data.tags }}
|
{{ range .data.tags }}
|
||||||
<label class="flex text-sm/6 items-center">
|
<label class="flex text-sm/6 items-center">
|
||||||
<input type="checkbox" class="form-checkbox h-4 w-4 text-gray-900" value="{{ .ID }}" name="tags[]">
|
<input type="checkbox" {{ .Checked }} class="form-checkbox h-4 w-4 text-gray-900" value="{{ .ID }}" name="tags[]">
|
||||||
<span class="ml-2 text-sm/6 text-gray-900">{{ .Name }}</span>
|
<span class="ml-2 text-sm/6 text-gray-900">{{ .Name }}</span>
|
||||||
</label>
|
</label>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
@@ -61,7 +111,7 @@
|
|||||||
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Price B/W</label>
|
<label for="variant-value1" class="block text-sm/6 font-medium text-gray-900">Price B/W</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<input type="number" name="variant-value[]" id="variant-value1" step="0.01" min="0.00" 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">
|
<input type="number" value="{{ .data.priceBW }}" name="variant-value[]" id="variant-value1" step="0.01" min="0.00" 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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -72,7 +122,7 @@
|
|||||||
<label for="variant-value2" class="block text-sm/6 font-medium text-gray-900">Price Colored</label>
|
<label for="variant-value2" class="block text-sm/6 font-medium text-gray-900">Price Colored</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<input type="number" name="variant-value[]" id="variant-value2" step="0.01" min="0.00" 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">
|
<input type="number" value="{{ .data.priceColored }}" name="variant-value[]" id="variant-value2" step="0.01" min="0.00" 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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -123,24 +173,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label class="block text-sm font-medium text-gray-900">
|
|
||||||
Print Mode
|
|
||||||
</label>
|
|
||||||
<select name="print-mode" 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="CreateBooklet">Create Booklet</option>
|
|
||||||
<option value="LongEdge">Long Edge</option>
|
|
||||||
<option value="ShortEdge">Short Edge</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
|
|
||||||
<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>
|
<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">Update Item</button>
|
<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">Update Item</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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">
|
<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 Orders</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Edit Orders</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Zine Shop</title>
|
<title>Zines</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link href="/static/output.css" rel="stylesheet">
|
<link href="/static/output.css" rel="stylesheet">
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
<div class="mx-auto max-w-7xl px-4 sm:px-8 lg:px-8">
|
<div class="mx-auto max-w-7xl px-4 sm:px-8 lg:px-8">
|
||||||
<div class="relative flex h-16 items-center justify-between">
|
<div class="relative flex h-16 items-center justify-between">
|
||||||
<div class="flex flex-1 items-center">
|
<div class="flex flex-1 items-center">
|
||||||
<a href="/"><div class="flex shrink-0">
|
<a href="/"><div class="flex-shrink-0 w-full h-full">
|
||||||
<img class="h-8 w-auto" src="/static/img/circlea.png" alt="Your Company">
|
<img class="h-8 w-auto" src="/static/img/logo-white.png" alt="Your Company">
|
||||||
</div></a>
|
</div></a>
|
||||||
<!--
|
<!--
|
||||||
{{ if .loggedIn }}
|
{{ if .loggedIn }}
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
-->
|
-->
|
||||||
</div>
|
</div>
|
||||||
{{ if .loggedIn }}
|
{{ if .isAdmin }}
|
||||||
<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">
|
<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="/additem" 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">Add Item</a>
|
<a href="/additem" 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">Add Item</a>
|
||||||
<a href="/batchupload" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300
|
<a href="/batchupload" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300
|
||||||
@@ -33,13 +33,21 @@
|
|||||||
<a href="/orders" class="rounded-md bg-gray-900 m-2 px-3 py-2 text-sm font-medium text-gray-300
|
<a href="/orders" 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">Orders</a>
|
hover:bg-gray-700 hover:text-white">Orders</a>
|
||||||
<a href="/tags" 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">Tags</a>
|
<a href="/tags" 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">Tags</a>
|
||||||
|
<a href="/invites" 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">Invites</a>
|
||||||
<a href="/cart/print" 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/print" 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">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="/invoice" 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">Invoices</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>
|
||||||
{{ else }}
|
{{ end }}
|
||||||
|
{{ if .loggedIn }}
|
||||||
<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">
|
<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="/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>
|
<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>
|
</div>
|
||||||
|
|||||||
28
views/invites.html
Normal file
28
views/invites.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{{ 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">Create/Delete Invites</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
{{ range .tokens }}
|
||||||
|
<form action="/invites" method="POST">
|
||||||
|
<div class="max-w-md mx-auto mt-4">
|
||||||
|
<div class="flex">
|
||||||
|
<input type="text" id="token" name="token" value="{{ .Token }}" readonly="readonly" class="flex-grow border border-gray-300 rounded-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
<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="/invites" method="POST">
|
||||||
|
<div class="max-w-md mx-auto mt-4">
|
||||||
|
<div class="flex">
|
||||||
|
<button type="submit" name="action" value="create" class="bg-green-600 text-white ml-4 mr-4 rounded px-4 hover:bg-green-700">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{ template "footer.html" . }}
|
||||||
55
views/invoice.html
Normal file
55
views/invoice.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
<div class="-m-1.5 overflow-x-auto">
|
||||||
|
<div class="p-1.5 min-w-full inline-block align-middle">
|
||||||
|
<div class="overflow-hidden">
|
||||||
|
<table class="min-w-full divide-y divide-gray-200 dark:divide-neutral-700">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase dark:text-neutral-500"></th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-start text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Name</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Paper</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Amount</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-end text-xs font-medium text-gray-500 uppercase dark:text-neutral-500">Price</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-200 dark:divide-neutral-700">
|
||||||
|
{{ range .PrintJobs }}
|
||||||
|
<tr>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-neutral-200">
|
||||||
|
<a href="/shopitems/{{ .Variant.ShopItemID }}" class="flex items-center aspect-square w-8 h-10 shrink-0">
|
||||||
|
<img class="h-auto w-full max-h-full dark:hidden" src="/{{ .ShopItem.Image }}" alt="imac image" />
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-800 dark:text-neutral-200">
|
||||||
|
<div class="text-sm break-normal">
|
||||||
|
<p>{{ .ShopItem.Name }}</p>
|
||||||
|
<p>{{ .Variant.Name }}</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-800 dark:text-neutral-200">
|
||||||
|
<div class="text-xs">
|
||||||
|
<p>{{ .PaperType.Brand }} - {{.PaperType.Name }}: {{ .PaperType.Size }} {{ .PaperType.Weight }}g</p>
|
||||||
|
{{ if .CoverPaperType }}
|
||||||
|
<p class="text-red-700">{{ .CoverPaperType.Brand }} - {{.CoverPaperType.Name }}: {{ .CoverPaperType.Size }} {{ .CoverPaperType.Weight }}g</p>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .Amount }}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200">{{ .PriceTotal }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-800 dark:text-neutral-200">
|
||||||
|
<b>TOTAL</b>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"></td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-800 dark:text-neutral-200"><b>{{ .PriceTotal }}</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
29
views/invoiceview.html
Normal file
29
views/invoiceview.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{{ 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">Invoices</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ range .data.invoices }}
|
||||||
|
<div class="w-full grid grid-cols-1 gap-4 mx-auto p-4 m-4 flex flex-wrap border rounded shadow-md max-w-4xl">
|
||||||
|
<div class="">
|
||||||
|
<div class="font-bold text-center mb-4">
|
||||||
|
Invoice #{{ .ID }} - {{ .CreatedAt }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{{ template "invoice.html" . }}
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 mt-4 flex flex-wrap gap-2 w-full">
|
||||||
|
<form action="/invoice/{{ .ID }}" method="POST">
|
||||||
|
<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>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ template "footer.html" . }}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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="Logo">
|
<img class="mx-auto h-10 w-auto" src="/static/img/logo-black.png" alt="Logo">
|
||||||
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Login to your account</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Login to your account</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -74,11 +74,6 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex items-start sm:items-center">
|
|
||||||
<input id="terms-checkbox-2" type="checkbox" value="" class="h-4 w-4 rounded border-gray-300 bg-gray-100 text-primary-600 focus:ring-2 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:ring-offset-gray-800 dark:focus:ring-primary-600" />
|
|
||||||
<label for="terms-checkbox-2" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300"> I agree with the <a href="#" title="" class="text-primary-700 underline hover:no-underline dark:text-primary-500">Terms and Conditions</a> of use of the Flowbite marketplace </label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="gap-4 sm:flex sm:items-center">
|
<div class="gap-4 sm:flex sm:items-center">
|
||||||
<button type="button" class="w-full rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"><a href="/">Return to Shopping</a></button>
|
<button type="button" class="w-full rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700"><a href="/">Return to Shopping</a></button>
|
||||||
|
|
||||||
|
|||||||
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" . }}
|
||||||
22
views/printstarted.html
Normal file
22
views/printstarted.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{{ template "header.html" . }}
|
||||||
|
|
||||||
|
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
|
||||||
|
<div class="mx-auto max-w-3xl">
|
||||||
|
<div class="mt-6 sm:mt-8">
|
||||||
|
<div class="relative overflow-x-auto border-b border-gray-200 dark:border-gray-800">
|
||||||
|
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Print Started
|
||||||
|
</h2>
|
||||||
|
<div class="w-full grid grid-cols-1 gap-4 mx-auto p-4 m-4 flex flex-wrap border rounded shadow-md">
|
||||||
|
<div class="flex flex-col">
|
||||||
|
{{ template "invoice.html" .data.invoice }}
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 mt-4 flex flex-wrap gap-2 w-full">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{ template "footer.html" . }}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
|
|
||||||
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
|
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-16">
|
||||||
<div class="mx-auto max-w-3xl">
|
<div class="mx-auto max-w-4xl">
|
||||||
<div class="mt-6 sm:mt-8">
|
<div class="mt-6 sm:mt-8">
|
||||||
<div class="relative overflow-x-auto border-b border-gray-200 dark:border-gray-800">
|
<div class="relative overflow-x-auto border-b border-gray-200 dark:border-gray-800">
|
||||||
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Zineshop Print
|
<h2 class="title font-manrope font-bold text-4xl leading-10 mb-8 text-center text-black">Zineshop Print
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<p class="font-normal text-base leading-7 text-gray-500 text-left mb-5 mt-6">
|
<p class="font-normal text-base leading-7 text-gray-500 text-left mb-5 mt-6">
|
||||||
<bold>CoverPage</bold>: If selected, the Printer will take Paper from the BypassTray for the first page. For
|
<bold>CoverPage</bold>: If selected, the Printer will take Paper from the BypassTray for the first page. For
|
||||||
example you can put colored paper there to have a nice looking front page, and the rest will be normal paper.
|
example you can put colored paper there to have a nice looking front page, and the rest will be normal paper.
|
||||||
Makue sure you put paper in that tray when selecting this option.<br><br>
|
Make sure you put paper in that tray when selecting this option.<br><br>
|
||||||
|
|
||||||
Print Order: The Zines will be printed from top to bottom as seen in this list.
|
Print Order: The Zines will be printed from top to bottom as seen in this list.
|
||||||
|
|
||||||
@@ -33,14 +33,30 @@
|
|||||||
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="flex items-center aspect-square w-8 h-10 shrink-0">
|
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="flex items-center aspect-square w-8 h-10 shrink-0">
|
||||||
<img class="h-auto w-full max-h-full dark:hidden" src="/{{ .ShopItem.Image }}" alt="imac image" />
|
<img class="h-auto w-full max-h-full dark:hidden" src="/{{ .ShopItem.Image }}" alt="imac image" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
{{ if .ShopItem.WasPrinted }}
|
||||||
|
<span class="inline-flex items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-green-600/20 ring-inset">Tested</span>
|
||||||
|
{{ else }}
|
||||||
|
<span class="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-red-600/10 ring-inset">NOT TESTED</span>
|
||||||
|
{{ end }}
|
||||||
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="hover:underline">{{ .ShopItem.Name }} - {{ .ItemVariant.Name }}</a>
|
<a href="/shopitems/{{ .ItemVariant.ShopItemID }}" class="hover:underline">{{ .ShopItem.Name }} - {{ .ItemVariant.Name }}</a>
|
||||||
</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">CoverPage: 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">
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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="Logo">
|
<img class="mx-auto h-10 w-auto" src="/static/img/logo-black.png" alt="Logo">
|
||||||
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Register your account</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Register your account</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
59
views/registertoken.html
Normal file
59
views/registertoken.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{{ 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="Logo">
|
||||||
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Register your account</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<form class="space-y-6" action="/register" method="POST">
|
||||||
|
<div>
|
||||||
|
<label for="token" class="block text-sm/6 font-medium text-gray-900">Token</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="text" name="token" id="token" value="{{ .token }}" 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>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="name" class="block text-sm/6 font-medium text-gray-900">Username</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>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="email" class="block text-sm/6 font-medium text-gray-900">Email address</label>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="email" name="email" id="email" autocomplete="email" 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>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<label for="password" class="block text-sm/6 font-medium text-gray-900">Password</label>
|
||||||
|
</div>
|
||||||
|
<div class="mt-2">
|
||||||
|
<input type="password" name="password" id="password" autocomplete="current-password" 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">
|
||||||
|
{{ .error }}
|
||||||
|
</p>
|
||||||
|
<p class="mt-10 text-center text-sm/6 text-green-500">
|
||||||
|
{{ .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">Register</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{{ template "footer.html" . }}
|
||||||
@@ -9,15 +9,18 @@
|
|||||||
<img class="w-full h-full object-cover" src="/{{ .data.shopItem.Image}}" alt="Product Image">
|
<img class="w-full h-full object-cover" src="/{{ .data.shopItem.Image}}" alt="Product Image">
|
||||||
</div>
|
</div>
|
||||||
<div class="flex -mx-2 mb-4">
|
<div class="flex -mx-2 mb-4">
|
||||||
|
{{ if .loggedIn }}
|
||||||
<input type="hidden" id="{{ .data.shopItem.ID}}" name="ShopItemId" value="{{ .data.shopItem.ID }}">
|
<input type="hidden" id="{{ .data.shopItem.ID}}" name="ShopItemId" value="{{ .data.shopItem.ID }}">
|
||||||
<div class="w-1/3 px-2">
|
<div class="w-1/3 px-2">
|
||||||
<button type="submit" class="w-full bg-gray-900 dark:bg-gray-600 text-white py-2 px-4 rounded-lg 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-lg font-bold hover:bg-gray-800 dark:hover:bg-gray-700">Add to Cart</button>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
<div class="w-1/3 px-2">
|
<div class="w-1/3 px-2">
|
||||||
<button type="button" class="w-full bg-blue-900 dark:bg-gray-600 text-white py-2 px-4 rounded-lg font-bold hover:bg-gray-800 dark:hover:bg-gray-700"><a href="/{{ .data.shopItem.Pdf }}">View</a></button>
|
<button type="button" class="w-full bg-blue-900 dark:bg-gray-600 text-white py-2 px-4 rounded-lg font-bold hover:bg-gray-800 dark:hover:bg-gray-700"><a href="/{{ .data.shopItem.Pdf }}">View</a></button>
|
||||||
</div>
|
</div>
|
||||||
{{ if .loggedIn }}
|
|
||||||
|
{{ if .isAdmin }}
|
||||||
<div class="w-1/3 px-2">
|
<div class="w-1/3 px-2">
|
||||||
<button type="button" class="w-full bg-blue-900 dark:bg-gray-600 text-white py-2 px-4 rounded-lg font-bold hover:bg-gray-800 dark:hover:bg-gray-700"><a href="{{ .data.shopItem.ID }}/edit">Edit</a></button>
|
<button type="button" class="w-full bg-blue-900 dark:bg-gray-600 text-white py-2 px-4 rounded-lg font-bold hover:bg-gray-800 dark:hover:bg-gray-700"><a href="{{ .data.shopItem.ID }}/edit">Edit</a></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,6 +37,7 @@
|
|||||||
{{ .data.shopItem.Abstract }}
|
{{ .data.shopItem.Abstract }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{{ if .loggedIn }}
|
||||||
<div class="flex mb-4">
|
<div class="flex mb-4">
|
||||||
<label for="ItemVariantId" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"></label>
|
<label for="ItemVariantId" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white"></label>
|
||||||
<select name="ItemVariantId" id="ItemVariantId" 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="ItemVariantId" id="ItemVariantId" 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">
|
||||||
@@ -43,15 +47,16 @@
|
|||||||
{{ end }}
|
{{ end }}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
<div class="flex mb-4">
|
<div class="flex mb-4">
|
||||||
<div class="mr-4">
|
<div class="mr-4">
|
||||||
<span class="font-bold text-gray-700 dark:text-gray-300">Tags:</span>
|
<span class="font-bold text-gray-700 dark:text-gray-300">Tags:</span>
|
||||||
<span class="text-gray-600 dark:text-gray-300">
|
<p class="mt-1 text-sm text-gray-500">
|
||||||
{{ range .data.shopItem.Tags }}
|
{{ range .data.shopItem.Tags }}
|
||||||
{{ .Name }}
|
<a href="/tags/{{ .ID }}"><span class="bg-{{ .Color }}-100 text-{{ .Color }}-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-sm dark:bg-{{ .Color }}-900 dark:text-{{ .Color }}-300">{{ .Name }}</span></a>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</span>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -1,28 +1,61 @@
|
|||||||
<div class="bg-white">
|
<div class="bg-white">
|
||||||
<div class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl lg:px-8">
|
<div class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:max-w-7xl">
|
||||||
<h2 class="text-2xl font-bold tracking-tight text-gray-900">Available Zines</h2>
|
<h2 class="text-2xl font-bold tracking-tight text-gray-900">Available Zines</h2>
|
||||||
|
|
||||||
<div class="mt-6 grid grid-cols-1 gap-x-6 gap-y-10 sm:grid-cols-2 lg:grid-cols-4 xl:gap-x-8">
|
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
|
||||||
|
<div class="mt-6 grid grid-cols-1 gap-x-6 gap-y-10 md:grid-cols-2 xl:grid-cols-4">
|
||||||
{{ range .data.shopItems }}
|
{{ range .data.shopItems }}
|
||||||
|
|
||||||
<div class="group relative">
|
<div class="myClass group relative">
|
||||||
<img src="/{{ .Image }}" alt="Product Image" class="aspect-4/5 w-full rounded-md bg-gray-200 object-cover group-hover:opacity-75 lg:aspect-auto lg:h-80">
|
<a href="/shopitems/{{ .ID }}">
|
||||||
|
<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>
|
||||||
<div class="mt-4 flex justify-between">
|
<div class="mt-4 flex justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-sm text-gray-700">
|
<h3 class="text-sm text-gray-700">
|
||||||
<a href="/shopitems/{{ .ID }}">
|
<a href="/shopitems/{{ .ID }}">
|
||||||
<span aria-hidden="true" class="absolute inset-0"></span>
|
|
||||||
{{ .Name }}
|
{{ .Name }}
|
||||||
</a>
|
</a>
|
||||||
</h3>
|
</h3>
|
||||||
<p class="mt-1 text-sm text-gray-500">{{ .Abstract }}</p>
|
<p class="mt-1 text-sm text-gray-500">{{ .Abstract }}</p>
|
||||||
<p class="mt-1 text-sm text-gray-500">{{ range .Tags }}{{ .Name }} {{ end }}</p>
|
|
||||||
|
<p class="mt-1 text-sm text-gray-500">
|
||||||
|
{{ range .Tags }}
|
||||||
|
<a href="/tags/{{ .ID }}"><span class="bg-{{ .Color }}-100 text-{{ .Color }}-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-sm dark:bg-{{ .Color }}-900 dark:text-{{ .Color }}-300">{{ .Name }}</span></a>
|
||||||
|
{{ end }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
{{ if $.loggedIn }}
|
||||||
<p class="text-sm font-medium text-gray-900">{{ .BasePrice }}€</p>
|
<p class="text-sm font-medium text-gray-900">{{ .BasePrice }}€</p>
|
||||||
|
{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function myFunction() {
|
||||||
|
// Declare variables
|
||||||
|
var input, filter, ul, li, a, i, txtValue;
|
||||||
|
input = document.getElementById('myInput');
|
||||||
|
filter = input.value.toUpperCase();
|
||||||
|
//ul = document.getElementById("myUL");
|
||||||
|
//li = ul.getElementsByTagName('li');
|
||||||
|
li = document.getElementsByClassName("myClass");
|
||||||
|
|
||||||
|
console.log(li)
|
||||||
|
// Loop through all list items, and hide those who don't match the search query
|
||||||
|
for (i = 0; i < li.length; i++) {
|
||||||
|
a = li[i].getElementsByTagName("a")[1];
|
||||||
|
txtValue = a.textContent || a.innerText;
|
||||||
|
if (txtValue.toUpperCase().indexOf(filter) > -1) {
|
||||||
|
li[i].style.display = "";
|
||||||
|
} else {
|
||||||
|
li[i].style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
|
<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">
|
<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">
|
<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 Tags</h2>
|
<h2 class="mt-10 text-center text-2xl/9 font-bold tracking-tight text-gray-900">Edit Tags</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -12,7 +12,36 @@
|
|||||||
<form action="/tags/{{ .ID }}" method="POST">
|
<form action="/tags/{{ .ID }}" method="POST">
|
||||||
<div class="max-w-md mx-auto mt-4">
|
<div class="max-w-md mx-auto mt-4">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
|
|
||||||
|
<span class="bg-{{ .Color }}-100 text-{{ .Color }}-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded-sm
|
||||||
|
dark:bg-{{ .Color }}-900 dark:text-{{ .Color }}-300">Preview</span>
|
||||||
<input type="text" id="name" name="name" value="{{ .Name }}" 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="name" name="name" value="{{ .Name }}" class="flex-grow border border-gray-300 rounded-l-md p-2 focus:outline-none focus:ring focus:ring-blue-500">
|
||||||
|
<select name="color" required>
|
||||||
|
<option selected value="{{ .Color }}">{{ .Color }}</option>
|
||||||
|
<option value="1">Default</option>
|
||||||
|
<option value="red">red</option>
|
||||||
|
<option value="orange">orange</option>
|
||||||
|
<option value="amber">amber</option>
|
||||||
|
<option value="yellow">yellow</option>
|
||||||
|
<option value="lime">lime</option>
|
||||||
|
<option value="green">green</option>
|
||||||
|
<option value="emerald">emerald</option>
|
||||||
|
<option value="teal">teal</option>
|
||||||
|
<option value="cyan">cyan</option>
|
||||||
|
<option value="sky">sky</option>
|
||||||
|
<option value="blue">blue</option>
|
||||||
|
<option value="indigo">indigo</option>
|
||||||
|
<option value="violet">violet</option>
|
||||||
|
<option value="purple">purple</option>
|
||||||
|
<option value="fuchsia">fuchsia</option>
|
||||||
|
<option value="pink">pink</option>
|
||||||
|
<option value="rose">rose</option>
|
||||||
|
<option value="slate">slate</option>
|
||||||
|
<option value="gray">gray</option>
|
||||||
|
<option value="zinc">zinc</option>
|
||||||
|
<option value="neutral">neutral</option>
|
||||||
|
<option value="stone">stone</option>
|
||||||
|
</select>
|
||||||
<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="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>
|
<button type="submit" name="action" value="delete" class="bg-red-800 text-white rounded px-4 hover:bg-red-900">Delete</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user