From 861b18651bd77371711aef0727e3a472fc90a4a0 Mon Sep 17 00:00:00 2001 From: kalipso Date: Fri, 27 Jun 2025 16:31:37 +0200 Subject: [PATCH] add ui configurable config options --- controllers/configController.go | 218 ++++++++++++++++++++++++++++++ controllers/shopItemController.go | 114 ---------------- main.go | 11 +- models/config.go | 11 ++ repositories/configRepository.go | 81 +++++++++++ repositories/repository.go | 16 ++- static/output.css | 19 +-- views/configview.html | 33 +++++ 8 files changed, 365 insertions(+), 138 deletions(-) create mode 100644 controllers/configController.go create mode 100644 models/config.go create mode 100644 repositories/configRepository.go create mode 100644 views/configview.html diff --git a/controllers/configController.go b/controllers/configController.go new file mode 100644 index 0000000..4c46251 --- /dev/null +++ b/controllers/configController.go @@ -0,0 +1,218 @@ +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) + 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) 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) +} diff --git a/controllers/shopItemController.go b/controllers/shopItemController.go index a0da554..d662d18 100644 --- a/controllers/shopItemController.go +++ b/controllers/shopItemController.go @@ -29,15 +29,10 @@ type ShopItemController interface { AddItemHandler(*gin.Context) AddItemsView(*gin.Context) AddItemsHandler(*gin.Context) - CreateTag(*gin.Context) - GetAllTags(*gin.Context) EditItemView(*gin.Context) EditItemHandler(*gin.Context) DeleteItemView(*gin.Context) DeleteItemHandler(*gin.Context) - TagView(*gin.Context) - TagHandler(*gin.Context) - AddTagHandler(*gin.Context) } type shopItemController struct{} @@ -621,115 +616,6 @@ func (rc *shopItemController) DeleteItemHandler(c *gin.Context) { c.HTML(http.StatusOK, "index.html", data) } -func (rc *shopItemController) TagHandler(ctx *gin.Context) { - name := ctx.PostForm("name") - color := ctx.PostForm("color") - action := ctx.PostForm("action") - - tag, err := repositories.Tags.GetById(ctx.Param("id")) - - if err != nil { - fmt.Println(err) - ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err}) - return - } - - if action == "update" { - tag.Name = name - tag.Color = color - tag, err = repositories.Tags.Update(tag) - - if err != nil { - fmt.Println(err) - ctx.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err}) - return - } - } - - if action == "delete" { - repositories.Tags.DeleteById(ctx.Param("id")) - } - - rc.TagView(ctx) -} - -func (rc *shopItemController) AddTagHandler(c *gin.Context) { - tag, err := models.NewTag(c) - - if err != nil { - fmt.Println(err) - c.HTML(http.StatusBadRequest, "tagview.html", gin.H{"error": err}) - return - } - - _, err = repositories.Tags.Create(tag) - if err != nil { - data := CreateSessionData(c, gin.H{ - "error": err, - "success": "", - }) - - c.HTML(http.StatusOK, "tagview.html", data) - return - } - - rc.TagView(c) -} - -func (rc *shopItemController) TagView(c *gin.Context) { - tags, err := repositories.Tags.GetAll() - - if err != nil { - c.HTML(http.StatusBadRequest, "tagview.html", gin.H{"data": gin.H{"error": err}}) - } - - data := CreateSessionData(c, gin.H{ - "tags": tags, - }) - - if err != nil { - c.HTML(http.StatusBadRequest, "tagview.html", data) - } - - c.HTML(http.StatusOK, "tagview.html", data) -} - -func (rc *shopItemController) CreateTag(c *gin.Context) { - tag, err := models.NewTagByJson(c) - - if err != nil { - ReplyError(c, err) - } - - _, err = repositories.Tags.Create(tag) - if err != nil { - ReplyError(c, fmt.Errorf("shopItem creation failed: %s", err)) - return - } - - //userID := user.(models.User).ID - //rc.DB.Model(&models.shopItem{}).Where("id = ?"), room.ID).Association("Admins").Append(&models.User{ID: userID}) - - //if result.Error != nil { - // ReplyError(c, fmt.Errorf("shopItem creation failed: %s", result.Error)) - // return - //} - - ReplyOK(c, fmt.Sprintf("tag '%s' was created", tag.Name)) - -} - -func (rc *shopItemController) GetAllTags(c *gin.Context) { - tags, err := repositories.Tags.GetAll() - - if err != nil { - ReplyError(c, fmt.Errorf("Could not query Tags")) - return - } - - c.JSON(http.StatusOK, tags) -} - func ReplyError(ctx *gin.Context, err error) { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) } diff --git a/main.go b/main.go index d603f48..acf0549 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ var ( userController controllers.UserController = controllers.UserController{} cartItemController controllers.CartItemController = controllers.NewCartItemController() printController controllers.PrintController = controllers.NewPrintController() + configController controllers.ConfigController = controllers.NewConfigController() authValidator middlewares.AuthValidator = middlewares.AuthValidator{} ) @@ -67,10 +68,14 @@ func main() { viewRoutes.GET("/cart/print", authValidator.RequireAdmin, printController.PrintCartView) viewRoutes.POST("/print", authValidator.RequireAdmin, printController.PrintHandler) - viewRoutes.GET("/tags", authValidator.RequireAdmin, shopItemController.TagView) - viewRoutes.POST("/tags/:id", authValidator.RequireAdmin, shopItemController.TagHandler) + viewRoutes.GET("/config", authValidator.RequireAdmin, configController.ConfigView) + viewRoutes.POST("/config/:id", authValidator.RequireAdmin, configController.ConfigHandler) + viewRoutes.POST("/config", authValidator.RequireAdmin, configController.AddConfigHandler) + + viewRoutes.GET("/tags", authValidator.RequireAdmin, configController.TagView) + viewRoutes.POST("/tags/:id", authValidator.RequireAdmin, configController.TagHandler) viewRoutes.GET("/tags/:id", userController.TagView) - viewRoutes.POST("/tags", authValidator.RequireAdmin, shopItemController.AddTagHandler) + viewRoutes.POST("/tags", authValidator.RequireAdmin, configController.AddTagHandler) viewRoutes.GET("/cart", authValidator.RequireAuth, cartItemController.CartItemView) viewRoutes.POST("/cart", authValidator.RequireAuth, cartItemController.AddItemHandler) viewRoutes.POST("/cart/delete", authValidator.RequireAuth, cartItemController.DeleteItemHandler) diff --git a/models/config.go b/models/config.go new file mode 100644 index 0000000..59c8a1d --- /dev/null +++ b/models/config.go @@ -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"` +} diff --git a/repositories/configRepository.go b/repositories/configRepository.go new file mode 100644 index 0000000..443a272 --- /dev/null +++ b/repositories/configRepository.go @@ -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 +} diff --git a/repositories/repository.go b/repositories/repository.go index e3e81ff..dad8aa5 100644 --- a/repositories/repository.go +++ b/repositories/repository.go @@ -9,12 +9,13 @@ import ( ) var ( - ShopItems ShopItemRepository - Users UserRepository - Tags TagRepository - CartItems CartItemRepository - Orders OrderRepository - Tokens RegisterTokenRepository + ShopItems ShopItemRepository + Users UserRepository + Tags TagRepository + CartItems CartItemRepository + Orders OrderRepository + Tokens RegisterTokenRepository + ConfigOptions ConfigRepository ) func InitRepositories() { @@ -29,6 +30,8 @@ func InitRepositories() { &models.Tag{}, &models.CartItem{}, &models.Order{}, + &models.Config{}, + &models.Paper{}, &models.RegisterToken{}) if err != nil { @@ -41,4 +44,5 @@ func InitRepositories() { CartItems = NewGORMCartItemRepository(db) Orders = NewGORMOrderRepository(db) Tokens = NewGORMRegisterTokenRepository(db) + ConfigOptions = NewGORMConfigRepository(db) } diff --git a/static/output.css b/static/output.css index ce1c154..7856e3d 100644 --- a/static/output.css +++ b/static/output.css @@ -1722,27 +1722,16 @@ video { -moz-osx-font-smoothing: grayscale; } -.shadow-sm { - --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - -.shadow-xl { - --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); -} - .shadow-2xl { --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25); --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } -.shadow-red-900 { - --tw-shadow-color: #7f1d1d; - --tw-shadow: var(--tw-shadow-colored); +.shadow-sm { + --tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } .outline { diff --git a/views/configview.html b/views/configview.html new file mode 100644 index 0000000..a29ee6a --- /dev/null +++ b/views/configview.html @@ -0,0 +1,33 @@ +{{ template "header.html" . }} + + +
+
+ Your Company +

Edit config options

+
+ +
+ {{ range .data.configOptions }} +
+
+
+ + + + + +
+ + {{ end }} +
+
+
+ + + +
+
+
+
+{{ template "footer.html" . }}