fix: enrich weekly star reward groups

This commit is contained in:
zhx 2026-06-08 19:22:58 +08:00
parent 0adef2ee26
commit 3ed3f85837
2 changed files with 205 additions and 7 deletions

View File

@ -32,8 +32,9 @@ type weeklyStarGiftData struct {
}
type weeklyStarRewardData struct {
RankNo int32 `json:"rank_no"`
ResourceGroupID int64 `json:"resource_group_id"`
RankNo int32 `json:"rank_no"`
ResourceGroupID int64 `json:"resource_group_id"`
ResourceGroup *achievementResourceGroupData `json:"resource_group,omitempty"`
}
type weeklyStarEntryData struct {
@ -98,8 +99,12 @@ func (h *Handler) getWeeklyStarCurrent(writer http.ResponseWriter, request *http
return
}
users := h.resolveWeeklyStarUsers(request, weeklyStarUserIDs(resp.GetTopEntries(), resp.GetMyEntry()))
resourceGroups, ok := h.resolveWeeklyStarResourceGroups(writer, request, resp.GetCycle())
if !ok {
return
}
data := weeklyStarCurrentData{
Cycle: weeklyStarCycleFromProto(resp.GetCycle()),
Cycle: weeklyStarCycleFromProto(resp.GetCycle(), resourceGroups),
TopEntries: weeklyStarEntriesFromProto(resp.GetTopEntries(), users),
ServerTimeMS: resp.GetServerTimeMs(),
}
@ -133,8 +138,12 @@ func (h *Handler) listWeeklyStarLeaderboard(writer http.ResponseWriter, request
return
}
users := h.resolveWeeklyStarUsers(request, weeklyStarUserIDs(resp.GetEntries(), nil))
resourceGroups, ok := h.resolveWeeklyStarResourceGroups(writer, request, resp.GetCycle())
if !ok {
return
}
httpkit.WriteOK(writer, request, weeklyStarLeaderboardData{
Cycle: weeklyStarCycleFromProto(resp.GetCycle()),
Cycle: weeklyStarCycleFromProto(resp.GetCycle(), resourceGroups),
Entries: weeklyStarEntriesFromProto(resp.GetEntries(), users),
NextPageToken: resp.GetNextPageToken(),
Total: resp.GetTotal(),
@ -162,14 +171,20 @@ func (h *Handler) listWeeklyStarHistory(writer http.ResponseWriter, request *htt
return
}
ids := make([]int64, 0)
cycleItems := make([]*activityv1.WeeklyStarCycle, 0, len(resp.GetCycles()))
for _, cycle := range resp.GetCycles() {
cycleItems = append(cycleItems, cycle.GetCycle())
ids = append(ids, weeklyStarUserIDs(cycle.GetTopEntries(), nil)...)
}
users := h.resolveWeeklyStarUsers(request, ids)
resourceGroups, ok := h.resolveWeeklyStarResourceGroups(writer, request, cycleItems...)
if !ok {
return
}
cycles := make([]weeklyStarHistoryCycleData, 0, len(resp.GetCycles()))
for _, item := range resp.GetCycles() {
cycles = append(cycles, weeklyStarHistoryCycleData{
Cycle: weeklyStarCycleFromProto(item.GetCycle()),
Cycle: weeklyStarCycleFromProto(item.GetCycle(), resourceGroups),
TopEntries: weeklyStarEntriesFromProto(item.GetTopEntries(), users),
})
}
@ -213,7 +228,13 @@ func (h *Handler) resolveWeeklyStarUsers(request *http.Request, ids []int64) map
return users
}
func weeklyStarCycleFromProto(item *activityv1.WeeklyStarCycle) *weeklyStarCycleData {
func (h *Handler) resolveWeeklyStarResourceGroups(writer http.ResponseWriter, request *http.Request, cycles ...*activityv1.WeeklyStarCycle) (map[int64]achievementResourceGroupData, bool) {
// 周星周期只存奖励资源组 ID资源名称、类型、素材和数量仍由 wallet-service 资源库统一维护。
// gateway 在 App 出口补齐这些展示字段,避免 activity-service 复制资源库快照,也让后台改资源组后 App 读取保持一致。
return h.resolveAchievementResourceGroups(writer, request, weeklyStarResourceGroupIDs(cycles...))
}
func weeklyStarCycleFromProto(item *activityv1.WeeklyStarCycle, resourceGroups map[int64]achievementResourceGroupData) *weeklyStarCycleData {
if item == nil {
return nil
}
@ -235,11 +256,25 @@ func weeklyStarCycleFromProto(item *activityv1.WeeklyStarCycle) *weeklyStarCycle
cycle.Gifts = append(cycle.Gifts, weeklyStarGiftData{GiftID: gift.GetGiftId(), SortOrder: gift.GetSortOrder()})
}
for _, reward := range item.GetRewards() {
cycle.Rewards = append(cycle.Rewards, weeklyStarRewardData{RankNo: reward.GetRankNo(), ResourceGroupID: reward.GetResourceGroupId()})
rewardData := weeklyStarRewardData{RankNo: reward.GetRankNo(), ResourceGroupID: reward.GetResourceGroupId()}
if group, ok := resourceGroups[reward.GetResourceGroupId()]; ok {
rewardData.ResourceGroup = &group
}
cycle.Rewards = append(cycle.Rewards, rewardData)
}
return cycle
}
func weeklyStarResourceGroupIDs(cycles ...*activityv1.WeeklyStarCycle) []int64 {
ids := make([]int64, 0)
for _, cycle := range cycles {
for _, reward := range cycle.GetRewards() {
ids = append(ids, reward.GetResourceGroupId())
}
}
return ids
}
func weeklyStarEntriesFromProto(items []*activityv1.WeeklyStarLeaderboardEntry, users map[int64]weeklyStarUserData) []weeklyStarEntryData {
entries := make([]weeklyStarEntryData, 0, len(items))
for _, item := range items {

View File

@ -552,6 +552,16 @@ type fakeAchievementClient struct {
err error
}
type fakeWeeklyStarClient struct {
lastCurrent *activityv1.GetWeeklyStarCurrentRequest
currentResp *activityv1.GetWeeklyStarCurrentResponse
lastLeaderboard *activityv1.ListWeeklyStarLeaderboardRequest
leaderboardResp *activityv1.ListWeeklyStarLeaderboardResponse
lastHistory *activityv1.ListWeeklyStarHistoryRequest
historyResp *activityv1.ListWeeklyStarHistoryResponse
err error
}
type fakeBroadcastClient struct {
lastRemove *activityv1.RemoveRegionBroadcastMemberRequest
err error
@ -1084,6 +1094,39 @@ func (f *fakeAchievementClient) SetBadgeDisplay(_ context.Context, req *activity
return &activityv1.SetBadgeDisplayResponse{}, nil
}
func (f *fakeWeeklyStarClient) GetWeeklyStarCurrent(_ context.Context, req *activityv1.GetWeeklyStarCurrentRequest) (*activityv1.GetWeeklyStarCurrentResponse, error) {
f.lastCurrent = req
if f.err != nil {
return nil, f.err
}
if f.currentResp != nil {
return f.currentResp, nil
}
return &activityv1.GetWeeklyStarCurrentResponse{}, nil
}
func (f *fakeWeeklyStarClient) ListWeeklyStarLeaderboard(_ context.Context, req *activityv1.ListWeeklyStarLeaderboardRequest) (*activityv1.ListWeeklyStarLeaderboardResponse, error) {
f.lastLeaderboard = req
if f.err != nil {
return nil, f.err
}
if f.leaderboardResp != nil {
return f.leaderboardResp, nil
}
return &activityv1.ListWeeklyStarLeaderboardResponse{}, nil
}
func (f *fakeWeeklyStarClient) ListWeeklyStarHistory(_ context.Context, req *activityv1.ListWeeklyStarHistoryRequest) (*activityv1.ListWeeklyStarHistoryResponse, error) {
f.lastHistory = req
if f.err != nil {
return nil, f.err
}
if f.historyResp != nil {
return f.historyResp, nil
}
return &activityv1.ListWeeklyStarHistoryResponse{}, nil
}
func (f *fakeBroadcastClient) RemoveRegionBroadcastMember(_ context.Context, req *activityv1.RemoveRegionBroadcastMemberRequest) (*activityv1.RemoveRegionBroadcastMemberResponse, error) {
f.lastRemove = req
if f.err != nil {
@ -4669,6 +4712,126 @@ func TestAchievementAndBadgeRoutesEmbedResourceMaterials(t *testing.T) {
}
}
func TestWeeklyStarCurrentEmbedsRewardResourceGroups(t *testing.T) {
rewardResource := &walletv1.Resource{
ResourceId: 8101,
ResourceCode: "weekly_star_frame",
ResourceType: "avatar_frame",
Name: "Weekly Star Frame",
Status: "active",
Grantable: true,
GrantStrategy: "new_entitlement",
UsageScopes: []string{"profile"},
AssetUrl: "https://cdn.example/weekly-star-frame.png",
SortOrder: 10,
}
weeklyStarClient := &fakeWeeklyStarClient{
currentResp: &activityv1.GetWeeklyStarCurrentResponse{
Cycle: &activityv1.WeeklyStarCycle{
CycleId: "wstar-test",
ActivityCode: "weekly_star",
RegionId: 686,
Title: "Weekly Star",
Status: "active",
StartMs: 1778256000000,
EndMs: 1778860800000,
Gifts: []*activityv1.WeeklyStarGift{{GiftId: "308", SortOrder: 1}},
Rewards: []*activityv1.WeeklyStarReward{{RankNo: 1, ResourceGroupId: 23}},
},
TopEntries: []*activityv1.WeeklyStarLeaderboardEntry{{RankNo: 1, UserId: 88, Score: 120000, FirstScoredAtMs: 1778256001000, LastScoredAtMs: 1778256002000}},
ServerTimeMs: 1778256003000,
},
}
walletClient := &fakeWalletClient{
resourceGroupsByID: map[int64]*walletv1.ResourceGroup{23: {
GroupId: 23,
GroupCode: "weekly_star_top1",
Name: "Top 1 Resource Group",
Status: "active",
Items: []*walletv1.ResourceGroupItem{{
GroupItemId: 101,
ItemType: "resource",
ResourceId: rewardResource.GetResourceId(),
Resource: rewardResource,
Quantity: 1,
DurationMs: 7 * 24 * int64(time.Hour/time.Millisecond),
SortOrder: 10,
}},
}},
}
userClient := &fakeUserProfileClient{
usersByID: map[int64]*userv1.User{
42: {UserId: 42, DisplayUserId: "163000", Username: "viewer", RegionId: 686},
88: {UserId: 88, DisplayUserId: "163088", Username: "weekly_ranker", Avatar: "https://cdn.example/ranker.png", RegionId: 686},
},
}
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, userClient)
handler.SetWeeklyStarClient(weeklyStarClient)
handler.SetWalletClient(walletClient)
router := handler.Routes(auth.NewVerifier("secret"))
request := httptest.NewRequest(http.MethodGet, "/api/v1/activities/weekly-star/current", nil)
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("weekly star status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
}
var envelope struct {
Code string `json:"code"`
Data struct {
Cycle struct {
Rewards []struct {
ResourceGroupID int64 `json:"resource_group_id"`
ResourceGroup struct {
GroupID int64 `json:"group_id"`
Name string `json:"name"`
Items []struct {
ResourceID int64 `json:"resource_id"`
Resource struct {
ResourceID int64 `json:"resource_id"`
ResourceType string `json:"resource_type"`
Name string `json:"name"`
AssetURL string `json:"asset_url"`
} `json:"resource"`
Quantity int64 `json:"quantity"`
DurationMS int64 `json:"duration_ms"`
} `json:"items"`
} `json:"resource_group"`
} `json:"rewards"`
} `json:"cycle"`
TopEntries []struct {
User struct {
Username string `json:"username"`
} `json:"user"`
} `json:"top_entries"`
} `json:"data"`
}
if err := json.NewDecoder(recorder.Body).Decode(&envelope); err != nil {
t.Fatalf("decode weekly star response failed: %v", err)
}
if weeklyStarClient.lastCurrent == nil || weeklyStarClient.lastCurrent.GetUserId() != 42 || weeklyStarClient.lastCurrent.GetRegionId() != 686 {
t.Fatalf("weekly star request mismatch: %+v", weeklyStarClient.lastCurrent)
}
if envelope.Code != httpkit.CodeOK || len(envelope.Data.Cycle.Rewards) != 1 {
t.Fatalf("weekly star response missing rewards: %+v", envelope)
}
firstReward := envelope.Data.Cycle.Rewards[0]
if firstReward.ResourceGroupID != 23 || firstReward.ResourceGroup.GroupID != 23 || firstReward.ResourceGroup.Name != "Top 1 Resource Group" {
t.Fatalf("weekly star reward group mismatch: %+v", firstReward)
}
if len(firstReward.ResourceGroup.Items) != 1 {
t.Fatalf("weekly star reward group items mismatch: %+v", firstReward.ResourceGroup)
}
firstItem := firstReward.ResourceGroup.Items[0]
if firstItem.ResourceID != 8101 || firstItem.Quantity != 1 || firstItem.DurationMS == 0 || firstItem.Resource.ResourceID != 8101 || firstItem.Resource.ResourceType != "avatar_frame" || firstItem.Resource.Name != "Weekly Star Frame" || firstItem.Resource.AssetURL == "" {
t.Fatalf("weekly star reward group item must embed resource material: %+v", firstItem)
}
if len(envelope.Data.TopEntries) != 1 || envelope.Data.TopEntries[0].User.Username != "weekly_ranker" {
t.Fatalf("weekly star top entry user mismatch: %+v", envelope.Data.TopEntries)
}
}
func TestAppearanceAggregatesEquippedResourcesAndBadges(t *testing.T) {
frameResource := &walletv1.Resource{
ResourceId: 8101,