This commit is contained in:
Tomas Dvorak
2026-01-26 08:13:18 +01:00
parent aa036b6550
commit dfc079288f
505 changed files with 95755 additions and 5712 deletions
+96 -2
View File
@@ -1,6 +1,8 @@
package controllers
import (
"crypto/rand"
"encoding/hex"
"net/http"
"strconv"
"strings"
@@ -62,6 +64,16 @@ func NewEngagementController(db *gorm.DB, es email.EmailService) *EngagementCont
return &EngagementController{DB: db, Email: es}
}
// genRewardSKU generates a short uppercase code like RWD-1A2B3C4D
func genRewardSKU() string {
b := make([]byte, 4)
if _, err := rand.Read(b); err == nil {
return "RWD-" + strings.ToUpper(hex.EncodeToString(b))
}
// Fallback to time-based base36 suffix
return "RWD-" + strings.ToUpper(strconv.FormatInt(time.Now().UnixNano()%2176782336, 36))
}
// Admin: adjust points for a user (positive or negative)
// POST /api/v1/admin/engagement/adjust { user_id, delta, reason?, meta? }
func (ec *EngagementController) AdminAdjustPoints(c *gin.Context) {
@@ -536,7 +548,6 @@ func (ec *EngagementController) GetAchievements(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"achievements": items, "counters": gin.H{"comments": commentCount, "votes": voteCount, "newsletter": hasNewsletter}})
}
// Admin: list rewards
// GET /api/v1/admin/engagement/rewards
func (ec *EngagementController) AdminListRewards(c *gin.Context) {
var items []models.RewardItem
@@ -579,6 +590,28 @@ func (ec *EngagementController) AdminListRewards(c *gin.Context) {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to load rewards"})
return
}
// Backfill missing SKU for merch_physical items
for i := range items {
if strings.EqualFold(strings.TrimSpace(items[i].Type), "merch_physical") {
md := items[i].Metadata
var skuVal string
if md != nil {
if v, ok := md["sku"]; ok {
if s, ok2 := v.(string); ok2 {
skuVal = strings.TrimSpace(s)
}
}
}
if strings.TrimSpace(skuVal) == "" {
if md == nil {
md = datatypes.JSONMap{}
}
md["sku"] = genRewardSKU()
_ = ec.DB.Model(&models.RewardItem{}).Where("id = ?", items[i].ID).Update("metadata", md).Error
items[i].Metadata = md
}
}
}
c.JSON(http.StatusOK, gin.H{"items": items})
}
@@ -611,6 +644,20 @@ func (ec *EngagementController) AdminCreateReward(c *gin.Context) {
if body.Metadata != nil {
item.Metadata = body.Metadata
}
// Ensure SKU is auto-generated for merch_physical when missing/empty
if strings.EqualFold(strings.TrimSpace(item.Type), "merch_physical") {
if item.Metadata == nil {
item.Metadata = datatypes.JSONMap{}
}
if v, ok := item.Metadata["sku"]; !ok {
item.Metadata["sku"] = genRewardSKU()
} else {
s, _ := v.(string)
if strings.TrimSpace(s) == "" {
item.Metadata["sku"] = genRewardSKU()
}
}
}
if err := ec.DB.Create(&item).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create reward"})
return
@@ -686,8 +733,55 @@ func (ec *EngagementController) AdminUpdateReward(c *gin.Context) {
if body.Active != nil {
updates["active"] = *body.Active
}
// Determine target type after potential change
targetType := existing.Type
if body.Type != nil {
targetType = strings.TrimSpace(*body.Type)
}
if body.Metadata != nil {
updates["metadata"] = body.Metadata
// Merge existing metadata with new to preserve fields like auto-generated sku
merged := map[string]interface{}{}
if existing.Metadata != nil {
for k, v := range existing.Metadata {
merged[k] = v
}
}
for k, v := range body.Metadata {
merged[k] = v
}
if strings.EqualFold(strings.TrimSpace(targetType), "merch_physical") {
if v, ok := merged["sku"]; !ok {
merged["sku"] = genRewardSKU()
} else {
s, _ := v.(string)
if strings.TrimSpace(s) == "" {
merged["sku"] = genRewardSKU()
}
}
}
updates["metadata"] = merged
} else {
// If type is merch_physical and existing metadata lacks sku, add it
if strings.EqualFold(strings.TrimSpace(targetType), "merch_physical") {
needSKU := true
if existing.Metadata != nil {
if v, ok := existing.Metadata["sku"]; ok {
if s, ok2 := v.(string); ok2 && strings.TrimSpace(s) != "" {
needSKU = false
}
}
}
if needSKU {
merged := map[string]interface{}{}
if existing.Metadata != nil {
for k, v := range existing.Metadata {
merged[k] = v
}
}
merged["sku"] = genRewardSKU()
updates["metadata"] = merged
}
}
}
if len(updates) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "No changes"})