fix: allow robot init active appearance resources

This commit is contained in:
zhx 2026-06-18 10:35:13 +08:00
parent 0d111d9a88
commit c93a30f3db
5 changed files with 76 additions and 14 deletions

View File

@ -90,20 +90,19 @@ func (h *Handler) loadRobotAppearanceCatalog(ctx context.Context, requestID stri
func (h *Handler) listRobotResources(ctx context.Context, requestID string, appCode string, resourceType string) ([]*walletv1.Resource, error) {
resp, err := h.wallet.ListResources(ctx, &walletv1.ListResourcesRequest{
RequestId: requestID,
AppCode: appCode,
ResourceType: resourceType,
Page: 1,
PageSize: 500,
ActiveOnly: true,
ManagerGrantOnly: true,
RequestId: requestID,
AppCode: appCode,
ResourceType: resourceType,
Page: 1,
PageSize: 500,
ActiveOnly: true,
})
if err != nil {
return nil, fmt.Errorf("读取机器人%s资源失败: %w", resourceType, err)
}
resources := make([]*walletv1.Resource, 0, len(resp.GetResources()))
for _, item := range resp.GetResources() {
if item != nil && item.GetResourceId() > 0 && item.GetStatus() == "active" && item.GetManagerGrantEnabled() {
if item != nil && item.GetResourceId() > 0 && item.GetStatus() == "active" {
resources = append(resources, item)
}
}

View File

@ -65,20 +65,22 @@ func (c *fakeRobotGameClient) RegisterDiceRobots(_ context.Context, req *gamev1.
type fakeRobotWalletClient struct {
walletclient.Client
grants []string
equips []int64
listRequests []*walletv1.ListResourcesRequest
grants []string
equips []int64
}
func (c *fakeRobotWalletClient) ListResources(_ context.Context, req *walletv1.ListResourcesRequest) (*walletv1.ListResourcesResponse, error) {
c.listRequests = append(c.listRequests, req)
switch req.GetResourceType() {
case "avatar_frame":
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 101, ResourceType: "avatar_frame", Status: "active", ManagerGrantEnabled: true}}}, nil
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 101, ResourceType: "avatar_frame", Status: "active", ManagerGrantEnabled: false}}}, nil
case "vehicle":
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 201, ResourceType: "vehicle", Status: "active", ManagerGrantEnabled: true}}}, nil
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{{ResourceId: 201, ResourceType: "vehicle", Status: "active", ManagerGrantEnabled: false}}}, nil
case "badge":
return &walletv1.ListResourcesResponse{Resources: []*walletv1.Resource{
{ResourceId: 301, ResourceType: "badge", Status: "active", ManagerGrantEnabled: true, MetadataJson: `{"badge_form":"strip"}`},
{ResourceId: 302, ResourceType: "badge", Status: "active", ManagerGrantEnabled: true, MetadataJson: `{"badge_form":"tile"}`},
{ResourceId: 301, ResourceType: "badge", Status: "active", ManagerGrantEnabled: false, MetadataJson: `{"badge_form":"strip"}`},
{ResourceId: 302, ResourceType: "badge", Status: "active", ManagerGrantEnabled: false, MetadataJson: `{"badge_form":"tile"}`},
}}, nil
default:
return &walletv1.ListResourcesResponse{}, nil
@ -158,6 +160,14 @@ func TestGenerateDiceRobotsUsesLikeiProfiles(t *testing.T) {
if len(wallets.grants) != 8 || len(wallets.equips) != 4 || len(activities.levels) != 4 {
t.Fatalf("robot appearance init mismatch: grants=%d equips=%d levels=%d", len(wallets.grants), len(wallets.equips), len(activities.levels))
}
for _, req := range wallets.listRequests {
if req.GetManagerGrantOnly() {
t.Fatalf("robot appearance resource list must not require manager grant: %+v", req)
}
if !req.GetActiveOnly() {
t.Fatalf("robot appearance resource list must still require active resources: %+v", req)
}
}
for _, level := range activities.levels {
if level.GetLevel() < robotMinDisplayLevel || level.GetLevel() > robotMaxDisplayLevel {
t.Fatalf("robot level out of range: %+v", level)

View File

@ -37,6 +37,7 @@ const (
GrantSourceGrowthLevel = "growth_level"
GrantSourceAchievement = "achievement"
GrantSourceResourceShop = "resource_shop"
GrantSourceGameRobotInit = "game_robot_init"
GrantStatusDone = "succeeded"
ResultWalletCredit = "wallet_credit"
ResultEntitlement = "entitlement"

View File

@ -3863,6 +3863,46 @@ func TestManagerCenterResourceGrantFiltersAndRechecksSwitch(t *testing.T) {
}
}
// TestGameRobotInitCanGrantActiveNonGrantableResource 锁定机器人初始化发放不跟随人工发放开关;
// 只要资源仍处于 active就允许机器人账号获得装扮避免运营库没有打开 grantable 时生成失败。
func TestGameRobotInitCanGrantActiveNonGrantableResource(t *testing.T) {
repository := mysqltest.NewRepository(t)
svc := walletservice.New(repository)
ctx := context.Background()
resource, err := svc.CreateResource(ctx, resourcedomain.ResourceCommand{
ResourceCode: "robot_init_frame",
ResourceType: resourcedomain.TypeAvatarFrame,
Name: "Robot Init Frame",
Status: resourcedomain.StatusActive,
Grantable: false,
ManagerGrantEnabled: false,
GrantStrategy: resourcedomain.GrantStrategySetActiveFlag,
UsageScopes: []string{"profile"},
OperatorUserID: 90001,
})
if err != nil {
t.Fatalf("create robot init resource failed: %v", err)
}
grant, err := svc.GrantResource(ctx, resourcedomain.GrantResourceCommand{
CommandID: "cmd-game-robot-init-non-grantable",
TargetUserID: 43009,
ResourceID: resource.ResourceID,
Quantity: 1,
DurationMS: int64(24 * time.Hour / time.Millisecond),
Reason: "game robot init",
OperatorUserID: 91001,
GrantSource: resourcedomain.GrantSourceGameRobotInit,
})
if err != nil {
t.Fatalf("game robot init should grant active non-grantable resource: %v", err)
}
if grant.GrantSource != resourcedomain.GrantSourceGameRobotInit || len(grant.Items) != 1 {
t.Fatalf("game robot init grant response mismatch: %+v", grant)
}
}
func TestCreateResourceRejectsDuplicateResourceCodeAsConflict(t *testing.T) {
repository := mysqltest.NewRepository(t)
svc := walletservice.New(repository)

View File

@ -3561,6 +3561,18 @@ func validateGrantResourceGroupCommand(command resourcedomain.GrantResourceGroup
}
func validateGrantableResourceForSource(resource resourcedomain.Resource, grantSource string) error {
// 机器人初始化只从后台维护的 active 装扮池里挑展示资源;它不是人工管理端发放,
// 因此不继承 grantable 和 manager_grant_enabled 这两个运营开关,避免测试/运营库
// 已上架资源因为未显式打开管理端发放而无法生成机器人。
if grantSource == resourcedomain.GrantSourceGameRobotInit {
if resource.Status != resourcedomain.StatusActive {
return xerr.New(xerr.Conflict, "resource is disabled")
}
if resourcedomain.IsWalletCredit(resource) && !resourcedomain.IsCoinResource(resource) {
return xerr.New(xerr.InvalidArgument, "wallet credit resource must be coin")
}
return nil
}
if err := validateGrantableResource(resource); err != nil {
return err
}