feat: 友链/书库/移动端导航/排行榜等多模块功能
新增模块: - 友链(friendlink)后端处理 + 前端管理页与友链板 - 书库(library):导入、章节、封面、阅读页、横竖版自适应 AdaptiveCoverSlot - 顶栏导航(header_nav)配置与 MobileTabBar/MobileRailDrawers 移动端抽屉 - 排行榜 service 测试、站点页面测试、时间线发布(timeline_release) 其它改动: - 后端 handlers/services 全量小幅调整 - 前端组件、库函数、URL/品牌/站点 URL 工具更新 - Lightbox 图片、MdEntries 条目卡、coverColor 派生色相等前端能力
This commit is contained in:
67
backend/service/leaderboard_test.go
Normal file
67
backend/service/leaderboard_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/freefire/jiang13-bbs/model"
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// 贡献值口径:earnedPoints 只累计窗口内正入账积分(排除 bounty_refund),
|
||||
// 支出、悬赏退回、封禁用户、窗口外入账均不计
|
||||
func TestEarnedPointsWindowAndExclusions(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatalf("open sqlite: %v", err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.User{}, &model.PointLedger{}); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
weekAgo := now.AddDate(0, 0, -7)
|
||||
users := []*model.User{
|
||||
{Username: "earner", Password: "x"},
|
||||
{Username: "refund_only", Password: "x"},
|
||||
{Username: "banned", Password: "x", Banned: true},
|
||||
{Username: "old_earner", Password: "x"},
|
||||
}
|
||||
for _, u := range users {
|
||||
if err := db.Create(u).Error; err != nil {
|
||||
t.Fatalf("seed user %s: %v", u.Username, err)
|
||||
}
|
||||
}
|
||||
a, d := users[0].ID, users[3].ID
|
||||
ledgers := []model.PointLedger{
|
||||
{UserID: a, Delta: 5, Reason: model.PointReasonCheckin, Balance: 5, CreatedAt: now},
|
||||
{UserID: a, Delta: 3, Reason: model.PointReasonReplyReward, Balance: 8, CreatedAt: now},
|
||||
{UserID: a, Delta: 2, Reason: model.PointReasonStreakBonus, Balance: 10, CreatedAt: now.Add(-time.Hour)},
|
||||
{UserID: a, Delta: -3, Reason: model.PointReasonUnlockPost, Balance: 7, CreatedAt: now}, // 支出不计
|
||||
{UserID: users[1].ID, Delta: 8, Reason: model.PointReasonBountyRefund, Balance: 8, CreatedAt: now}, // 退回不计
|
||||
{UserID: users[2].ID, Delta: 5, Reason: model.PointReasonCheckin, Balance: 5, CreatedAt: now}, // 封禁不计
|
||||
{UserID: d, Delta: 5, Reason: model.PointReasonCheckin, Balance: 5, CreatedAt: weekAgo.Add(-time.Hour)}, // 窗口外
|
||||
}
|
||||
if err := db.Create(&ledgers).Error; err != nil {
|
||||
t.Fatalf("seed ledgers: %v", err)
|
||||
}
|
||||
|
||||
s := NewLeaderboardService(db)
|
||||
from := weekAgo
|
||||
pts, err := s.earnedPoints(&from, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("earnedPoints: %v", err)
|
||||
}
|
||||
if len(pts) != 1 || pts[a] != 10 {
|
||||
t.Fatalf("周窗内应仅 earner 计 10 分,got %v", pts)
|
||||
}
|
||||
|
||||
all, err := s.earnedPoints(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("earnedPoints(all): %v", err)
|
||||
}
|
||||
if len(all) != 2 || all[a] != 10 || all[d] != 5 {
|
||||
t.Fatalf("全窗口:earner=10、old_earner=5,退回/封禁不计,got %v", all)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user