修改礼物tab接口
This commit is contained in:
parent
9040b4b161
commit
5000076365
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
- 礼物 Tab 基础配置入口是 `GET /api/v1/gift-tabs`,不需要 `room_id`,只返回后台启用的 Tab 配置。
|
- 礼物 Tab 基础配置入口是 `GET /api/v1/gift-tabs`,不需要 `room_id`,只返回后台启用的 Tab 配置。
|
||||||
- `GET /api/v1/gift-tabs` 不按礼物数量过滤;只要后台启用了 Tab,即使该 Tab 下当前没有礼物也必须返回给 App 展示。
|
- `GET /api/v1/gift-tabs` 不按礼物数量过滤;只要后台启用了 Tab,即使该 Tab 下当前没有礼物也必须返回给 App 展示。
|
||||||
|
- `GET /api/v1/gift-tabs` 会按 Tab 返回当前 active 礼物列表,App 可以用它提前预加载礼物资源;无礼物的 Tab 返回 `gifts: []`。
|
||||||
- 房间送礼面板入口是 `GET /api/v1/rooms/{room_id}/gift-panel`,返回当前房间可送礼物、可收礼人、金币余额和房间内可展示 Tab。
|
- 房间送礼面板入口是 `GET /api/v1/rooms/{room_id}/gift-panel`,返回当前房间可送礼物、可收礼人、金币余额和房间内可展示 Tab。
|
||||||
- `GET /api/v1/gift-tabs` 不能替代 `GET /api/v1/rooms/{room_id}/gift-panel`;App 真正送礼前必须以房间面板返回的数据为准。
|
- `GET /api/v1/gift-tabs` 不能替代 `GET /api/v1/rooms/{room_id}/gift-panel`;App 真正送礼前必须以房间面板返回的数据为准。
|
||||||
- 送礼只调用 `POST /api/v1/rooms/gift/send`。
|
- 送礼只调用 `POST /api/v1/rooms/gift/send`。
|
||||||
@ -33,6 +34,12 @@ GET /api/v1/gift-tabs
|
|||||||
X-App-Code: lalu
|
X-App-Code: lalu
|
||||||
```
|
```
|
||||||
|
|
||||||
|
查询参数:
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `region_id` | int64 | 否 | 不传时预加载全部 active 礼物;传入时只返回 GLOBAL 和该区域可用礼物。 |
|
||||||
|
|
||||||
成功响应:
|
成功响应:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@ -52,7 +59,24 @@ X-App-Code: lalu
|
|||||||
"order": 10,
|
"order": 10,
|
||||||
"sort_order": 10,
|
"sort_order": 10,
|
||||||
"created_at_ms": 1710000000000,
|
"created_at_ms": 1710000000000,
|
||||||
"updated_at_ms": 1710000000000
|
"updated_at_ms": 1710000000000,
|
||||||
|
"gifts": [
|
||||||
|
{
|
||||||
|
"gift_id": "rose",
|
||||||
|
"resource_id": 11,
|
||||||
|
"gift_type_code": "normal",
|
||||||
|
"name": "Rose",
|
||||||
|
"coin_price": 100,
|
||||||
|
"resource": {
|
||||||
|
"resource_id": 11,
|
||||||
|
"resource_code": "gift_rose",
|
||||||
|
"resource_type": "gift",
|
||||||
|
"name": "Rose",
|
||||||
|
"status": "active",
|
||||||
|
"asset_url": "https://cdn.example/rose.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"total": 1
|
"total": 1
|
||||||
@ -74,6 +98,7 @@ X-App-Code: lalu
|
|||||||
| `sort_order` | int | 后台配置排序值。 |
|
| `sort_order` | int | 后台配置排序值。 |
|
||||||
| `created_at_ms` | int64 | 创建时间,Unix epoch milliseconds。 |
|
| `created_at_ms` | int64 | 创建时间,Unix epoch milliseconds。 |
|
||||||
| `updated_at_ms` | int64 | 更新时间,Unix epoch milliseconds。 |
|
| `updated_at_ms` | int64 | 更新时间,Unix epoch milliseconds。 |
|
||||||
|
| `gifts` | array | 当前 Tab 下的 active 礼物列表;没有礼物时返回空数组。 |
|
||||||
|
|
||||||
## 获取礼物面板
|
## 获取礼物面板
|
||||||
|
|
||||||
|
|||||||
@ -1904,9 +1904,16 @@ paths:
|
|||||||
- resources
|
- resources
|
||||||
summary: App 礼物 Tab 配置列表
|
summary: App 礼物 Tab 配置列表
|
||||||
operationId: listGiftTabs
|
operationId: listGiftTabs
|
||||||
|
parameters:
|
||||||
|
- name: region_id
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: 不传时预加载全部 active 礼物;传入时只返回 GLOBAL 和该区域可用礼物。
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: 返回后台启用的礼物 Tab 配置;不按礼物数量过滤,即使 Tab 下当前没有礼物也返回。
|
description: 返回后台启用的礼物 Tab 配置和当前 active 礼物;不按礼物数量过滤 Tab,即使 Tab 下当前没有礼物也返回 gifts 空数组。
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/GiftTabListEnvelope"
|
$ref: "#/definitions/GiftTabListEnvelope"
|
||||||
"502":
|
"502":
|
||||||
@ -2580,6 +2587,11 @@ definitions:
|
|||||||
updated_at_ms:
|
updated_at_ms:
|
||||||
type: integer
|
type: integer
|
||||||
format: int64
|
format: int64
|
||||||
|
gifts:
|
||||||
|
type: array
|
||||||
|
description: 当前 Tab 下的 active 礼物列表;没有礼物时返回空数组。
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/GiftConfigData"
|
||||||
DeletePushTokenData:
|
DeletePushTokenData:
|
||||||
type: object
|
type: object
|
||||||
required:
|
required:
|
||||||
|
|||||||
@ -84,7 +84,7 @@
|
|||||||
| GET | `/api/v1/resources` | resources | `listResources` | App 资源列表 |
|
| GET | `/api/v1/resources` | resources | `listResources` | App 资源列表 |
|
||||||
| GET | `/api/v1/resource-groups/{group_id}` | resources | `getResourceGroup` | App 资源组详情 |
|
| GET | `/api/v1/resource-groups/{group_id}` | resources | `getResourceGroup` | App 资源组详情 |
|
||||||
| GET | `/api/v1/gifts` | resources | `listGifts` | App 礼物列表 |
|
| GET | `/api/v1/gifts` | resources | `listGifts` | App 礼物列表 |
|
||||||
| GET | `/api/v1/gift-tabs` | resources | `listGiftTabs` | App 礼物 Tab 配置列表,不依赖房间 |
|
| GET | `/api/v1/gift-tabs` | resources | `listGiftTabs` | App 礼物 Tab 配置和礼物预加载列表,不依赖房间 |
|
||||||
| GET | `/api/v1/users/me/resources` | resources | `listMyResources` | 我的资源权益 |
|
| GET | `/api/v1/users/me/resources` | resources | `listMyResources` | 我的资源权益 |
|
||||||
| POST | `/api/v1/users/me/resources/{resource_id}/equip` | resources | `equipMyResource` | 佩戴我的资源 |
|
| POST | `/api/v1/users/me/resources/{resource_id}/equip` | resources | `equipMyResource` | 佩戴我的资源 |
|
||||||
| GET | `/api/v1/messages/tabs` | messages | `listMessageTabs` | 消息 tab 分区摘要 |
|
| GET | `/api/v1/messages/tabs` | messages | `listMessageTabs` | 消息 tab 分区摘要 |
|
||||||
|
|||||||
@ -92,16 +92,17 @@ type giftConfigData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type giftTabData struct {
|
type giftTabData struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
GiftTypeCode string `json:"gift_type_code"`
|
GiftTypeCode string `json:"gift_type_code"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
TabKey string `json:"tab_key"`
|
TabKey string `json:"tab_key"`
|
||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Order int32 `json:"order"`
|
Order int32 `json:"order"`
|
||||||
SortOrder int32 `json:"sort_order"`
|
SortOrder int32 `json:"sort_order"`
|
||||||
CreatedAtMS int64 `json:"created_at_ms"`
|
CreatedAtMS int64 `json:"created_at_ms"`
|
||||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||||
|
Gifts []giftConfigData `json:"gifts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type emojiPackData struct {
|
type emojiPackData struct {
|
||||||
@ -236,6 +237,11 @@ func (h *Handler) listGiftTabs(writer http.ResponseWriter, request *http.Request
|
|||||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
regionID, filterRegion, ok := optionalNonNegativeInt64Query(request, "region_id")
|
||||||
|
if !ok {
|
||||||
|
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||||
|
return
|
||||||
|
}
|
||||||
resp, err := h.walletClient.ListGiftTypeConfigs(request.Context(), &walletv1.ListGiftTypeConfigsRequest{
|
resp, err := h.walletClient.ListGiftTypeConfigs(request.Context(), &walletv1.ListGiftTypeConfigsRequest{
|
||||||
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
||||||
AppCode: appcode.FromContext(request.Context()),
|
AppCode: appcode.FromContext(request.Context()),
|
||||||
@ -245,13 +251,52 @@ func (h *Handler) listGiftTabs(writer http.ResponseWriter, request *http.Request
|
|||||||
httpkit.WriteRPCError(writer, request, err)
|
httpkit.WriteRPCError(writer, request, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
gifts, err := h.listAllActiveGifts(request, regionID, filterRegion)
|
||||||
|
if err != nil {
|
||||||
|
httpkit.WriteRPCError(writer, request, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
giftsByType := make(map[string][]giftConfigData, len(gifts))
|
||||||
|
for _, item := range gifts {
|
||||||
|
giftsByType[item.GiftTypeCode] = append(giftsByType[item.GiftTypeCode], item)
|
||||||
|
}
|
||||||
items := make([]giftTabData, 0, len(resp.GetGiftTypes()))
|
items := make([]giftTabData, 0, len(resp.GetGiftTypes()))
|
||||||
for _, item := range resp.GetGiftTypes() {
|
for _, item := range resp.GetGiftTypes() {
|
||||||
items = append(items, giftTabFromProto(item))
|
tab := giftTabFromProto(item)
|
||||||
|
tab.Gifts = giftsByType[tab.GiftTypeCode]
|
||||||
|
if tab.Gifts == nil {
|
||||||
|
tab.Gifts = []giftConfigData{}
|
||||||
|
}
|
||||||
|
items = append(items, tab)
|
||||||
}
|
}
|
||||||
httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
|
httpkit.WriteOK(writer, request, map[string]any{"items": items, "total": len(items)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *Handler) listAllActiveGifts(request *http.Request, regionID int64, filterRegion bool) ([]giftConfigData, error) {
|
||||||
|
const pageSize int32 = 100
|
||||||
|
items := make([]giftConfigData, 0, pageSize)
|
||||||
|
for page := int32(1); ; page++ {
|
||||||
|
resp, err := h.walletClient.ListGiftConfigs(request.Context(), &walletv1.ListGiftConfigsRequest{
|
||||||
|
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
||||||
|
AppCode: appcode.FromContext(request.Context()),
|
||||||
|
Page: page,
|
||||||
|
PageSize: pageSize,
|
||||||
|
ActiveOnly: true,
|
||||||
|
RegionId: regionID,
|
||||||
|
FilterRegion: filterRegion,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, gift := range resp.GetGifts() {
|
||||||
|
items = append(items, giftFromProto(gift))
|
||||||
|
}
|
||||||
|
if len(resp.GetGifts()) == 0 || int64(len(items)) >= resp.GetTotal() {
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (h *Handler) listEmojiPacks(writer http.ResponseWriter, request *http.Request) {
|
func (h *Handler) listEmojiPacks(writer http.ResponseWriter, request *http.Request) {
|
||||||
if h.walletClient == nil {
|
if h.walletClient == nil {
|
||||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||||
@ -460,6 +505,7 @@ func giftTabFromProto(item *walletv1.GiftTypeConfig) giftTabData {
|
|||||||
SortOrder: item.GetSortOrder(),
|
SortOrder: item.GetSortOrder(),
|
||||||
CreatedAtMS: item.GetCreatedAtMs(),
|
CreatedAtMS: item.GetCreatedAtMs(),
|
||||||
UpdatedAtMS: item.GetUpdatedAtMs(),
|
UpdatedAtMS: item.GetUpdatedAtMs(),
|
||||||
|
Gifts: []giftConfigData{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -369,6 +369,7 @@ type fakeWalletClient struct {
|
|||||||
lastGetResourceGroup *walletv1.GetResourceGroupRequest
|
lastGetResourceGroup *walletv1.GetResourceGroupRequest
|
||||||
resourceGroupsByID map[int64]*walletv1.ResourceGroup
|
resourceGroupsByID map[int64]*walletv1.ResourceGroup
|
||||||
lastListGiftConfigs *walletv1.ListGiftConfigsRequest
|
lastListGiftConfigs *walletv1.ListGiftConfigsRequest
|
||||||
|
listGiftConfigsResp *walletv1.ListGiftConfigsResponse
|
||||||
lastListGiftTypes *walletv1.ListGiftTypeConfigsRequest
|
lastListGiftTypes *walletv1.ListGiftTypeConfigsRequest
|
||||||
listGiftTypesResp *walletv1.ListGiftTypeConfigsResponse
|
listGiftTypesResp *walletv1.ListGiftTypeConfigsResponse
|
||||||
lastGrantResource *walletv1.GrantResourceRequest
|
lastGrantResource *walletv1.GrantResourceRequest
|
||||||
@ -1153,6 +1154,12 @@ func (f *fakeWalletClient) GetResourceGroup(_ context.Context, req *walletv1.Get
|
|||||||
|
|
||||||
func (f *fakeWalletClient) ListGiftConfigs(_ context.Context, req *walletv1.ListGiftConfigsRequest) (*walletv1.ListGiftConfigsResponse, error) {
|
func (f *fakeWalletClient) ListGiftConfigs(_ context.Context, req *walletv1.ListGiftConfigsRequest) (*walletv1.ListGiftConfigsResponse, error) {
|
||||||
f.lastListGiftConfigs = req
|
f.lastListGiftConfigs = req
|
||||||
|
if f.err != nil {
|
||||||
|
return nil, f.err
|
||||||
|
}
|
||||||
|
if f.listGiftConfigsResp != nil {
|
||||||
|
return f.listGiftConfigsResp, nil
|
||||||
|
}
|
||||||
return &walletv1.ListGiftConfigsResponse{}, nil
|
return &walletv1.ListGiftConfigsResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3252,6 +3259,26 @@ func TestListEmojiPacksFiltersRegionAndReturnsAssets(t *testing.T) {
|
|||||||
|
|
||||||
func TestListGiftTabsReturnsActiveTypeConfigs(t *testing.T) {
|
func TestListGiftTabsReturnsActiveTypeConfigs(t *testing.T) {
|
||||||
walletClient := &fakeWalletClient{
|
walletClient := &fakeWalletClient{
|
||||||
|
listGiftConfigsResp: &walletv1.ListGiftConfigsResponse{
|
||||||
|
Gifts: []*walletv1.GiftConfig{
|
||||||
|
{
|
||||||
|
GiftId: "rose",
|
||||||
|
ResourceId: 11,
|
||||||
|
Status: "active",
|
||||||
|
Name: "Rose",
|
||||||
|
GiftTypeCode: "normal",
|
||||||
|
CoinPrice: 100,
|
||||||
|
Resource: &walletv1.Resource{
|
||||||
|
ResourceId: 11,
|
||||||
|
ResourceCode: "gift_rose",
|
||||||
|
ResourceType: "gift",
|
||||||
|
Name: "Rose",
|
||||||
|
Status: "active",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Total: 1,
|
||||||
|
},
|
||||||
listGiftTypesResp: &walletv1.ListGiftTypeConfigsResponse{
|
listGiftTypesResp: &walletv1.ListGiftTypeConfigsResponse{
|
||||||
GiftTypes: []*walletv1.GiftTypeConfig{
|
GiftTypes: []*walletv1.GiftTypeConfig{
|
||||||
{
|
{
|
||||||
@ -3296,6 +3323,11 @@ func TestListGiftTabsReturnsActiveTypeConfigs(t *testing.T) {
|
|||||||
Order int32 `json:"order"`
|
Order int32 `json:"order"`
|
||||||
SortOrder int32 `json:"sort_order"`
|
SortOrder int32 `json:"sort_order"`
|
||||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||||
|
Gifts []struct {
|
||||||
|
GiftID string `json:"gift_id"`
|
||||||
|
GiftTypeCode string `json:"gift_type_code"`
|
||||||
|
CoinPrice int64 `json:"coin_price"`
|
||||||
|
} `json:"gifts"`
|
||||||
} `json:"items"`
|
} `json:"items"`
|
||||||
Total int `json:"total"`
|
Total int `json:"total"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
@ -3306,8 +3338,8 @@ func TestListGiftTabsReturnsActiveTypeConfigs(t *testing.T) {
|
|||||||
if walletClient.lastListGiftTypes == nil || walletClient.lastListGiftTypes.GetAppCode() != "lalu" || !walletClient.lastListGiftTypes.GetActiveOnly() {
|
if walletClient.lastListGiftTypes == nil || walletClient.lastListGiftTypes.GetAppCode() != "lalu" || !walletClient.lastListGiftTypes.GetActiveOnly() {
|
||||||
t.Fatalf("gift tabs request mismatch: %+v", walletClient.lastListGiftTypes)
|
t.Fatalf("gift tabs request mismatch: %+v", walletClient.lastListGiftTypes)
|
||||||
}
|
}
|
||||||
if walletClient.lastListGiftConfigs != nil {
|
if walletClient.lastListGiftConfigs == nil || walletClient.lastListGiftConfigs.GetAppCode() != "lalu" || !walletClient.lastListGiftConfigs.GetActiveOnly() || walletClient.lastListGiftConfigs.GetPageSize() != 100 || walletClient.lastListGiftConfigs.GetFilterRegion() {
|
||||||
t.Fatalf("gift tabs must not filter tabs by gift configs: %+v", walletClient.lastListGiftConfigs)
|
t.Fatalf("gift tabs gift preload request mismatch: %+v", walletClient.lastListGiftConfigs)
|
||||||
}
|
}
|
||||||
if envelope.Code != httpkit.CodeOK || envelope.Data.Total != 2 || len(envelope.Data.Items) != 2 {
|
if envelope.Code != httpkit.CodeOK || envelope.Data.Total != 2 || len(envelope.Data.Items) != 2 {
|
||||||
t.Fatalf("gift tabs envelope mismatch: %+v", envelope)
|
t.Fatalf("gift tabs envelope mismatch: %+v", envelope)
|
||||||
@ -3315,6 +3347,12 @@ func TestListGiftTabsReturnsActiveTypeConfigs(t *testing.T) {
|
|||||||
if envelope.Data.Items[0].Key != "normal" || envelope.Data.Items[0].GiftTypeCode != "normal" || envelope.Data.Items[0].Name != "普通礼物" || envelope.Data.Items[0].Label != "Gift" || envelope.Data.Items[0].TabKey != "Gift" || envelope.Data.Items[0].Order != 10 || envelope.Data.Items[0].SortOrder != 10 || envelope.Data.Items[0].UpdatedAtMS != 1_700_000_000_100 {
|
if envelope.Data.Items[0].Key != "normal" || envelope.Data.Items[0].GiftTypeCode != "normal" || envelope.Data.Items[0].Name != "普通礼物" || envelope.Data.Items[0].Label != "Gift" || envelope.Data.Items[0].TabKey != "Gift" || envelope.Data.Items[0].Order != 10 || envelope.Data.Items[0].SortOrder != 10 || envelope.Data.Items[0].UpdatedAtMS != 1_700_000_000_100 {
|
||||||
t.Fatalf("first gift tab mismatch: %+v", envelope.Data.Items[0])
|
t.Fatalf("first gift tab mismatch: %+v", envelope.Data.Items[0])
|
||||||
}
|
}
|
||||||
|
if len(envelope.Data.Items[0].Gifts) != 1 || envelope.Data.Items[0].Gifts[0].GiftID != "rose" || envelope.Data.Items[0].Gifts[0].GiftTypeCode != "normal" || envelope.Data.Items[0].Gifts[0].CoinPrice != 100 {
|
||||||
|
t.Fatalf("first gift tab gifts mismatch: %+v", envelope.Data.Items[0].Gifts)
|
||||||
|
}
|
||||||
|
if len(envelope.Data.Items[1].Gifts) != 0 {
|
||||||
|
t.Fatalf("empty gift tab must still be returned with empty gifts: %+v", envelope.Data.Items[1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessageReadAllReadAndDeleteRoutes(t *testing.T) {
|
func TestMessageReadAllReadAndDeleteRoutes(t *testing.T) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user