feat: add uuid

This commit is contained in:
2026-07-04 21:21:13 +03:30
parent 63716576ca
commit c6997477b9
10 changed files with 320 additions and 78 deletions
+30 -16
View File
@@ -5,6 +5,7 @@ package admin
import (
"archive/zip"
"context"
"crypto/rand"
"database/sql"
"embed"
"fmt"
@@ -15,6 +16,7 @@ import (
"path/filepath"
"strconv"
"strings"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
@@ -99,16 +101,16 @@ func (h *Handler) shop(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
data := map[string]any{
"Nav": "shop",
"Coins": h.rows(ctx, `SELECT id,title,coins,vip_days,price_toman,bonus_pct,sort,enabled FROM coin_packages ORDER BY sort`,
"id", "title", "coins", "vip_days", "price_toman", "bonus_pct", "sort", "enabled"),
"Tickets": h.rows(ctx, `SELECT id,title,tickets,price_toman,sort,enabled FROM ticket_packages ORDER BY sort`,
"id", "title", "tickets", "price_toman", "sort", "enabled"),
"Coins": h.rows(ctx, `SELECT id,title,coins,vip_days,price_toman,bonus_pct,sku,sort,enabled FROM coin_packages ORDER BY sort`,
"id", "title", "coins", "vip_days", "price_toman", "bonus_pct", "sku", "sort", "enabled"),
"Tickets": h.rows(ctx, `SELECT id,title,tickets,price_toman,sku,sort,enabled FROM ticket_packages ORDER BY sort`,
"id", "title", "tickets", "price_toman", "sku", "sort", "enabled"),
"Cards": h.rows(ctx, `SELECT id,title,price_coins,sort,enabled FROM card_skins ORDER BY sort`,
"id", "title", "price_coins", "sort", "enabled"),
"Boosters": h.rows(ctx, `SELECT id,title,multiplier,hours,price_toman,sort,enabled FROM boosters ORDER BY sort`,
"id", "title", "multiplier", "hours", "price_toman", "sort", "enabled"),
"VIP": h.rows(ctx, `SELECT id,title,months,price_toman,sort,enabled FROM vip_packages ORDER BY sort`,
"id", "title", "months", "price_toman", "sort", "enabled"),
"Boosters": h.rows(ctx, `SELECT id,title,multiplier,hours,price_toman,sku,sort,enabled FROM boosters ORDER BY sort`,
"id", "title", "multiplier", "hours", "price_toman", "sku", "sort", "enabled"),
"VIP": h.rows(ctx, `SELECT id,title,months,price_toman,sku,sort,enabled FROM vip_packages ORDER BY sort`,
"id", "title", "months", "price_toman", "sku", "sort", "enabled"),
"Tiers": h.rows(ctx, `SELECT id,title,hands,entry,prize,xp,trophy,rank_reward,sort,enabled FROM table_tiers ORDER BY sort`,
"id", "title", "hands", "entry", "prize", "xp", "trophy", "rank_reward", "sort", "enabled"),
"Saved": r.URL.Query().Get("saved") == "1",
@@ -181,25 +183,26 @@ func (h *Handler) addItem(w http.ResponseWriter, r *http.Request) {
if r.FormValue("enabled") == "on" {
en = 1
}
sku := newUUID() // شناسه‌ی محصولِ فروشگاه (uuid) خودکار تولید می‌شود
var q string
var args []any
switch kind {
case "coin":
q = `INSERT INTO coin_packages (id,title,coins,vip_days,price_toman,bonus_pct,sort,enabled) VALUES (?,?,?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("coins"), f("vip_days"), f("price_toman"), f("bonus_pct"), f("sort"), en}
q = `INSERT INTO coin_packages (id,title,coins,vip_days,price_toman,bonus_pct,sku,sort,enabled) VALUES (?,?,?,?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("coins"), f("vip_days"), f("price_toman"), f("bonus_pct"), sku, f("sort"), en}
case "ticket":
q = `INSERT INTO ticket_packages (id,title,tickets,price_toman,sort,enabled) VALUES (?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("tickets"), f("price_toman"), f("sort"), en}
q = `INSERT INTO ticket_packages (id,title,tickets,price_toman,sku,sort,enabled) VALUES (?,?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("tickets"), f("price_toman"), sku, f("sort"), en}
case "card":
q = `INSERT INTO card_skins (id,title,price_coins,sort,enabled) VALUES (?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("price_coins"), f("sort"), en}
case "booster":
q = `INSERT INTO boosters (id,title,multiplier,hours,price_toman,sort,enabled) VALUES (?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("multiplier"), f("hours"), f("price_toman"), f("sort"), en}
q = `INSERT INTO boosters (id,title,multiplier,hours,price_toman,sku,sort,enabled) VALUES (?,?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("multiplier"), f("hours"), f("price_toman"), sku, f("sort"), en}
case "vip":
q = `INSERT INTO vip_packages (id,title,months,price_toman,sort,enabled) VALUES (?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("months"), f("price_toman"), f("sort"), en}
q = `INSERT INTO vip_packages (id,title,months,price_toman,sku,sort,enabled) VALUES (?,?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("months"), f("price_toman"), sku, f("sort"), en}
case "tier":
q = `INSERT INTO table_tiers (id,title,hands,entry,prize,xp,trophy,rank_reward,sort,enabled) VALUES (?,?,?,?,?,?,?,?,?,?)`
args = []any{id, r.FormValue("title"), f("hands"), f("entry"), f("prize"), f("xp"), f("trophy"), f("rank_reward"), f("sort"), en}
@@ -643,6 +646,17 @@ func (h *Handler) chatMessageDelete(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/admin/chat?saved=1", http.StatusSeeOther)
}
// newUUID یک UUIDv4 برای شناسه‌ی محصولِ فروشگاه (SKU) تولید می‌کند.
func newUUID() string {
var b [16]byte
if _, err := rand.Read(b[:]); err != nil {
return fmt.Sprintf("sku-%d", time.Now().UnixNano())
}
b[6] = (b[6] & 0x0f) | 0x40 // نسخه ۴
b[8] = (b[8] & 0x3f) | 0x80 // variant
return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:16])
}
func (h *Handler) rows(ctx context.Context, query string, cols ...string) []map[string]any {
rs, err := h.db.QueryContext(ctx, query)
if err != nil {
+12 -4
View File
@@ -10,7 +10,7 @@
<h2>بسته‌های سکه</h2>
<table>
<tr><th>شناسه</th><th>عنوان</th><th>سکه</th><th>VIP (روز)</th><th>قیمت (تومان)</th><th>بونوس٪</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
<tr><th>شناسه</th><th>عنوان</th><th>سکه</th><th>VIP (روز)</th><th>قیمت (تومان)</th><th>بونوس٪</th><th>SKU (مایکت/کافه)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
{{range .Coins}}
<tr><form method="post" action="/admin/shop/coin">
<td>{{.id}}<input type="hidden" name="id" value="{{.id}}"></td>
@@ -19,6 +19,7 @@
<td><input name="vip_days" value="{{.vip_days}}"></td>
<td><input name="price_toman" value="{{.price_toman}}"></td>
<td><input name="bonus_pct" value="{{.bonus_pct}}"></td>
<td><code style="font-size:11px">{{.sku}}</code></td>
<td><input name="sort" value="{{.sort}}"></td>
<td><input type="checkbox" name="enabled" {{if .enabled}}checked{{end}}></td>
<td><button>ذخیره</button></td>
@@ -32,6 +33,7 @@
<td><input name="vip_days" value="0"></td>
<td><input name="price_toman" value="0"></td>
<td><input name="bonus_pct" value="0"></td>
<td style="color:#9aa;font-size:11px">خودکار</td>
<td><input name="sort" value="0"></td>
<td><input type="checkbox" name="enabled" checked></td>
<td colspan="2"><button>افزودن</button></td>
@@ -40,13 +42,14 @@
<h2>بسته‌های بلیط</h2>
<table>
<tr><th>شناسه</th><th>عنوان</th><th>بلیط</th><th>قیمت (تومان)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
<tr><th>شناسه</th><th>عنوان</th><th>بلیط</th><th>قیمت (تومان)</th><th>SKU (مایکت/کافه)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
{{range .Tickets}}
<tr><form method="post" action="/admin/shop/ticket">
<td>{{.id}}<input type="hidden" name="id" value="{{.id}}"></td>
<td><input type="text" name="title" value="{{.title}}"></td>
<td><input name="tickets" value="{{.tickets}}"></td>
<td><input name="price_toman" value="{{.price_toman}}"></td>
<td><code style="font-size:11px">{{.sku}}</code></td>
<td><input name="sort" value="{{.sort}}"></td>
<td><input type="checkbox" name="enabled" {{if .enabled}}checked{{end}}></td>
<td><button>ذخیره</button></td>
@@ -58,6 +61,7 @@
<td><input name="title" placeholder="عنوان"></td>
<td><input name="tickets" value="0"></td>
<td><input name="price_toman" value="0"></td>
<td style="color:#9aa;font-size:11px">خودکار</td>
<td><input name="sort" value="0"></td>
<td><input type="checkbox" name="enabled" checked></td>
<td colspan="2"><button>افزودن</button></td>
@@ -98,7 +102,7 @@
<h2>بوسترها</h2>
<table>
<tr><th>شناسه</th><th>عنوان</th><th>ضریب</th><th>ساعت</th><th>قیمت (تومان)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
<tr><th>شناسه</th><th>عنوان</th><th>ضریب</th><th>ساعت</th><th>قیمت (تومان)</th><th>SKU (مایکت/کافه)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
{{range .Boosters}}
<tr><form method="post" action="/admin/shop/booster">
<td>{{.id}}<input type="hidden" name="id" value="{{.id}}"></td>
@@ -106,6 +110,7 @@
<td><input name="multiplier" value="{{.multiplier}}"></td>
<td><input name="hours" value="{{.hours}}"></td>
<td><input name="price_toman" value="{{.price_toman}}"></td>
<td><code style="font-size:11px">{{.sku}}</code></td>
<td><input name="sort" value="{{.sort}}"></td>
<td><input type="checkbox" name="enabled" {{if .enabled}}checked{{end}}></td>
<td><button>ذخیره</button></td>
@@ -118,6 +123,7 @@
<td><input name="multiplier" value="2"></td>
<td><input name="hours" value="24"></td>
<td><input name="price_toman" value="0"></td>
<td style="color:#9aa;font-size:11px">خودکار</td>
<td><input name="sort" value="0"></td>
<td><input type="checkbox" name="enabled" checked></td>
<td colspan="2"><button>افزودن</button></td>
@@ -126,13 +132,14 @@
<h2>اشتراک‌های VIP</h2>
<table>
<tr><th>شناسه</th><th>عنوان</th><th>ماه</th><th>قیمت (تومان)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
<tr><th>شناسه</th><th>عنوان</th><th>ماه</th><th>قیمت (تومان)</th><th>SKU (مایکت/کافه)</th><th>ترتیب</th><th>فعال</th><th colspan="2"></th></tr>
{{range .VIP}}
<tr><form method="post" action="/admin/shop/vip">
<td>{{.id}}<input type="hidden" name="id" value="{{.id}}"></td>
<td><input type="text" name="title" value="{{.title}}"></td>
<td><input name="months" value="{{.months}}"></td>
<td><input name="price_toman" value="{{.price_toman}}"></td>
<td><code style="font-size:11px">{{.sku}}</code></td>
<td><input name="sort" value="{{.sort}}"></td>
<td><input type="checkbox" name="enabled" {{if .enabled}}checked{{end}}></td>
<td><button>ذخیره</button></td>
@@ -144,6 +151,7 @@
<td><input name="title" placeholder="عنوان"></td>
<td><input name="months" value="1"></td>
<td><input name="price_toman" value="0"></td>
<td style="color:#9aa;font-size:11px">خودکار</td>
<td><input name="sort" value="0"></td>
<td><input type="checkbox" name="enabled" checked></td>
<td colspan="2"><button>افزودن</button></td>