This commit is contained in:
Yvan
2026-09-22 20:20:23 +08:00
parent bf33e87d72
commit ceaea78b0f
42 changed files with 2845 additions and 154 deletions
+4 -4
View File
@@ -23,7 +23,7 @@ type categoryPO struct {
Name string `gorm:"size:40;uniqueIndex"`
Icon string `gorm:"size:500"`
Sort int `gorm:"default:0;index"`
Enabled bool `gorm:"default:true;index"`
Enabled bool `gorm:"index"`
}
func (categoryPO) TableName() string { return "live_categories" }
@@ -41,7 +41,7 @@ type roomPO struct {
AnchorUserID uint `gorm:"index"`
StreamURL string `gorm:"size:1000"`
ReplayURL string `gorm:"size:1000"`
Enabled bool `gorm:"default:true;index"`
Enabled bool `gorm:"index"`
}
func (roomPO) TableName() string { return "live_rooms" }
@@ -171,7 +171,7 @@ func (r *catalogRepo) DeleteCategory(ctx context.Context, id uint) error {
func (r *catalogRepo) ListRooms(ctx context.Context, filter bizlive.RoomFilter, options bizlive.ListOptions) ([]*bizlive.Room, int64, error) {
db := r.db(ctx)
query := db.Model(&roomPO{}).
Joins("LEFT JOIN live_categories ON live_categories.id = live_rooms.category_id").
Joins("LEFT JOIN live_categories ON live_categories.id = live_rooms.category_id AND live_categories.deleted_at IS NULL").
Joins("LEFT JOIN sys_users ON sys_users.id = live_rooms.anchor_user_id AND sys_users.deleted_at IS NULL")
if filter.Name != "" {
value := "%" + filter.Name + "%"
@@ -219,7 +219,7 @@ func (r *catalogRepo) GetRoom(ctx context.Context, id uint) (*bizlive.Room, erro
var row roomRow
err := r.db(ctx).Model(&roomPO{}).
Select("live_rooms.*, live_categories.name AS category_name, COALESCE(NULLIF(sys_users.nick_name, ''), sys_users.username) AS anchor_name, sys_users.header_img AS anchor_avatar").
Joins("LEFT JOIN live_categories ON live_categories.id = live_rooms.category_id").
Joins("LEFT JOIN live_categories ON live_categories.id = live_rooms.category_id AND live_categories.deleted_at IS NULL").
Joins("LEFT JOIN sys_users ON sys_users.id = live_rooms.anchor_user_id AND sys_users.deleted_at IS NULL").
Where("live_rooms.id = ?", id).Scan(&row).Error
if err != nil {
+158 -2
View File
@@ -2,6 +2,7 @@ package live
import (
"context"
"errors"
"testing"
bizlive "kra/internal/biz/live"
@@ -44,7 +45,7 @@ func TestCatalogRepoScansCategoryAndRoomFields(t *testing.T) {
if err := db.Create(&category).Error; err != nil {
t.Fatal(err)
}
room := roomPO{Name: "Test Room", CategoryID: category.ID, CoverURL: "cover.png", Intro: "intro", Sort: 2, AnchorUserID: 2, Enabled: true}
room := roomPO{Name: "Test Room", CategoryID: category.ID, CoverURL: "cover.png", Intro: "intro", Sort: 2, AnchorUserID: 2, ReplayURL: "https://example.test/replay.mp4", Enabled: true}
if err := db.Create(&room).Error; err != nil {
t.Fatal(err)
}
@@ -70,7 +71,7 @@ func TestCatalogRepoScansCategoryAndRoomFields(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if got.ID != room.ID || got.Name != room.Name || got.AnchorUserID != 2 || got.AnchorAvatar != "avatar.png" || !got.Enabled {
if got.ID != room.ID || got.Name != room.Name || got.AnchorUserID != 2 || got.AnchorAvatar != "avatar.png" || got.ReplayURL != room.ReplayURL || !got.Enabled {
t.Fatalf("room get scan result=%+v", got)
}
}
@@ -110,3 +111,158 @@ func TestCatalogRepoFiltersRoomsByCategoryEnabled(t *testing.T) {
t.Fatalf("enabled-category rooms total=%d rooms=%+v", total, rooms)
}
}
func TestCatalogRepoPublicVisibilityFiltersBeforePagination(t *testing.T) {
db := openCatalogTestDB(t)
if err := db.Exec(`INSERT INTO sys_users(id, username, nick_name, header_img) VALUES (2, 'anchor', 'Anchor', 'avatar.png')`).Error; err != nil {
t.Fatal(err)
}
visible := categoryPO{Name: "Visible", Enabled: true}
disabled := categoryPO{Name: "Disabled", Enabled: true}
deleted := categoryPO{Name: "Deleted", Enabled: true}
for _, category := range []*categoryPO{&visible, &disabled, &deleted} {
if err := db.Create(category).Error; err != nil {
t.Fatal(err)
}
}
if err := db.Model(&disabled).Update("enabled", false).Error; err != nil {
t.Fatal(err)
}
if err := db.Delete(&deleted).Error; err != nil {
t.Fatal(err)
}
rooms := []*roomPO{
{Name: "Offline Room", CategoryID: visible.ID, Enabled: true},
{Name: "Replay Room", CategoryID: visible.ID, Enabled: true, ReplayURL: "https://example.test/replay.mp4"},
{Name: "Disabled Room", CategoryID: visible.ID, Enabled: true},
{Name: "Disabled Category", CategoryID: disabled.ID, Enabled: true},
{Name: "Deleted Category", CategoryID: deleted.ID, Enabled: true},
{Name: "Missing Category", CategoryID: 999, Enabled: true},
{Name: "Deleted Room", CategoryID: visible.ID, Enabled: true},
}
for _, room := range rooms {
room.AnchorUserID = 2
room.CoverURL = "cover.png"
if err := db.Create(room).Error; err != nil {
t.Fatal(err)
}
}
if err := db.Model(rooms[2]).Update("enabled", false).Error; err != nil {
t.Fatal(err)
}
if err := db.Delete(rooms[6]).Error; err != nil {
t.Fatal(err)
}
repo := NewCatalogRepo(catalogTestProvider{db: db})
enabled := true
filter := bizlive.RoomFilter{Enabled: &enabled, CategoryEnabled: &enabled}
items, total, err := repo.ListRooms(context.Background(), filter, bizlive.ListOptions{Limit: 10, OrderBy: "id_asc"})
if err != nil {
t.Fatal(err)
}
if total != 2 || len(items) != 2 || items[0].ID != rooms[0].ID || items[1].ID != rooms[1].ID {
t.Fatalf("public candidates total=%d items=%+v", total, items)
}
if items[1].ReplayURL != rooms[1].ReplayURL {
t.Fatalf("replay URL=%q, want %q", items[1].ReplayURL, rooms[1].ReplayURL)
}
items, total, err = repo.ListRooms(context.Background(), filter, bizlive.ListOptions{Offset: 1, Limit: 1, OrderBy: "id_asc"})
if err != nil {
t.Fatal(err)
}
if total != 2 || len(items) != 1 || items[0].ID != rooms[1].ID {
t.Fatalf("public page total=%d items=%+v", total, items)
}
filter.CategoryID = disabled.ID
items, total, err = repo.ListRooms(context.Background(), filter, bizlive.ListOptions{Limit: 10})
if err != nil {
t.Fatal(err)
}
if total != 0 || len(items) != 0 {
t.Fatalf("disabled category returned rooms: total=%d items=%+v", total, items)
}
}
func TestCatalogRepoCreatePreservesExplicitEnabledState(t *testing.T) {
db := openCatalogTestDB(t)
// Existing installations still have the old database-level default.
for _, table := range []string{"live_categories", "live_rooms"} {
if err := db.Table(table).AutoMigrate(&struct {
Enabled bool `gorm:"default:true"`
}{}); err != nil {
t.Fatal(err)
}
}
if err := db.Exec(`INSERT INTO sys_users(id, username, nick_name, header_img) VALUES (2, 'anchor', 'Anchor', 'avatar.png')`).Error; err != nil {
t.Fatal(err)
}
repo := NewCatalogRepo(catalogTestProvider{db: db})
ctx := context.Background()
for _, enabled := range []bool{false, true} {
name := "Disabled"
if enabled {
name = "Enabled"
}
t.Run(name+" category", func(t *testing.T) {
created, err := repo.CreateCategory(ctx, &bizlive.Category{Name: name, Enabled: enabled})
if err != nil {
t.Fatal(err)
}
if created.Enabled != enabled {
t.Fatalf("created category enabled=%v, want %v", created.Enabled, enabled)
}
reloaded, err := repo.GetCategory(ctx, created.ID)
if err != nil || reloaded.Enabled != enabled {
t.Fatalf("reloaded category=%+v error=%v, want enabled=%v", reloaded, err, enabled)
}
})
}
enabled := true
categories, total, err := repo.ListCategories(ctx, bizlive.CategoryFilter{Enabled: &enabled}, bizlive.ListOptions{Limit: 10})
if err != nil {
t.Fatal(err)
}
if total != 1 || len(categories) != 1 || categories[0].Name != "Enabled" {
t.Fatalf("public categories include a disabled new category: total=%d categories=%+v", total, categories)
}
categoryID := categories[0].ID
streams := bizlive.NewStreamUsecase(NewStreamRepo())
rooms := bizlive.NewRoomUsecase(repo, streams)
for _, enabled := range []bool{false, true} {
name := "Disabled"
if enabled {
name = "Enabled"
}
t.Run(name+" room", func(t *testing.T) {
created, err := repo.CreateRoom(ctx, &bizlive.Room{
Name: name, CategoryID: categoryID, AnchorUserID: 2,
CoverURL: "cover.png", ReplayURL: "https://example.test/replay.mp4", Enabled: enabled,
})
if err != nil {
t.Fatal(err)
}
if created.Enabled != enabled {
t.Fatalf("created room enabled=%v, want %v", created.Enabled, enabled)
}
reloaded, err := repo.GetRoom(ctx, created.ID)
if err != nil || reloaded.Enabled != enabled {
t.Fatalf("reloaded room=%+v error=%v, want enabled=%v", reloaded, err, enabled)
}
public, err := rooms.GetPublic(ctx, created.ID)
if enabled {
if err != nil || public.Status != bizlive.RoomStatusOffline {
t.Fatalf("enabled offline public room=%+v error=%v", public, err)
}
} else if public != nil || !errors.Is(err, bizlive.ErrRoomDisabled) {
t.Fatalf("disabled new room passed public/publisher authorization: room=%+v error=%v", public, err)
}
})
}
public, total, err := repo.ListRooms(ctx, bizlive.RoomFilter{Enabled: &enabled, CategoryEnabled: &enabled}, bizlive.ListOptions{Limit: 10})
if err != nil {
t.Fatal(err)
}
if total != 1 || len(public) != 1 || public[0].Name != "Enabled" {
t.Fatalf("public list includes a disabled new room: total=%d rooms=%+v", total, public)
}
}