feat: add characters
This commit is contained in:
+58
-2
@@ -33,11 +33,12 @@ type Handler struct {
|
||||
tpl *template.Template
|
||||
cardsDir string // پوشهی دیسکیِ آپلودِ اسکینها (همان مسیری که static از آن سرو میکند)
|
||||
carpetsDir string // پوشهی دیسکیِ آپلودِ تصاویرِ فرش
|
||||
avatarsDir string // پوشهی دیسکیِ آپلودِ تصاویرِ شخصیتِ آواتار
|
||||
}
|
||||
|
||||
func New(db *sql.DB, eco *economy.Service, cardsDir, carpetsDir string) *Handler {
|
||||
func New(db *sql.DB, eco *economy.Service, cardsDir, carpetsDir, avatarsDir string) *Handler {
|
||||
tpl := template.Must(template.ParseFS(tplFS, "templates/*.html"))
|
||||
return &Handler{db: db, eco: eco, tpl: tpl, cardsDir: cardsDir, carpetsDir: carpetsDir}
|
||||
return &Handler{db: db, eco: eco, tpl: tpl, cardsDir: cardsDir, carpetsDir: carpetsDir, avatarsDir: avatarsDir}
|
||||
}
|
||||
|
||||
// Routes زیرروترِ /admin را با Basic Auth برمیگرداند.
|
||||
@@ -537,6 +538,61 @@ func (h *Handler) carpetUpload(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/admin/carpets?saved=1", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// avatarUpload یک تصویرِ png یا svg را برای یک شخصیتِ آواتار آپلود و با نامِ
|
||||
// <id>.<ext> ذخیره میکند و img_ext را در دیتابیس بهروزرسانی میکند. نوعِ فایل از
|
||||
// پسوندِ نامِ آپلودشده تشخیص داده میشود (svg → svg، وگرنه png). png برای شفافیت.
|
||||
func (h *Handler) avatarUpload(w http.ResponseWriter, r *http.Request) {
|
||||
id := chi.URLParam(r, "id")
|
||||
if id == "" || strings.ContainsAny(id, "/\\.") {
|
||||
http.Error(w, "invalid id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if h.avatarsDir == "" {
|
||||
http.Error(w, "AVATARS_DIR تنظیم نشده است", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if err := r.ParseMultipartForm(16 << 20); err != nil {
|
||||
http.Error(w, "bad upload", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
file, hdr, err := r.FormFile("image")
|
||||
if err != nil {
|
||||
http.Error(w, "image لازم است", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
buf, err := io.ReadAll(io.LimitReader(file, 16<<20))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
ext := "png"
|
||||
if strings.HasSuffix(strings.ToLower(hdr.Filename), ".svg") {
|
||||
ext = "svg"
|
||||
// «SVGِ رستری» (PNG داخلِ svg) را به PNG واقعی تبدیل کن تا اپ رندرش کند.
|
||||
if raw, rext, ok := extractEmbeddedRaster(buf); ok {
|
||||
buf, ext = raw, rext
|
||||
}
|
||||
}
|
||||
if err := os.MkdirAll(h.avatarsDir, 0o755); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// نسخههای قبلی با پسوندِ دیگر را پاک کن تا چند نسخه نماند.
|
||||
for _, e := range []string{"png", "jpg", "svg"} {
|
||||
if e != ext {
|
||||
_ = os.Remove(filepath.Join(h.avatarsDir, id+"."+e))
|
||||
}
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(h.avatarsDir, id+"."+ext), buf, 0o644); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_, _ = h.db.ExecContext(r.Context(), `UPDATE avatars SET img_ext = ? WHERE id = ?`, ext, id)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"ok":true}`))
|
||||
}
|
||||
|
||||
// --- مدیریتِ بستههای چت و پیامها ---
|
||||
|
||||
func (h *Handler) chatAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user