fix: normalize Yumi gift challenge rewards
This commit is contained in:
parent
489aa40a50
commit
5cc47b90f6
@ -4,12 +4,15 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"chatapp3-golang/internal/integration"
|
||||
"chatapp3-golang/internal/model"
|
||||
"chatapp3-golang/internal/utils"
|
||||
|
||||
@ -607,8 +610,9 @@ func (s *Service) buildRewardSnapshots(ctx context.Context, activity model.YumiG
|
||||
})
|
||||
for index, item := range detail.RewardConfigList {
|
||||
rewardConfigID := int64(item.ID)
|
||||
if rewardConfigID <= 0 || strings.TrimSpace(item.Type) == "" || int64(item.Quantity) <= 0 {
|
||||
return nil, NewAppError(http.StatusBadRequest, "invalid_reward_item", fmt.Sprintf("reward group %d contains an invalid item", groupID))
|
||||
normalizedItem, normalizeErr := normalizeFrozenRewardItem(groupID, index, item)
|
||||
if normalizeErr != nil {
|
||||
return nil, normalizeErr
|
||||
}
|
||||
key := fmt.Sprintf("%d:%d", groupID, rewardConfigID)
|
||||
if _, exists := seen[key]; exists {
|
||||
@ -626,8 +630,8 @@ func (s *Service) buildRewardSnapshots(ctx context.Context, activity model.YumiG
|
||||
displayName := truncate(firstNonBlank(item.Name, item.BadgeName, item.Remark), 500)
|
||||
rows = append(rows, model.YumiGiftChallengeRewardSnapshot{
|
||||
ID: id, ActivityID: activity.ID, ResourceGroupID: groupID, RewardConfigID: rewardConfigID,
|
||||
RewardType: strings.ToUpper(strings.TrimSpace(item.Type)), DetailType: strings.TrimSpace(item.DetailType),
|
||||
Content: strings.TrimSpace(item.Content), Quantity: int64(item.Quantity), SortOrder: sortOrder,
|
||||
RewardType: normalizedItem.rewardType, DetailType: normalizedItem.detailType,
|
||||
Content: normalizedItem.content, Quantity: normalizedItem.quantity, SortOrder: sortOrder,
|
||||
Remark: strings.TrimSpace(item.Remark), Cover: strings.TrimSpace(item.Cover),
|
||||
SourceURL: strings.TrimSpace(item.SourceURL), DisplayName: displayName, CreateTime: now,
|
||||
})
|
||||
@ -639,6 +643,71 @@ func (s *Service) buildRewardSnapshots(ctx context.Context, activity model.YumiG
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
type frozenRewardItem struct {
|
||||
rewardType string
|
||||
detailType string
|
||||
content string
|
||||
quantity int64
|
||||
}
|
||||
|
||||
func normalizeFrozenRewardItem(groupID int64, index int, item integration.RewardGroupItem) (frozenRewardItem, error) {
|
||||
result := frozenRewardItem{
|
||||
rewardType: strings.ToUpper(strings.TrimSpace(item.Type)),
|
||||
detailType: strings.TrimSpace(item.DetailType),
|
||||
content: strings.TrimSpace(item.Content),
|
||||
quantity: int64(item.Quantity),
|
||||
}
|
||||
itemLabel := fmt.Sprintf("reward group %d item %d (id=%d, type=%s, quantity=%d)",
|
||||
groupID, index+1, int64(item.ID), result.rewardType, result.quantity)
|
||||
if int64(item.ID) <= 0 {
|
||||
return frozenRewardItem{}, NewAppError(http.StatusBadRequest, "invalid_reward_item", itemLabel+" has an invalid id")
|
||||
}
|
||||
if result.rewardType == "" {
|
||||
return frozenRewardItem{}, NewAppError(http.StatusBadRequest, "invalid_reward_item", itemLabel+" has an empty type")
|
||||
}
|
||||
|
||||
// 奖励组详情为了展示会把原始 PROPS 改写成 AVATAR_FRAME/RIDE 等子类型,
|
||||
// 但冻结发奖接口只按基础类型分流;这里还原 PROPS,同时保留子类型用于展示和通知。
|
||||
switch result.rewardType {
|
||||
case "AVATAR_FRAME", "RIDE", "NOBLE_VIP", "THEME", "LAYOUT", "CHAT_BUBBLE",
|
||||
"FLOAT_PICTURE", "DATA_CARD", "VIP_EFFECT_IMAGE", "RED_PACKET":
|
||||
if result.detailType == "" || strings.EqualFold(result.detailType, "PROPS") {
|
||||
result.detailType = result.rewardType
|
||||
}
|
||||
result.rewardType = "PROPS"
|
||||
case "ROOM_BADGE", "HONOR_ACTIVITY":
|
||||
if result.detailType == "" || strings.EqualFold(result.detailType, "BADGE") {
|
||||
result.detailType = result.rewardType
|
||||
}
|
||||
result.rewardType = "BADGE"
|
||||
}
|
||||
|
||||
if result.quantity < 0 || result.quantity > math.MaxInt32 {
|
||||
return frozenRewardItem{}, NewAppError(http.StatusBadRequest, "invalid_reward_item", itemLabel+" has an out-of-range quantity")
|
||||
}
|
||||
// 所有当前可发奖类型的 content 都是正整数资源 ID 或整数币值。启用时先拒绝空值、
|
||||
// 非数字和零值,避免活动完成后才在 Java 发奖链路留下 UNKNOWN 记录。
|
||||
contentNumber, contentOK := new(big.Int).SetString(result.content, 10)
|
||||
if !contentOK || contentNumber.Sign() <= 0 {
|
||||
return frozenRewardItem{}, NewAppError(http.StatusBadRequest, "invalid_reward_item", itemLabel+" has invalid content")
|
||||
}
|
||||
|
||||
switch result.rewardType {
|
||||
case "GOLD", "DIAMOND":
|
||||
// 币值由 content 承载,旧奖励组按契约把 quantity 保存为 0;不能把币值复制到
|
||||
// quantity,否则既破坏冻结事实,也会与 Java 实际按 content 发币的逻辑不一致。
|
||||
case "BADGE":
|
||||
// quantity=0 是 Java 的永久徽章语义,正数才表示临时徽章天数。
|
||||
case "PROPS", "GIFT", "EMOJI", "FRAGMENTS", "CUSTOMIZE", "PROP_COUPON":
|
||||
if result.quantity == 0 {
|
||||
return frozenRewardItem{}, NewAppError(http.StatusBadRequest, "invalid_reward_item", itemLabel+" requires a positive quantity")
|
||||
}
|
||||
default:
|
||||
return frozenRewardItem{}, NewAppError(http.StatusBadRequest, "unsupported_reward_item", itemLabel+" is not supported by the reward delivery service")
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func firstNonBlank(values ...string) string {
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user