Files
MeBox/internal/service/telegram_mgo_compat_test.go
T
2026-06-16 23:08:14 +08:00

279 lines
10 KiB
Go

package service
import (
"strings"
"testing"
"time"
"go.uber.org/zap"
"github.com/ShukeBta/MediaStationGo/internal/config"
"github.com/ShukeBta/MediaStationGo/internal/model"
)
func TestMgoBotUserManagementAndAuditCommands(t *testing.T) {
ctx := t.Context()
repos, bot := newBotTestService(t)
if err := repos.User.Create(ctx, &model.User{Username: "root", PasswordHash: "x", Role: "admin", IsActive: true}); err != nil {
t.Fatal(err)
}
channel := &model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: `{"admin_user_ids":"9401"}`}
msg := &TelegramMessage{From: TelegramUser{ID: 9401, Username: "admin"}, Chat: TelegramChat{ID: 9401, Type: "private"}}
reply, err := bot.executeCommand(ctx, channel, msg, "/ucr viewer secret-pass 30")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "已创建用户") {
t.Fatalf("expected user creation, got %q", reply.Text)
}
viewer, err := repos.User.FindByUsername(ctx, "viewer")
if err != nil || viewer == nil {
t.Fatalf("viewer should exist: %v", err)
}
if err := repos.UserDevice.Create(ctx, &model.UserDevice{
UserID: viewer.ID,
DeviceID: "dev-abc",
DeviceName: "Windows PC",
Client: "Infuse",
LastIP: "1.2.3.4",
FirstSeenAt: time.Now(),
LastSeenAt: time.Now(),
}); err != nil {
t.Fatal(err)
}
for _, tc := range []struct {
command string
want string
}{
{"/uinfo viewer", "用户信息"},
{"/userip viewer", "1.2.3.4"},
{"/auditip 1.2.3", "viewer"},
{"/auditdevice Windows", "viewer"},
{"/auditclient Infuse", "viewer"},
{"/udeviceid dev-abc", "viewer"},
} {
t.Run(tc.command, func(t *testing.T) {
reply, err := bot.executeCommand(ctx, channel, msg, tc.command)
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, tc.want) {
t.Fatalf("%s expected %q in %q", tc.command, tc.want, reply.Text)
}
})
}
}
func TestMgoBotBatchAndPermissionCommands(t *testing.T) {
ctx := t.Context()
repos, bot := newBotTestService(t)
channel := &model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: `{"admin_user_ids":"9501"}`}
msg := &TelegramMessage{From: TelegramUser{ID: 9501, Username: "admin"}, Chat: TelegramChat{ID: 9501, Type: "private"}}
users := []*model.User{
{Username: "root", PasswordHash: "x", Role: "admin", IsActive: true},
{Username: "viewer1", PasswordHash: "x", Role: "user", IsActive: true},
{Username: "viewer2", PasswordHash: "x", Role: "user", IsActive: true},
{Username: "viewer3", PasswordHash: "x", Role: "user", IsActive: true},
}
for _, user := range users {
if err := repos.User.Create(ctx, user); err != nil {
t.Fatal(err)
}
if user.Role != "admin" && user.Username != "viewer3" {
if err := repos.Permission.Create(ctx, DefaultPermissions(user.ID)); err != nil {
t.Fatal(err)
}
}
}
reply, err := bot.executeCommand(ctx, channel, msg, "/renewall 7 confirm")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "批量续期完成") {
t.Fatalf("expected renewall success, got %q", reply.Text)
}
renewed, _ := repos.User.FindByUsername(ctx, "viewer1")
if renewed.ExpiredAt == nil {
t.Fatal("renewall should set expiry for normal users")
}
if reply, err = bot.executeCommand(ctx, channel, msg, "/embylibs_blockall"); err != nil || !strings.Contains(reply.Text, "关闭媒体播放权限") {
t.Fatalf("expected blockall success, reply=%q err=%v", reply.Text, err)
}
perm, _ := repos.Permission.FindByUserID(ctx, users[1].ID)
if perm == nil || perm.CanPlayMedia {
t.Fatal("embylibs_blockall should disable media playback for normal users")
}
perm, _ = repos.Permission.FindByUserID(ctx, users[3].ID)
if perm == nil || perm.CanPlayMedia {
t.Fatal("embylibs_blockall should create disabled media playback permissions when missing")
}
if reply, err = bot.executeCommand(ctx, channel, msg, "/embylibs_unblockall"); err != nil || !strings.Contains(reply.Text, "开启媒体播放权限") {
t.Fatalf("expected unblockall success, reply=%q err=%v", reply.Text, err)
}
perm, _ = repos.Permission.FindByUserID(ctx, users[1].ID)
if perm == nil || !perm.CanPlayMedia {
t.Fatal("embylibs_unblockall should enable media playback for normal users")
}
if reply, err = bot.executeCommand(ctx, channel, msg, "/banall confirm"); err != nil || !strings.Contains(reply.Text, "已禁用普通用户") {
t.Fatalf("expected banall success, reply=%q err=%v", reply.Text, err)
}
banned, _ := repos.User.FindByUsername(ctx, "viewer2")
if banned.IsActive {
t.Fatal("banall should disable normal users")
}
if reply, err = bot.executeCommand(ctx, channel, msg, "/unbanall confirm"); err != nil || !strings.Contains(reply.Text, "已解禁普通用户") {
t.Fatalf("expected unbanall success, reply=%q err=%v", reply.Text, err)
}
unbanned, _ := repos.User.FindByUsername(ctx, "viewer2")
if !unbanned.IsActive {
t.Fatal("unbanall should re-enable normal users")
}
}
func TestMgoBotSyncExpiryAndBotAdminCommands(t *testing.T) {
ctx := t.Context()
repos, bot := newBotTestService(t)
channel := &model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: `{"admin_user_ids":"9601"}`}
if err := repos.NotifyChannel.Create(ctx, channel); err != nil {
t.Fatal(err)
}
msg := &TelegramMessage{From: TelegramUser{ID: 9601, Username: "admin"}, Chat: TelegramChat{ID: 9601, Type: "private"}}
past := time.Now().Add(-24 * time.Hour)
if err := repos.User.Create(ctx, &model.User{Username: "expired", PasswordHash: "x", Role: "user", IsActive: true, ExpiredAt: &past}); err != nil {
t.Fatal(err)
}
reply, err := bot.executeCommand(ctx, channel, msg, "/syncunbound")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "expired") {
t.Fatalf("syncunbound should list unbound users, got %q", reply.Text)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/check_ex")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "expired") {
t.Fatalf("check_ex should list expired users, got %q", reply.Text)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/proadmin 9602")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "已添加") {
t.Fatalf("proadmin should update channel config, got %q", reply.Text)
}
updated, _ := repos.NotifyChannel.FindByID(ctx, channel.ID)
cfg := bot.telegramChannelConfig(updated)
if !strings.Contains(cfg["admin_user_ids"], "9602") {
t.Fatalf("expected admin ids to include 9602, got %#v", cfg)
}
}
func TestMgoBotProtectedUsersAndBackupCommands(t *testing.T) {
ctx := t.Context()
repos, bot := newBotTestService(t)
cfg := &config.Config{}
cfg.App.DataDir = t.TempDir()
bot.SetBackupService(NewBackupService(cfg, zap.NewNop(), repos.DB))
channel := &model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: `{"admin_user_ids":"9701"}`}
msg := &TelegramMessage{From: TelegramUser{ID: 9701, Username: "admin"}, Chat: TelegramChat{ID: 9701, Type: "private"}}
users := []*model.User{
{Username: "root", PasswordHash: "x", Role: "admin", IsActive: true},
{Username: "safe", PasswordHash: "x", Role: "user", IsActive: true},
{Username: "normal", PasswordHash: "x", Role: "user", IsActive: true},
}
for _, user := range users {
if err := repos.User.Create(ctx, user); err != nil {
t.Fatal(err)
}
}
reply, err := bot.executeCommand(ctx, channel, msg, "/prouser safe")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "已加入保护名单") {
t.Fatalf("expected protect success, got %q", reply.Text)
}
if reason := bot.protectReason(ctx, users[1].ID); !strings.Contains(reason, "保护名单") {
t.Fatalf("protected user should have protect reason, got %q", reason)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/banall confirm")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "已禁用普通用户") {
t.Fatalf("expected banall success, got %q", reply.Text)
}
protected, _ := repos.User.FindByUsername(ctx, "safe")
normal, _ := repos.User.FindByUsername(ctx, "normal")
if !protected.IsActive {
t.Fatal("protected user should not be disabled by banall")
}
if normal.IsActive {
t.Fatal("normal user should be disabled by banall")
}
reply, err = bot.executeCommand(ctx, channel, msg, "/revuser safe")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "已移出保护名单") {
t.Fatalf("expected unprotect success, got %q", reply.Text)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/backup_db")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "数据库备份完成") {
t.Fatalf("backup_db should create backup, got %q", reply.Text)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/restore_from_db list")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "mediastation_") {
t.Fatalf("restore list should show backup, got %q", reply.Text)
}
}
func TestMgoBotAliasesAndSyncGroupGuards(t *testing.T) {
ctx := t.Context()
repos, bot := newBotTestService(t)
if err := repos.User.Create(ctx, &model.User{Username: "root", PasswordHash: "x", Role: "admin", IsActive: true}); err != nil {
t.Fatal(err)
}
channel := &model.NotifyChannel{Name: "Telegram", Type: "telegram", Enabled: true, Config: `{"admin_user_ids":"9801"}`}
msg := &TelegramMessage{From: TelegramUser{ID: 9801, Username: "admin"}, Chat: TelegramChat{ID: 9801, Type: "private"}}
reply, err := bot.executeCommand(ctx, channel, msg, "/kk")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "用户管理") {
t.Fatalf("/kk should map to user management, got %q", reply.Text)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/syncgroupm")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "未配置可校验成员") {
t.Fatalf("syncgroupm should explain missing group config, got %q", reply.Text)
}
reply, err = bot.executeCommand(ctx, channel, msg, "/kick_not_emby")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(reply.Text, "无法枚举全部群成员") {
t.Fatalf("kick_not_emby should explain Telegram limitation, got %q", reply.Text)
}
}