增加用户的manager身份
This commit is contained in:
parent
245412ae95
commit
ad4a755998
@ -442,7 +442,7 @@ func (x *CoinSellerProfile) GetUpdatedAtMs() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UserRoleSummary 是 App 我的页和入口显隐使用的轻量角色摘要。
|
// UserRoleSummary 是 App 我的页和入口显隐使用的轻量角色摘要。
|
||||||
// 它把 host、Agency、BD 和币商身份收敛到一次 user-service RPC,避免 gateway 随角色扩张继续 fanout。
|
// 它把 host、Agency、manager、BD 和币商身份收敛到一次 user-service RPC,避免 gateway 随角色扩张继续 fanout。
|
||||||
type UserRoleSummary struct {
|
type UserRoleSummary struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
UserId int64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||||
@ -457,6 +457,7 @@ type UserRoleSummary struct {
|
|||||||
BdStatus string `protobuf:"bytes,10,opt,name=bd_status,json=bdStatus,proto3" json:"bd_status,omitempty"`
|
BdStatus string `protobuf:"bytes,10,opt,name=bd_status,json=bdStatus,proto3" json:"bd_status,omitempty"`
|
||||||
CoinSellerStatus string `protobuf:"bytes,11,opt,name=coin_seller_status,json=coinSellerStatus,proto3" json:"coin_seller_status,omitempty"`
|
CoinSellerStatus string `protobuf:"bytes,11,opt,name=coin_seller_status,json=coinSellerStatus,proto3" json:"coin_seller_status,omitempty"`
|
||||||
PendingRoleInvitations int64 `protobuf:"varint,12,opt,name=pending_role_invitations,json=pendingRoleInvitations,proto3" json:"pending_role_invitations,omitempty"`
|
PendingRoleInvitations int64 `protobuf:"varint,12,opt,name=pending_role_invitations,json=pendingRoleInvitations,proto3" json:"pending_role_invitations,omitempty"`
|
||||||
|
IsManager bool `protobuf:"varint,13,opt,name=is_manager,json=isManager,proto3" json:"is_manager,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
@ -575,6 +576,13 @@ func (x *UserRoleSummary) GetPendingRoleInvitations() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *UserRoleSummary) GetIsManager() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.IsManager
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// AgencyMembership 是 host 与 Agency 的有时效关系事实。
|
// AgencyMembership 是 host 与 Agency 的有时效关系事实。
|
||||||
type AgencyMembership struct {
|
type AgencyMembership struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
@ -3689,7 +3697,7 @@ const file_proto_user_v1_host_proto_rawDesc = "" +
|
|||||||
"\x13merchant_asset_type\x18\x03 \x01(\tR\x11merchantAssetType\x12+\n" +
|
"\x13merchant_asset_type\x18\x03 \x01(\tR\x11merchantAssetType\x12+\n" +
|
||||||
"\x12created_by_user_id\x18\x04 \x01(\x03R\x0fcreatedByUserId\x12\"\n" +
|
"\x12created_by_user_id\x18\x04 \x01(\x03R\x0fcreatedByUserId\x12\"\n" +
|
||||||
"\rcreated_at_ms\x18\x05 \x01(\x03R\vcreatedAtMs\x12\"\n" +
|
"\rcreated_at_ms\x18\x05 \x01(\x03R\vcreatedAtMs\x12\"\n" +
|
||||||
"\rupdated_at_ms\x18\x06 \x01(\x03R\vupdatedAtMs\"\x95\x03\n" +
|
"\rupdated_at_ms\x18\x06 \x01(\x03R\vupdatedAtMs\"\xb4\x03\n" +
|
||||||
"\x0fUserRoleSummary\x12\x17\n" +
|
"\x0fUserRoleSummary\x12\x17\n" +
|
||||||
"\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x17\n" +
|
"\auser_id\x18\x01 \x01(\x03R\x06userId\x12\x17\n" +
|
||||||
"\ais_host\x18\x02 \x01(\bR\x06isHost\x12\x1b\n" +
|
"\ais_host\x18\x02 \x01(\bR\x06isHost\x12\x1b\n" +
|
||||||
@ -3705,7 +3713,9 @@ const file_proto_user_v1_host_proto_rawDesc = "" +
|
|||||||
"\tbd_status\x18\n" +
|
"\tbd_status\x18\n" +
|
||||||
" \x01(\tR\bbdStatus\x12,\n" +
|
" \x01(\tR\bbdStatus\x12,\n" +
|
||||||
"\x12coin_seller_status\x18\v \x01(\tR\x10coinSellerStatus\x128\n" +
|
"\x12coin_seller_status\x18\v \x01(\tR\x10coinSellerStatus\x128\n" +
|
||||||
"\x18pending_role_invitations\x18\f \x01(\x03R\x16pendingRoleInvitations\"\xaa\x03\n" +
|
"\x18pending_role_invitations\x18\f \x01(\x03R\x16pendingRoleInvitations\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"is_manager\x18\r \x01(\bR\tisManager\"\xaa\x03\n" +
|
||||||
"\x10AgencyMembership\x12#\n" +
|
"\x10AgencyMembership\x12#\n" +
|
||||||
"\rmembership_id\x18\x01 \x01(\x03R\fmembershipId\x12\x1b\n" +
|
"\rmembership_id\x18\x01 \x01(\x03R\fmembershipId\x12\x1b\n" +
|
||||||
"\tagency_id\x18\x02 \x01(\x03R\bagencyId\x12 \n" +
|
"\tagency_id\x18\x02 \x01(\x03R\bagencyId\x12 \n" +
|
||||||
|
|||||||
@ -57,7 +57,7 @@ message CoinSellerProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UserRoleSummary 是 App 我的页和入口显隐使用的轻量角色摘要。
|
// UserRoleSummary 是 App 我的页和入口显隐使用的轻量角色摘要。
|
||||||
// 它把 host、Agency、BD 和币商身份收敛到一次 user-service RPC,避免 gateway 随角色扩张继续 fanout。
|
// 它把 host、Agency、manager、BD 和币商身份收敛到一次 user-service RPC,避免 gateway 随角色扩张继续 fanout。
|
||||||
message UserRoleSummary {
|
message UserRoleSummary {
|
||||||
int64 user_id = 1;
|
int64 user_id = 1;
|
||||||
bool is_host = 2;
|
bool is_host = 2;
|
||||||
@ -71,6 +71,7 @@ message UserRoleSummary {
|
|||||||
string bd_status = 10;
|
string bd_status = 10;
|
||||||
string coin_seller_status = 11;
|
string coin_seller_status = 11;
|
||||||
int64 pending_role_invitations = 12;
|
int64 pending_role_invitations = 12;
|
||||||
|
bool is_manager = 13;
|
||||||
}
|
}
|
||||||
|
|
||||||
// AgencyMembership 是 host 与 Agency 的有时效关系事实。
|
// AgencyMembership 是 host 与 Agency 的有时效关系事实。
|
||||||
|
|||||||
@ -2717,7 +2717,10 @@ definitions:
|
|||||||
description: 用户是否拥有 active host profile。
|
description: 用户是否拥有 active host profile。
|
||||||
is_agent:
|
is_agent:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 用户是否拥有 active agency owner 身份。
|
description: 用户是否拥有 Agency 入口身份;active Agency owner 或 Agency 来源主播都可能为 true。
|
||||||
|
is_manager:
|
||||||
|
type: boolean
|
||||||
|
description: 用户是否拥有经理中心身份;首版等价于 active Agency owner。
|
||||||
is_bd:
|
is_bd:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: 用户是否拥有 active BD 或 BD Leader 身份。
|
description: 用户是否拥有 active BD 或 BD Leader 身份。
|
||||||
@ -2732,6 +2735,7 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- is_host
|
- is_host
|
||||||
- is_agency
|
- is_agency
|
||||||
|
- is_manager
|
||||||
- is_bd
|
- is_bd
|
||||||
- is_bd_leader
|
- is_bd_leader
|
||||||
- is_coin_seller
|
- is_coin_seller
|
||||||
@ -2741,6 +2745,8 @@ definitions:
|
|||||||
type: boolean
|
type: boolean
|
||||||
is_agency:
|
is_agency:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
is_manager:
|
||||||
|
type: boolean
|
||||||
is_bd:
|
is_bd:
|
||||||
type: boolean
|
type: boolean
|
||||||
is_bd_leader:
|
is_bd_leader:
|
||||||
@ -3170,6 +3176,7 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
- host-center
|
- host-center
|
||||||
|
- manager-center
|
||||||
- bd-center
|
- bd-center
|
||||||
- bd-leader-center
|
- bd-leader-center
|
||||||
- agency-center
|
- agency-center
|
||||||
|
|||||||
@ -49,6 +49,7 @@ Authorization: Bearer <access_token>
|
|||||||
"roles": {
|
"roles": {
|
||||||
"is_host": true,
|
"is_host": true,
|
||||||
"is_agency": false,
|
"is_agency": false,
|
||||||
|
"is_manager": false,
|
||||||
"is_bd": false,
|
"is_bd": false,
|
||||||
"is_bd_leader": false,
|
"is_bd_leader": false,
|
||||||
"is_coin_seller": false,
|
"is_coin_seller": false,
|
||||||
@ -116,6 +117,7 @@ Authorization: Bearer <access_token>
|
|||||||
| `apply_host` | `roles.is_host == false` |
|
| `apply_host` | `roles.is_host == false` |
|
||||||
| `host_center` | `roles.is_host == true` |
|
| `host_center` | `roles.is_host == true` |
|
||||||
| `agency_center` | `roles.is_agency == true` |
|
| `agency_center` | `roles.is_agency == true` |
|
||||||
|
| `manager_center` | `roles.is_manager == true` |
|
||||||
| `bd_center` | `roles.is_bd == true` |
|
| `bd_center` | `roles.is_bd == true` |
|
||||||
| `bd_leader_center` | `roles.is_bd_leader == true` |
|
| `bd_leader_center` | `roles.is_bd_leader == true` |
|
||||||
| `coin_seller_center` | `roles.is_coin_seller == true` |
|
| `coin_seller_center` | `roles.is_coin_seller == true` |
|
||||||
|
|||||||
@ -247,12 +247,12 @@ func (s *Store) seedMenus() error {
|
|||||||
{ParentID: &gameID, Title: "游戏列表", Code: "game-list", Path: "/games", Icon: "sports_esports", PermissionCode: "game:view", Sort: 70, Visible: true},
|
{ParentID: &gameID, Title: "游戏列表", Code: "game-list", Path: "/games", Icon: "sports_esports", PermissionCode: "game:view", Sort: 70, Visible: true},
|
||||||
{ParentID: &geoID, Title: "国家管理", Code: "host-org-countries", Path: "/host/countries", Icon: "public", PermissionCode: "country:view", Sort: 70, Visible: true},
|
{ParentID: &geoID, Title: "国家管理", Code: "host-org-countries", Path: "/host/countries", Icon: "public", PermissionCode: "country:view", Sort: 70, Visible: true},
|
||||||
{ParentID: &geoID, Title: "区域管理", Code: "host-org-regions", Path: "/host/regions", Icon: "map", PermissionCode: "region:view", Sort: 71, Visible: true},
|
{ParentID: &geoID, Title: "区域管理", Code: "host-org-regions", Path: "/host/regions", Icon: "map", PermissionCode: "region:view", Sort: 71, Visible: true},
|
||||||
{ParentID: &hostOrgID, Title: "经理列表", Code: "host-org-managers", Path: "/host/managers", Icon: "users", PermissionCode: "agency:view", Sort: 80, Visible: true},
|
{ParentID: &hostOrgID, Title: "Manager列表", Code: "host-org-managers", Path: "/host/managers", Icon: "users", PermissionCode: "agency:view", Sort: 80, Visible: true},
|
||||||
{ParentID: &hostOrgID, Title: "Agency 列表", Code: "host-org-agencies", Path: "/host/agencies", Icon: "apartment", PermissionCode: "agency:view", Sort: 81, Visible: true},
|
{ParentID: &hostOrgID, Title: "Agency 列表", Code: "host-org-agencies", Path: "/host/agencies", Icon: "apartment", PermissionCode: "agency:view", Sort: 81, Visible: true},
|
||||||
{ParentID: &hostOrgID, Title: "BD Leader 列表", Code: "host-org-bd-leaders", Path: "/host/bd-leaders", Icon: "shield", PermissionCode: "bd:view", Sort: 82, Visible: true},
|
{ParentID: &hostOrgID, Title: "BD Leader 列表", Code: "host-org-bd-leaders", Path: "/host/bd-leaders", Icon: "shield", PermissionCode: "bd:view", Sort: 82, Visible: true},
|
||||||
{ParentID: &hostOrgID, Title: "BD 列表", Code: "host-org-bds", Path: "/host/bds", Icon: "team", PermissionCode: "bd:view", Sort: 83, Visible: true},
|
{ParentID: &hostOrgID, Title: "BD 列表", Code: "host-org-bds", Path: "/host/bds", Icon: "team", PermissionCode: "bd:view", Sort: 83, Visible: true},
|
||||||
{ParentID: &hostOrgID, Title: "主播列表", Code: "host-org-hosts", Path: "/host/hosts", Icon: "users", PermissionCode: "host:view", Sort: 84, Visible: true},
|
{ParentID: &hostOrgID, Title: "Host 列表", Code: "host-org-hosts", Path: "/host/hosts", Icon: "users", PermissionCode: "host:view", Sort: 84, Visible: true},
|
||||||
{ParentID: &hostOrgID, Title: "币商列表", Code: "host-org-coin-sellers", Path: "/host/coin-sellers", Icon: "wallet", PermissionCode: "coin-seller:view", Sort: 85, Visible: true},
|
{ParentID: &hostOrgID, Title: "Coin Saller列表", Code: "host-org-coin-sellers", Path: "/host/coin-sellers", Icon: "wallet", PermissionCode: "coin-seller:view", Sort: 85, Visible: true},
|
||||||
}
|
}
|
||||||
for _, menu := range children {
|
for _, menu := range children {
|
||||||
if _, err := s.syncDefaultMenu(s.db, menu); err != nil {
|
if _, err := s.syncDefaultMenu(s.db, menu); err != nil {
|
||||||
|
|||||||
@ -34,6 +34,7 @@ func TestGetMyOverviewComposesProfileWalletVIPStatsRolesAndEntries(t *testing.T)
|
|||||||
UserId: 42,
|
UserId: 42,
|
||||||
IsHost: true,
|
IsHost: true,
|
||||||
IsAgency: true,
|
IsAgency: true,
|
||||||
|
IsManager: true,
|
||||||
IsBd: true,
|
IsBd: true,
|
||||||
IsBdLeader: true,
|
IsBdLeader: true,
|
||||||
IsCoinSeller: true,
|
IsCoinSeller: true,
|
||||||
@ -81,7 +82,7 @@ func TestGetMyOverviewComposesProfileWalletVIPStatsRolesAndEntries(t *testing.T)
|
|||||||
t.Fatalf("profile stats mismatch: %+v", stats)
|
t.Fatalf("profile stats mismatch: %+v", stats)
|
||||||
}
|
}
|
||||||
roles := data["roles"].(map[string]any)
|
roles := data["roles"].(map[string]any)
|
||||||
if roles["is_host"] != true || roles["is_agency"] != true || roles["is_bd"] != true || roles["is_bd_leader"] != true || roles["is_coin_seller"] != true || roles["agency_id"] != float64(7001) {
|
if roles["is_host"] != true || roles["is_agency"] != true || roles["is_manager"] != true || roles["is_bd"] != true || roles["is_bd_leader"] != true || roles["is_coin_seller"] != true || roles["agency_id"] != float64(7001) {
|
||||||
t.Fatalf("roles data mismatch: %+v", roles)
|
t.Fatalf("roles data mismatch: %+v", roles)
|
||||||
}
|
}
|
||||||
wallet := data["wallet"].(map[string]any)
|
wallet := data["wallet"].(map[string]any)
|
||||||
@ -106,6 +107,7 @@ func TestGetMyOverviewComposesProfileWalletVIPStatsRolesAndEntries(t *testing.T)
|
|||||||
!overviewEntryVisible(entries, "task") ||
|
!overviewEntryVisible(entries, "task") ||
|
||||||
!overviewEntryVisible(entries, "host_center") ||
|
!overviewEntryVisible(entries, "host_center") ||
|
||||||
!overviewEntryVisible(entries, "agency_center") ||
|
!overviewEntryVisible(entries, "agency_center") ||
|
||||||
|
!overviewEntryVisible(entries, "manager_center") ||
|
||||||
!overviewEntryVisible(entries, "bd_center") ||
|
!overviewEntryVisible(entries, "bd_center") ||
|
||||||
!overviewEntryVisible(entries, "bd_leader_center") ||
|
!overviewEntryVisible(entries, "bd_leader_center") ||
|
||||||
!overviewEntryVisible(entries, "coin_seller_center") ||
|
!overviewEntryVisible(entries, "coin_seller_center") ||
|
||||||
@ -136,7 +138,7 @@ func TestGetMyOverviewProjectsOrdinaryUserEntriesAndZeroWallet(t *testing.T) {
|
|||||||
t.Fatalf("missing stats should be zero projection: %+v", stats)
|
t.Fatalf("missing stats should be zero projection: %+v", stats)
|
||||||
}
|
}
|
||||||
roles := data["roles"].(map[string]any)
|
roles := data["roles"].(map[string]any)
|
||||||
if roles["is_host"] != false || roles["is_bd"] != false || roles["is_coin_seller"] != false {
|
if roles["is_host"] != false || roles["is_manager"] != false || roles["is_bd"] != false || roles["is_coin_seller"] != false {
|
||||||
t.Fatalf("ordinary roles mismatch: %+v", roles)
|
t.Fatalf("ordinary roles mismatch: %+v", roles)
|
||||||
}
|
}
|
||||||
entries := data["entries"].([]any)
|
entries := data["entries"].([]any)
|
||||||
@ -162,11 +164,11 @@ func TestGetMyOverviewDegradesOptionalUpstreamFailures(t *testing.T) {
|
|||||||
t.Fatalf("profile stats degradation mismatch: %+v", stats)
|
t.Fatalf("profile stats degradation mismatch: %+v", stats)
|
||||||
}
|
}
|
||||||
roles := data["roles"].(map[string]any)
|
roles := data["roles"].(map[string]any)
|
||||||
if roles["unavailable"] != true || roles["is_host"] != false || roles["is_bd"] != false || roles["is_coin_seller"] != false {
|
if roles["unavailable"] != true || roles["is_host"] != false || roles["is_manager"] != false || roles["is_bd"] != false || roles["is_coin_seller"] != false {
|
||||||
t.Fatalf("roles degradation mismatch: %+v", roles)
|
t.Fatalf("roles degradation mismatch: %+v", roles)
|
||||||
}
|
}
|
||||||
entries := data["entries"].([]any)
|
entries := data["entries"].([]any)
|
||||||
if overviewEntryVisible(entries, "host_center") || overviewEntryVisible(entries, "bd_center") || overviewEntryVisible(entries, "coin_seller_center") {
|
if overviewEntryVisible(entries, "host_center") || overviewEntryVisible(entries, "manager_center") || overviewEntryVisible(entries, "bd_center") || overviewEntryVisible(entries, "coin_seller_center") {
|
||||||
t.Fatalf("degraded roles must not expose privileged entries: %+v", entries)
|
t.Fatalf("degraded roles must not expose privileged entries: %+v", entries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2427,20 +2427,14 @@ func TestGetAppVersionReturnsLatestVersionAndUpdateDecision(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetMyHostIdentityCombinesActiveHostAndBDProfiles(t *testing.T) {
|
func TestGetMyHostIdentityCombinesActiveHostAndBDProfiles(t *testing.T) {
|
||||||
hostClient := &fakeUserHostClient{
|
hostClient := &fakeUserHostClient{
|
||||||
hostProfile: &userv1.HostProfile{
|
roleSummary: &userv1.UserRoleSummary{
|
||||||
UserId: 42,
|
UserId: 42,
|
||||||
Status: "active",
|
IsHost: true,
|
||||||
Source: "admin_create_agency",
|
IsAgency: true,
|
||||||
},
|
IsManager: true,
|
||||||
bdProfile: &userv1.BDProfile{
|
IsBd: true,
|
||||||
UserId: 42,
|
IsBdLeader: true,
|
||||||
Status: "active",
|
IsCoinSeller: true,
|
||||||
Role: "bd_leader",
|
|
||||||
},
|
|
||||||
profile: &userv1.CoinSellerProfile{
|
|
||||||
UserId: 42,
|
|
||||||
Status: "active",
|
|
||||||
MerchantAssetType: "COIN_SELLER_COIN",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
||||||
@ -2456,14 +2450,8 @@ func TestGetMyHostIdentityCombinesActiveHostAndBDProfiles(t *testing.T) {
|
|||||||
if recorder.Code != http.StatusOK {
|
if recorder.Code != http.StatusOK {
|
||||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||||
}
|
}
|
||||||
if hostClient.lastHost == nil || hostClient.lastHost.GetUserId() != 42 || hostClient.lastHost.GetMeta().GetRequestId() != assertGeneratedRequestID(t, recorder, "req-host-identity") {
|
if hostClient.lastRoleSummary == nil || hostClient.lastRoleSummary.GetUserId() != 42 || hostClient.lastRoleSummary.GetMeta().GetRequestId() != assertGeneratedRequestID(t, recorder, "req-host-identity") {
|
||||||
t.Fatalf("host identity host request mismatch: %+v", hostClient.lastHost)
|
t.Fatalf("host identity role summary request mismatch: %+v", hostClient.lastRoleSummary)
|
||||||
}
|
|
||||||
if hostClient.lastBD == nil || hostClient.lastBD.GetUserId() != 42 {
|
|
||||||
t.Fatalf("host identity bd request mismatch: %+v", hostClient.lastBD)
|
|
||||||
}
|
|
||||||
if hostClient.last == nil || hostClient.last.GetUserId() != 42 {
|
|
||||||
t.Fatalf("host identity coin seller request mismatch: %+v", hostClient.last)
|
|
||||||
}
|
}
|
||||||
var response httpkit.ResponseEnvelope
|
var response httpkit.ResponseEnvelope
|
||||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||||
@ -2473,6 +2461,7 @@ func TestGetMyHostIdentityCombinesActiveHostAndBDProfiles(t *testing.T) {
|
|||||||
if response.Code != httpkit.CodeOK || !ok ||
|
if response.Code != httpkit.CodeOK || !ok ||
|
||||||
data["is_host"] != true ||
|
data["is_host"] != true ||
|
||||||
data["is_agent"] != true ||
|
data["is_agent"] != true ||
|
||||||
|
data["is_manager"] != true ||
|
||||||
data["is_bd"] != true ||
|
data["is_bd"] != true ||
|
||||||
data["is_bd_leader"] != true ||
|
data["is_bd_leader"] != true ||
|
||||||
data["is_coin_seller"] != true {
|
data["is_coin_seller"] != true {
|
||||||
@ -2481,11 +2470,7 @@ func TestGetMyHostIdentityCombinesActiveHostAndBDProfiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetMyHostIdentityTreatsMissingProfilesAsFalse(t *testing.T) {
|
func TestGetMyHostIdentityTreatsMissingProfilesAsFalse(t *testing.T) {
|
||||||
hostClient := &fakeUserHostClient{
|
hostClient := &fakeUserHostClient{}
|
||||||
hostErr: xerr.ToGRPCError(xerr.New(xerr.NotFound, "host profile not found")),
|
|
||||||
bdErr: xerr.ToGRPCError(xerr.New(xerr.NotFound, "bd profile not found")),
|
|
||||||
err: xerr.ToGRPCError(xerr.New(xerr.NotFound, "coin seller profile not found")),
|
|
||||||
}
|
|
||||||
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
|
||||||
handler.SetUserHostClient(hostClient)
|
handler.SetUserHostClient(hostClient)
|
||||||
router := handler.Routes(auth.NewVerifier("secret"))
|
router := handler.Routes(auth.NewVerifier("secret"))
|
||||||
@ -2507,6 +2492,7 @@ func TestGetMyHostIdentityTreatsMissingProfilesAsFalse(t *testing.T) {
|
|||||||
if response.Code != httpkit.CodeOK || !ok ||
|
if response.Code != httpkit.CodeOK || !ok ||
|
||||||
data["is_host"] != false ||
|
data["is_host"] != false ||
|
||||||
data["is_agent"] != false ||
|
data["is_agent"] != false ||
|
||||||
|
data["is_manager"] != false ||
|
||||||
data["is_bd"] != false ||
|
data["is_bd"] != false ||
|
||||||
data["is_bd_leader"] != false ||
|
data["is_bd_leader"] != false ||
|
||||||
data["is_coin_seller"] != false {
|
data["is_coin_seller"] != false {
|
||||||
|
|||||||
@ -1,26 +1,17 @@
|
|||||||
package userapi
|
package userapi
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"hyapp/services/gateway-service/internal/transport/http/httpkit"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
userv1 "hyapp.local/api/proto/user/v1"
|
userv1 "hyapp.local/api/proto/user/v1"
|
||||||
"hyapp/pkg/xerr"
|
|
||||||
"hyapp/services/gateway-service/internal/auth"
|
"hyapp/services/gateway-service/internal/auth"
|
||||||
)
|
"hyapp/services/gateway-service/internal/transport/http/httpkit"
|
||||||
|
|
||||||
const (
|
|
||||||
hostIdentityActiveStatus = "active"
|
|
||||||
hostIdentityAgencyInvitation = "agency_invitation"
|
|
||||||
hostIdentityAdminCreateAgency = "admin_create_agency"
|
|
||||||
hostIdentityBDRole = "bd"
|
|
||||||
hostIdentityBDLeaderRole = "bd_leader"
|
|
||||||
hostIdentityCoinSellerAsset = "COIN_SELLER_COIN"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type userHostIdentityData struct {
|
type userHostIdentityData struct {
|
||||||
IsHost bool `json:"is_host"`
|
IsHost bool `json:"is_host"`
|
||||||
IsAgent bool `json:"is_agent"`
|
IsAgent bool `json:"is_agent"`
|
||||||
|
IsManager bool `json:"is_manager"`
|
||||||
IsBD bool `json:"is_bd"`
|
IsBD bool `json:"is_bd"`
|
||||||
IsBDLeader bool `json:"is_bd_leader"`
|
IsBDLeader bool `json:"is_bd_leader"`
|
||||||
IsCoinSeller bool `json:"is_coin_seller"`
|
IsCoinSeller bool `json:"is_coin_seller"`
|
||||||
@ -32,50 +23,24 @@ func (h *Handler) getMyHostIdentity(writer http.ResponseWriter, request *http.Re
|
|||||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
resp, err := h.userHostClient.GetUserRoleSummary(request.Context(), &userv1.GetUserRoleSummaryRequest{
|
||||||
userID := auth.UserIDFromContext(request.Context())
|
|
||||||
identity := userHostIdentityData{}
|
|
||||||
|
|
||||||
hostResp, err := h.userHostClient.GetHostProfile(request.Context(), &userv1.GetHostProfileRequest{
|
|
||||||
Meta: httpkit.UserMeta(request, ""),
|
Meta: httpkit.UserMeta(request, ""),
|
||||||
UserId: userID,
|
UserId: auth.UserIDFromContext(request.Context()),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if xerr.ReasonFromGRPC(err) != xerr.NotFound {
|
httpkit.WriteRPCError(writer, request, err)
|
||||||
httpkit.WriteRPCError(writer, request, err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
applyHostIdentity(&identity, hostResp.GetHostProfile())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bdResp, err := h.userHostClient.GetBDProfile(request.Context(), &userv1.GetBDProfileRequest{
|
summary := resp.GetSummary()
|
||||||
Meta: httpkit.UserMeta(request, ""),
|
httpkit.WriteOK(writer, request, userHostIdentityData{
|
||||||
UserId: userID,
|
IsHost: summary.GetIsHost(),
|
||||||
|
IsAgent: summary.GetIsAgency(),
|
||||||
|
IsManager: summary.GetIsManager(),
|
||||||
|
IsBD: summary.GetIsBd(),
|
||||||
|
IsBDLeader: summary.GetIsBdLeader(),
|
||||||
|
IsCoinSeller: summary.GetIsCoinSeller(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
if xerr.ReasonFromGRPC(err) != xerr.NotFound {
|
|
||||||
httpkit.WriteRPCError(writer, request, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
applyBDIdentity(&identity, bdResp.GetBdProfile())
|
|
||||||
}
|
|
||||||
|
|
||||||
coinSellerResp, err := h.userHostClient.GetCoinSellerProfile(request.Context(), &userv1.GetCoinSellerProfileRequest{
|
|
||||||
Meta: httpkit.UserMeta(request, ""),
|
|
||||||
UserId: userID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
if xerr.ReasonFromGRPC(err) != xerr.NotFound {
|
|
||||||
httpkit.WriteRPCError(writer, request, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
applyCoinSellerIdentity(&identity, coinSellerResp.GetCoinSellerProfile())
|
|
||||||
}
|
|
||||||
|
|
||||||
httpkit.WriteOK(writer, request, identity)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getMyRoleSummary 返回我的页入口显隐所需的完整角色摘要。
|
// getMyRoleSummary 返回我的页入口显隐所需的完整角色摘要。
|
||||||
@ -96,6 +61,7 @@ func (h *Handler) getMyRoleSummary(writer http.ResponseWriter, request *http.Req
|
|||||||
httpkit.WriteOK(writer, request, overviewRolesData{
|
httpkit.WriteOK(writer, request, overviewRolesData{
|
||||||
IsHost: summary.GetIsHost(),
|
IsHost: summary.GetIsHost(),
|
||||||
IsAgency: summary.GetIsAgency(),
|
IsAgency: summary.GetIsAgency(),
|
||||||
|
IsManager: summary.GetIsManager(),
|
||||||
IsBD: summary.GetIsBd(),
|
IsBD: summary.GetIsBd(),
|
||||||
IsBDLeader: summary.GetIsBdLeader(),
|
IsBDLeader: summary.GetIsBdLeader(),
|
||||||
IsCoinSeller: summary.GetIsCoinSeller(),
|
IsCoinSeller: summary.GetIsCoinSeller(),
|
||||||
@ -107,39 +73,3 @@ func (h *Handler) getMyRoleSummary(writer http.ResponseWriter, request *http.Req
|
|||||||
PendingRoleInvitations: summary.GetPendingRoleInvitations(),
|
PendingRoleInvitations: summary.GetPendingRoleInvitations(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyHostIdentity(identity *userHostIdentityData, profile *userv1.HostProfile) {
|
|
||||||
if profile == nil || profile.GetStatus() != hostIdentityActiveStatus {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
identity.IsHost = true
|
|
||||||
switch profile.GetSource() {
|
|
||||||
case hostIdentityAgencyInvitation, hostIdentityAdminCreateAgency:
|
|
||||||
identity.IsAgent = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyBDIdentity(identity *userHostIdentityData, profile *userv1.BDProfile) {
|
|
||||||
if profile == nil || profile.GetStatus() != hostIdentityActiveStatus {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch profile.GetRole() {
|
|
||||||
case hostIdentityBDLeaderRole:
|
|
||||||
identity.IsBD = true
|
|
||||||
identity.IsBDLeader = true
|
|
||||||
case hostIdentityBDRole:
|
|
||||||
identity.IsBD = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyCoinSellerIdentity(identity *userHostIdentityData, profile *userv1.CoinSellerProfile) {
|
|
||||||
if profile == nil ||
|
|
||||||
profile.GetStatus() != hostIdentityActiveStatus ||
|
|
||||||
profile.GetMerchantAssetType() != hostIdentityCoinSellerAsset {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
identity.IsCoinSeller = true
|
|
||||||
}
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ type overviewWalletData struct {
|
|||||||
type overviewRolesData struct {
|
type overviewRolesData struct {
|
||||||
IsHost bool `json:"is_host"`
|
IsHost bool `json:"is_host"`
|
||||||
IsAgency bool `json:"is_agency"`
|
IsAgency bool `json:"is_agency"`
|
||||||
|
IsManager bool `json:"is_manager"`
|
||||||
IsBD bool `json:"is_bd"`
|
IsBD bool `json:"is_bd"`
|
||||||
IsBDLeader bool `json:"is_bd_leader"`
|
IsBDLeader bool `json:"is_bd_leader"`
|
||||||
IsCoinSeller bool `json:"is_coin_seller"`
|
IsCoinSeller bool `json:"is_coin_seller"`
|
||||||
@ -183,6 +184,7 @@ func (h *Handler) getOverviewRoles(ctx context.Context, request *http.Request, u
|
|||||||
return overviewRolesData{
|
return overviewRolesData{
|
||||||
IsHost: summary.GetIsHost(),
|
IsHost: summary.GetIsHost(),
|
||||||
IsAgency: summary.GetIsAgency(),
|
IsAgency: summary.GetIsAgency(),
|
||||||
|
IsManager: summary.GetIsManager(),
|
||||||
IsBD: summary.GetIsBd(),
|
IsBD: summary.GetIsBd(),
|
||||||
IsBDLeader: summary.GetIsBdLeader(),
|
IsBDLeader: summary.GetIsBdLeader(),
|
||||||
IsCoinSeller: summary.GetIsCoinSeller(),
|
IsCoinSeller: summary.GetIsCoinSeller(),
|
||||||
@ -245,10 +247,11 @@ func overviewEntries(roles overviewRolesData) []overviewEntryData {
|
|||||||
{Key: "apply_host", Visible: !roles.IsHost, Enabled: true, Route: "/host/apply", IconKey: "host_apply", Order: 50},
|
{Key: "apply_host", Visible: !roles.IsHost, Enabled: true, Route: "/host/apply", IconKey: "host_apply", Order: 50},
|
||||||
{Key: "host_center", Visible: roles.IsHost, Enabled: roles.IsHost, Route: "/host", IconKey: "host_center", Order: 60},
|
{Key: "host_center", Visible: roles.IsHost, Enabled: roles.IsHost, Route: "/host", IconKey: "host_center", Order: 60},
|
||||||
{Key: "agency_center", Visible: roles.IsAgency, Enabled: roles.IsAgency, Route: "/agency", IconKey: "agency", Order: 70},
|
{Key: "agency_center", Visible: roles.IsAgency, Enabled: roles.IsAgency, Route: "/agency", IconKey: "agency", Order: 70},
|
||||||
{Key: "bd_center", Visible: roles.IsBD, Enabled: roles.IsBD, Route: "/bd", IconKey: "bd", Order: 80},
|
{Key: "manager_center", Visible: roles.IsManager, Enabled: roles.IsManager, Route: "/manager-center", IconKey: "manager_center", Order: 80},
|
||||||
{Key: "bd_leader_center", Visible: roles.IsBDLeader, Enabled: roles.IsBDLeader, Route: "/bd-leader", IconKey: "bd_leader", Order: 90},
|
{Key: "bd_center", Visible: roles.IsBD, Enabled: roles.IsBD, Route: "/bd", IconKey: "bd", Order: 90},
|
||||||
{Key: "coin_seller_center", Visible: roles.IsCoinSeller, Enabled: roles.IsCoinSeller, Route: "/coin-seller", IconKey: "coin_seller", Order: 100},
|
{Key: "bd_leader_center", Visible: roles.IsBDLeader, Enabled: roles.IsBDLeader, Route: "/bd-leader", IconKey: "bd_leader", Order: 100},
|
||||||
{Key: "settings", Visible: true, Enabled: true, Route: "/settings", IconKey: "settings", Order: 110},
|
{Key: "coin_seller_center", Visible: roles.IsCoinSeller, Enabled: roles.IsCoinSeller, Route: "/coin-seller", IconKey: "coin_seller", Order: 110},
|
||||||
{Key: "language", Visible: true, Enabled: true, Route: "/language", IconKey: "language", Order: 120},
|
{Key: "settings", Visible: true, Enabled: true, Route: "/settings", IconKey: "settings", Order: 120},
|
||||||
|
{Key: "language", Visible: true, Enabled: true, Route: "/language", IconKey: "language", Order: 130},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -184,6 +184,7 @@ type UserRoleSummary struct {
|
|||||||
UserID int64
|
UserID int64
|
||||||
IsHost bool
|
IsHost bool
|
||||||
IsAgency bool
|
IsAgency bool
|
||||||
|
IsManager bool
|
||||||
IsBD bool
|
IsBD bool
|
||||||
IsBDLeader bool
|
IsBDLeader bool
|
||||||
IsCoinSeller bool
|
IsCoinSeller bool
|
||||||
|
|||||||
@ -579,7 +579,7 @@ func TestGetUserRoleSummaryAggregatesRolesAndPendingInvitations(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("GetUserRoleSummary failed: %v", err)
|
t.Fatalf("GetUserRoleSummary failed: %v", err)
|
||||||
}
|
}
|
||||||
if !summary.IsHost || !summary.IsAgency || !summary.IsBD || !summary.IsBDLeader || !summary.IsCoinSeller || summary.AgencyID != 933 || summary.BDID != 931 {
|
if !summary.IsHost || !summary.IsAgency || !summary.IsManager || !summary.IsBD || !summary.IsBDLeader || !summary.IsCoinSeller || summary.AgencyID != 933 || summary.BDID != 931 {
|
||||||
t.Fatalf("role summary mismatch: %+v", summary)
|
t.Fatalf("role summary mismatch: %+v", summary)
|
||||||
}
|
}
|
||||||
pending, err := svc.GetUserRoleSummary(ctx, 932)
|
pending, err := svc.GetUserRoleSummary(ctx, 932)
|
||||||
|
|||||||
@ -118,6 +118,8 @@ func (r *Repository) GetUserRoleSummary(ctx context.Context, userID int64) (host
|
|||||||
summary.IsHost = hostStatus == hostdomain.HostStatusActive
|
summary.IsHost = hostStatus == hostdomain.HostStatusActive
|
||||||
if ownerAgencyID > 0 {
|
if ownerAgencyID > 0 {
|
||||||
summary.AgencyID = ownerAgencyID
|
summary.AgencyID = ownerAgencyID
|
||||||
|
// 经理中心首版授权边界是 active Agency owner;普通 Agency 成员只展示 Agency 入口,不具备 manager 身份。
|
||||||
|
summary.IsManager = true
|
||||||
} else {
|
} else {
|
||||||
summary.AgencyID = hostAgencyID
|
summary.AgencyID = hostAgencyID
|
||||||
}
|
}
|
||||||
|
|||||||
@ -351,6 +351,7 @@ func toProtoUserRoleSummary(summary hostdomain.UserRoleSummary) *userv1.UserRole
|
|||||||
UserId: summary.UserID,
|
UserId: summary.UserID,
|
||||||
IsHost: summary.IsHost,
|
IsHost: summary.IsHost,
|
||||||
IsAgency: summary.IsAgency,
|
IsAgency: summary.IsAgency,
|
||||||
|
IsManager: summary.IsManager,
|
||||||
IsBd: summary.IsBD,
|
IsBd: summary.IsBD,
|
||||||
IsBdLeader: summary.IsBDLeader,
|
IsBdLeader: summary.IsBDLeader,
|
||||||
IsCoinSeller: summary.IsCoinSeller,
|
IsCoinSeller: summary.IsCoinSeller,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user