mirror of
https://github.com/GMWalletApp/epusdt.git
synced 2026-07-07 18:26:16 +00:00
feat: add admin panel with multi-chain support and notification system
- Add full admin REST API: auth, API keys, chains, chain tokens, wallets, orders, RPC nodes, settings, dashboard stats, notifications - Add JWT-based admin authentication and API key auth middleware - Add multi-chain listeners: BSC, ETH, Polygon, Plasma, EVM WebSocket - Add RPC node health check job with automatic failover - Add Telegram notification channel for order events - Add installer for first-run database initialization - Add new DB models: admin_user, api_key, chain, chain_token, rpc_node, settings, notification_channel - Add order statistics aggregation (daily/monthly/by-chain) - Serve built admin SPA from embedded www/ assets - Add comprehensive test coverage for all new features
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/assimon/luuu/config"
|
||||
"github.com/assimon/luuu/internal/testutil"
|
||||
"github.com/assimon/luuu/model/dao"
|
||||
"github.com/assimon/luuu/model/data"
|
||||
"github.com/assimon/luuu/model/mdb"
|
||||
)
|
||||
|
||||
func withTelegramEnv(token, proxy string, manage int64, fn func()) {
|
||||
origToken := config.TgBotToken
|
||||
origProxy := config.TgProxy
|
||||
origManage := config.TgManage
|
||||
defer func() {
|
||||
config.TgBotToken = origToken
|
||||
config.TgProxy = origProxy
|
||||
config.TgManage = origManage
|
||||
}()
|
||||
|
||||
config.TgBotToken = token
|
||||
config.TgProxy = proxy
|
||||
config.TgManage = manage
|
||||
fn()
|
||||
}
|
||||
|
||||
func TestLoadCommandBotConfig_DoesNotUseEnvFallbackWhenNoChannel(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
// Env config is present but settings table is empty —
|
||||
// the bot must NOT fall back to config.TgBotToken.
|
||||
withTelegramEnv("env-token", "http://127.0.0.1:7890", 123456789, func() {
|
||||
cfg, source, err := loadCommandBotConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("loadCommandBotConfig err: %v", err)
|
||||
}
|
||||
if cfg != nil {
|
||||
t.Fatalf("expected nil config when settings table has no telegram keys, got %+v", cfg)
|
||||
}
|
||||
if source != "" {
|
||||
t.Fatalf("source = %q, want empty", source)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoadCommandBotConfig_PrefersEnabledTelegramChannel(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
// Seed settings table with telegram credentials.
|
||||
dao.Mdb.Create(&mdb.Setting{Group: "system", Key: "system.telegram_bot_token", Value: "db-token", Type: "string"})
|
||||
dao.Mdb.Create(&mdb.Setting{Group: "system", Key: "system.telegram_chat_id", Value: "987654321", Type: "string"})
|
||||
_ = data.ReloadSettings()
|
||||
|
||||
withTelegramEnv("env-token", "", 123456789, func() {
|
||||
cfg, source, err := loadCommandBotConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("loadCommandBotConfig err: %v", err)
|
||||
}
|
||||
if cfg == nil {
|
||||
t.Fatal("expected non-nil config")
|
||||
}
|
||||
if source != "settings" {
|
||||
t.Fatalf("source = %q, want %q", source, "settings")
|
||||
}
|
||||
if cfg.BotToken != "db-token" {
|
||||
t.Fatalf("bot token = %q, want %q", cfg.BotToken, "db-token")
|
||||
}
|
||||
if cfg.ChatID != 987654321 {
|
||||
t.Fatalf("chat id = %d, want %d", cfg.ChatID, int64(987654321))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoadCommandBotConfig_ReturnsNilWhenNoChannelAndNoEnv(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
// Fresh DB — ensure the cache doesn't carry over values from a previous test.
|
||||
_ = data.ReloadSettings()
|
||||
|
||||
withTelegramEnv("", "", 0, func() {
|
||||
cfg, source, err := loadCommandBotConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("loadCommandBotConfig err: %v", err)
|
||||
}
|
||||
if cfg != nil {
|
||||
t.Fatalf("expected nil config, got %+v", cfg)
|
||||
}
|
||||
if source != "" {
|
||||
t.Fatalf("source = %q, want empty", source)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoadCommandBotConfig_SkipsEmptyConfigChannel(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
// Only chat_id present, no bot_token → should return nil.
|
||||
dao.Mdb.Create(&mdb.Setting{Group: "system", Key: "system.telegram_chat_id", Value: "987654321", Type: "string"})
|
||||
_ = data.ReloadSettings()
|
||||
|
||||
cfg, source, err := loadCommandBotConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("loadCommandBotConfig err: %v", err)
|
||||
}
|
||||
if cfg != nil {
|
||||
t.Fatalf("expected nil config when bot_token is absent, got %+v", cfg)
|
||||
}
|
||||
if source != "" {
|
||||
t.Fatalf("source = %q, want empty", source)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadCommandBotConfig_SkipsInvalidAndUsesNextValid(t *testing.T) {
|
||||
cleanup := testutil.SetupTestDatabases(t)
|
||||
defer cleanup()
|
||||
|
||||
// bot_token present but chat_id is not a valid int → should return error.
|
||||
dao.Mdb.Create(&mdb.Setting{Group: "system", Key: "system.telegram_bot_token", Value: "db-token", Type: "string"})
|
||||
dao.Mdb.Create(&mdb.Setting{Group: "system", Key: "system.telegram_chat_id", Value: "not-a-number", Type: "string"})
|
||||
_ = data.ReloadSettings()
|
||||
|
||||
cfg, _, err := loadCommandBotConfig()
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid chat_id, got nil")
|
||||
}
|
||||
if cfg != nil {
|
||||
t.Fatalf("expected nil config on parse error, got %+v", cfg)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user