agency房间列表

This commit is contained in:
zhx 2026-06-30 13:05:13 +08:00
parent ce4f1dc4c1
commit 3af61b2468
38 changed files with 2876 additions and 1162 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1189,6 +1189,18 @@ message ListRoomsRequest {
bool all_visible_regions = 10; bool all_visible_regions = 10;
} }
// ListRoomsByOwnersRequest active
// owner_user_ids gateway
message ListRoomsByOwnersRequest {
RequestMeta meta = 1;
int64 viewer_user_id = 2;
repeated int64 owner_user_ids = 3;
string tab = 4;
string cursor = 5;
int32 limit = 6;
string query = 7;
}
// ListRoomFeedsRequest Mine visited/friend/following/followed // ListRoomFeedsRequest Mine visited/friend/following/followed
// //
message ListRoomFeedsRequest { message ListRoomFeedsRequest {
@ -1456,6 +1468,7 @@ service RoomQueryService {
rpc AdminListRobotRooms(AdminListRobotRoomsRequest) returns (AdminListRobotRoomsResponse); rpc AdminListRobotRooms(AdminListRobotRoomsRequest) returns (AdminListRobotRoomsResponse);
rpc AdminFilterAvailableRoomRobots(AdminFilterAvailableRoomRobotsRequest) returns (AdminFilterAvailableRoomRobotsResponse); rpc AdminFilterAvailableRoomRobots(AdminFilterAvailableRoomRobotsRequest) returns (AdminFilterAvailableRoomRobotsResponse);
rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse); rpc ListRooms(ListRoomsRequest) returns (ListRoomsResponse);
rpc ListRoomsByOwners(ListRoomsByOwnersRequest) returns (ListRoomsResponse);
rpc ListRoomFeeds(ListRoomFeedsRequest) returns (ListRoomsResponse); rpc ListRoomFeeds(ListRoomFeedsRequest) returns (ListRoomsResponse);
rpc ListRoomGiftLeaderboard(ListRoomGiftLeaderboardRequest) returns (ListRoomGiftLeaderboardResponse); rpc ListRoomGiftLeaderboard(ListRoomGiftLeaderboardRequest) returns (ListRoomGiftLeaderboardResponse);
rpc GetMyRoom(GetMyRoomRequest) returns (GetMyRoomResponse); rpc GetMyRoom(GetMyRoomRequest) returns (GetMyRoomResponse);

View File

@ -1570,6 +1570,7 @@ const (
RoomQueryService_AdminListRobotRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminListRobotRooms" RoomQueryService_AdminListRobotRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminListRobotRooms"
RoomQueryService_AdminFilterAvailableRoomRobots_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminFilterAvailableRoomRobots" RoomQueryService_AdminFilterAvailableRoomRobots_FullMethodName = "/hyapp.room.v1.RoomQueryService/AdminFilterAvailableRoomRobots"
RoomQueryService_ListRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRooms" RoomQueryService_ListRooms_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRooms"
RoomQueryService_ListRoomsByOwners_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomsByOwners"
RoomQueryService_ListRoomFeeds_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomFeeds" RoomQueryService_ListRoomFeeds_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomFeeds"
RoomQueryService_ListRoomGiftLeaderboard_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomGiftLeaderboard" RoomQueryService_ListRoomGiftLeaderboard_FullMethodName = "/hyapp.room.v1.RoomQueryService/ListRoomGiftLeaderboard"
RoomQueryService_GetMyRoom_FullMethodName = "/hyapp.room.v1.RoomQueryService/GetMyRoom" RoomQueryService_GetMyRoom_FullMethodName = "/hyapp.room.v1.RoomQueryService/GetMyRoom"
@ -1596,6 +1597,7 @@ type RoomQueryServiceClient interface {
AdminListRobotRooms(ctx context.Context, in *AdminListRobotRoomsRequest, opts ...grpc.CallOption) (*AdminListRobotRoomsResponse, error) AdminListRobotRooms(ctx context.Context, in *AdminListRobotRoomsRequest, opts ...grpc.CallOption) (*AdminListRobotRoomsResponse, error)
AdminFilterAvailableRoomRobots(ctx context.Context, in *AdminFilterAvailableRoomRobotsRequest, opts ...grpc.CallOption) (*AdminFilterAvailableRoomRobotsResponse, error) AdminFilterAvailableRoomRobots(ctx context.Context, in *AdminFilterAvailableRoomRobotsRequest, opts ...grpc.CallOption) (*AdminFilterAvailableRoomRobotsResponse, error)
ListRooms(ctx context.Context, in *ListRoomsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) ListRooms(ctx context.Context, in *ListRoomsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error)
ListRoomsByOwners(ctx context.Context, in *ListRoomsByOwnersRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error)
ListRoomFeeds(ctx context.Context, in *ListRoomFeedsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) ListRoomFeeds(ctx context.Context, in *ListRoomFeedsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error)
ListRoomGiftLeaderboard(ctx context.Context, in *ListRoomGiftLeaderboardRequest, opts ...grpc.CallOption) (*ListRoomGiftLeaderboardResponse, error) ListRoomGiftLeaderboard(ctx context.Context, in *ListRoomGiftLeaderboardRequest, opts ...grpc.CallOption) (*ListRoomGiftLeaderboardResponse, error)
GetMyRoom(ctx context.Context, in *GetMyRoomRequest, opts ...grpc.CallOption) (*GetMyRoomResponse, error) GetMyRoom(ctx context.Context, in *GetMyRoomRequest, opts ...grpc.CallOption) (*GetMyRoomResponse, error)
@ -1705,6 +1707,16 @@ func (c *roomQueryServiceClient) ListRooms(ctx context.Context, in *ListRoomsReq
return out, nil return out, nil
} }
func (c *roomQueryServiceClient) ListRoomsByOwners(ctx context.Context, in *ListRoomsByOwnersRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListRoomsResponse)
err := c.cc.Invoke(ctx, RoomQueryService_ListRoomsByOwners_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *roomQueryServiceClient) ListRoomFeeds(ctx context.Context, in *ListRoomFeedsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) { func (c *roomQueryServiceClient) ListRoomFeeds(ctx context.Context, in *ListRoomFeedsRequest, opts ...grpc.CallOption) (*ListRoomsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ListRoomsResponse) out := new(ListRoomsResponse)
@ -1810,6 +1822,7 @@ type RoomQueryServiceServer interface {
AdminListRobotRooms(context.Context, *AdminListRobotRoomsRequest) (*AdminListRobotRoomsResponse, error) AdminListRobotRooms(context.Context, *AdminListRobotRoomsRequest) (*AdminListRobotRoomsResponse, error)
AdminFilterAvailableRoomRobots(context.Context, *AdminFilterAvailableRoomRobotsRequest) (*AdminFilterAvailableRoomRobotsResponse, error) AdminFilterAvailableRoomRobots(context.Context, *AdminFilterAvailableRoomRobotsRequest) (*AdminFilterAvailableRoomRobotsResponse, error)
ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error)
ListRoomsByOwners(context.Context, *ListRoomsByOwnersRequest) (*ListRoomsResponse, error)
ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error) ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error)
ListRoomGiftLeaderboard(context.Context, *ListRoomGiftLeaderboardRequest) (*ListRoomGiftLeaderboardResponse, error) ListRoomGiftLeaderboard(context.Context, *ListRoomGiftLeaderboardRequest) (*ListRoomGiftLeaderboardResponse, error)
GetMyRoom(context.Context, *GetMyRoomRequest) (*GetMyRoomResponse, error) GetMyRoom(context.Context, *GetMyRoomRequest) (*GetMyRoomResponse, error)
@ -1856,6 +1869,9 @@ func (UnimplementedRoomQueryServiceServer) AdminFilterAvailableRoomRobots(contex
func (UnimplementedRoomQueryServiceServer) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) { func (UnimplementedRoomQueryServiceServer) ListRooms(context.Context, *ListRoomsRequest) (*ListRoomsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListRooms not implemented") return nil, status.Errorf(codes.Unimplemented, "method ListRooms not implemented")
} }
func (UnimplementedRoomQueryServiceServer) ListRoomsByOwners(context.Context, *ListRoomsByOwnersRequest) (*ListRoomsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListRoomsByOwners not implemented")
}
func (UnimplementedRoomQueryServiceServer) ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error) { func (UnimplementedRoomQueryServiceServer) ListRoomFeeds(context.Context, *ListRoomFeedsRequest) (*ListRoomsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListRoomFeeds not implemented") return nil, status.Errorf(codes.Unimplemented, "method ListRoomFeeds not implemented")
} }
@ -2066,6 +2082,24 @@ func _RoomQueryService_ListRooms_Handler(srv interface{}, ctx context.Context, d
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _RoomQueryService_ListRoomsByOwners_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListRoomsByOwnersRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RoomQueryServiceServer).ListRoomsByOwners(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: RoomQueryService_ListRoomsByOwners_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RoomQueryServiceServer).ListRoomsByOwners(ctx, req.(*ListRoomsByOwnersRequest))
}
return interceptor(ctx, in, info, handler)
}
func _RoomQueryService_ListRoomFeeds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { func _RoomQueryService_ListRoomFeeds_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListRoomFeedsRequest) in := new(ListRoomFeedsRequest)
if err := dec(in); err != nil { if err := dec(in); err != nil {
@ -2271,6 +2305,10 @@ var RoomQueryService_ServiceDesc = grpc.ServiceDesc{
MethodName: "ListRooms", MethodName: "ListRooms",
Handler: _RoomQueryService_ListRooms_Handler, Handler: _RoomQueryService_ListRooms_Handler,
}, },
{
MethodName: "ListRoomsByOwners",
Handler: _RoomQueryService_ListRoomsByOwners_Handler,
},
{ {
MethodName: "ListRoomFeeds", MethodName: "ListRoomFeeds",
Handler: _RoomQueryService_ListRoomFeeds_Handler, Handler: _RoomQueryService_ListRoomFeeds_Handler,

View File

@ -5120,6 +5120,136 @@ func (x *SetAgencyJoinEnabledResponse) GetAgency() *Agency {
return nil return nil
} }
type UpdateAgencyProfileRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
CommandId string `protobuf:"bytes,2,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"`
OperatorUserId int64 `protobuf:"varint,3,opt,name=operator_user_id,json=operatorUserId,proto3" json:"operator_user_id,omitempty"`
AgencyId int64 `protobuf:"varint,4,opt,name=agency_id,json=agencyId,proto3" json:"agency_id,omitempty"`
Name *string `protobuf:"bytes,5,opt,name=name,proto3,oneof" json:"name,omitempty"`
Avatar *string `protobuf:"bytes,6,opt,name=avatar,proto3,oneof" json:"avatar,omitempty"`
}
func (x *UpdateAgencyProfileRequest) Reset() {
*x = UpdateAgencyProfileRequest{}
mi := &file_proto_user_v1_host_proto_msgTypes[75]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UpdateAgencyProfileRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UpdateAgencyProfileRequest) ProtoMessage() {}
func (x *UpdateAgencyProfileRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_user_v1_host_proto_msgTypes[75]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UpdateAgencyProfileRequest.ProtoReflect.Descriptor instead.
func (*UpdateAgencyProfileRequest) Descriptor() ([]byte, []int) {
return file_proto_user_v1_host_proto_rawDescGZIP(), []int{75}
}
func (x *UpdateAgencyProfileRequest) GetMeta() *RequestMeta {
if x != nil {
return x.Meta
}
return nil
}
func (x *UpdateAgencyProfileRequest) GetCommandId() string {
if x != nil {
return x.CommandId
}
return ""
}
func (x *UpdateAgencyProfileRequest) GetOperatorUserId() int64 {
if x != nil {
return x.OperatorUserId
}
return 0
}
func (x *UpdateAgencyProfileRequest) GetAgencyId() int64 {
if x != nil {
return x.AgencyId
}
return 0
}
func (x *UpdateAgencyProfileRequest) GetName() string {
if x != nil && x.Name != nil {
return *x.Name
}
return ""
}
func (x *UpdateAgencyProfileRequest) GetAvatar() string {
if x != nil && x.Avatar != nil {
return *x.Avatar
}
return ""
}
type UpdateAgencyProfileResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Agency *Agency `protobuf:"bytes,1,opt,name=agency,proto3" json:"agency,omitempty"`
}
func (x *UpdateAgencyProfileResponse) Reset() {
*x = UpdateAgencyProfileResponse{}
mi := &file_proto_user_v1_host_proto_msgTypes[76]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UpdateAgencyProfileResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UpdateAgencyProfileResponse) ProtoMessage() {}
func (x *UpdateAgencyProfileResponse) ProtoReflect() protoreflect.Message {
mi := &file_proto_user_v1_host_proto_msgTypes[76]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UpdateAgencyProfileResponse.ProtoReflect.Descriptor instead.
func (*UpdateAgencyProfileResponse) Descriptor() ([]byte, []int) {
return file_proto_user_v1_host_proto_rawDescGZIP(), []int{76}
}
func (x *UpdateAgencyProfileResponse) GetAgency() *Agency {
if x != nil {
return x.Agency
}
return nil
}
var File_proto_user_v1_host_proto protoreflect.FileDescriptor var File_proto_user_v1_host_proto protoreflect.FileDescriptor
var file_proto_user_v1_host_proto_rawDesc = []byte{ var file_proto_user_v1_host_proto_rawDesc = []byte{
@ -5954,220 +6084,248 @@ var file_proto_user_v1_host_proto_rawDesc = []byte{
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x67,
0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61,
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x63,
0x79, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x32, 0xd5, 0x12, 0x0a, 0x0f, 0x55, 0x73, 0x79, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x22, 0xfc, 0x01, 0x0a, 0x1a, 0x55, 0x70,
0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65,
0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,
0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f,
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
0x03, 0x52, 0x0e, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49,
0x64, 0x12, 0x1b, 0x0a, 0x09, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x04,
0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x49, 0x64, 0x12, 0x17,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x1b, 0x0a, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61,
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x06, 0x61, 0x76, 0x61, 0x74, 0x61,
0x72, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x09, 0x0a,
0x07, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x22, 0x4c, 0x0a, 0x1b, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x63,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x06,
0x61, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x32, 0xc3, 0x13, 0x0a, 0x0f, 0x55, 0x73, 0x65, 0x72, 0x48,
0x6f, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x53, 0x65,
0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61,
0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x41, 0x70, 0x70,
0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61,
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79,
0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x41, 0x67, 0x65, 0x6e, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0d, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x41, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x23, 0x2e, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70,
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x73, 0x74, 0x1a, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c,
0x76, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x52, 0x65, 0x76, 0x69, 0x5d, 0x0a, 0x0e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73,
0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x74, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e,
0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x65, 0x77, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x0a, 0x0c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22,
0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49,
0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
0x48, 0x6f, 0x73, 0x74, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52,
0x6f, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x49, 0x6e, 0x76, 0x69, 0x74,
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x69, 0x63, 0x6b, 0x41, 0x65, 0x42, 0x44, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x67, 0x65, 0x6e, 0x63, 0x79, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x71, 0x75,
0x65, 0x12, 0x57, 0x0a, 0x0c, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70,
0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x65, 0x71,
0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x49, 0x6e, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x52,
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x42,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61,
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x42, 0x44, 0x52, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0a, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x65, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x73, 0x74, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x4c, 0x69, 0x73,
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x48, 0x6f, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65,
0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x12, 0x25, 0x2e, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67,
0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e,
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69,
0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x42, 0x44, 0x73, 0x52, 0x65, 0x71, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x4c, 0x69,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x24, 0x2e, 0x68,
0x72, 0x42, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x63, 0x69, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65,
0x72, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x4c, 0x69, 0x73,
0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x41, 0x67, 0x65, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74,
0x0e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79,
0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x52, 0x6f,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x44, 0x41, 0x67, 0x65, 0x6e, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x2e, 0x68,
0x63, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
0x6f, 0x6e, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76,
0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x72, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e,
0x69, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x66, 0x0a, 0x11, 0x47, 0x65,
0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65,
0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c,
0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2b, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63,
0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73,
0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x6f, 0x6c,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x65, 0x49, 0x6e, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72,
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79,
0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x48,
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48, 0x6f,
0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61,
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68,
0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x47, 0x65, 0x74, 0x48, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x47, 0x65, 0x74, 0x48,
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x6f, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66,
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x69, 0x6c, 0x65, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x6f, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x44, 0x50, 0x72, 0x6f,
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14,
0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72, 0x6f,
0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c,
0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x90, 0x01, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x72,
0x67, 0x69, 0x6f, 0x6e, 0x12, 0x35, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x90, 0x01,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x0a, 0x1f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e,
0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f,
0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x79, 0x6e, 0x12, 0x35, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e,
0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f,
0x73, 0x49, 0x6e, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74,
0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x69, 0x76, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x73, 0x49, 0x6e,
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x4d, 0x79, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x12, 0x69, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53,
0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f,
0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x0a, 0x09, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x53, 0x75, 0x6d, 0x6d,
0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x09, 0x47,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e,
0x0a, 0x17, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65,
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x78, 0x0a, 0x17, 0x43,
0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61,
0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x2d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69,
0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x6e, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x26, 0x2e, 0x68, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x75, 0x73, 0x69, 0x6e,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x65, 0x73, 0x73, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x65, 0x73,
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65,
0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x15, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4d, 0x65, 0x6d, 0x62, 0x65,
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x47, 0x65,
0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69,
0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x6f, 0x6e, 0x73, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70,
0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x65, 0x32, 0xc6, 0x07, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x41, 0x64, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x43, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63,
0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x68, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72,
0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e,
0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x63, 0x79, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x61, 0x74, 0x65, 0x42, 0x44, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x50, 0x72, 0x6f,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc6, 0x07, 0x0a,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x14, 0x55, 0x73, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5d, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x24, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x4c, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70,
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x12, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x1a, 0x1f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x65, 0x12, 0x6c, 0x0a, 0x13, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x42, 0x44, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52,
0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74,
0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x26, 0x2e, 0x68, 0x79,
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65,
0x6c, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6c, 0x0a, 0x13,
0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65,
0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a,
0x57, 0x0a, 0x0c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53,
0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x65, 0x74, 0x43, 0x6f, 0x69, 0x6e, 0x53, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x43, 0x72,
0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23,
0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43,
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x6e, 0x73, 0x65, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x6e,
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x63, 0x79, 0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65,
0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x44, 0x65, 0x6c,
0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70,
0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x41, 0x67, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e,
0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65,
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53,
0x74, 0x1a, 0x26, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x25, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x68,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74,
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6f, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63,
0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x2a, 0x2e, 0x68,
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74,
0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65,
0x64, 0x12, 0x2a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x67, 0x65, 0x6e,
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2b, 0x2e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73,
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c,
0x74, 0x41, 0x67, 0x65, 0x6e, 0x63, 0x79, 0x4a, 0x6f, 0x69, 0x6e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x75,
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x68, 0x79, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06, 0x70,
0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x74, 0x6f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72,
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -6182,7 +6340,7 @@ func file_proto_user_v1_host_proto_rawDescGZIP() []byte {
return file_proto_user_v1_host_proto_rawDescData return file_proto_user_v1_host_proto_rawDescData
} }
var file_proto_user_v1_host_proto_msgTypes = make([]protoimpl.MessageInfo, 76) var file_proto_user_v1_host_proto_msgTypes = make([]protoimpl.MessageInfo, 78)
var file_proto_user_v1_host_proto_goTypes = []any{ var file_proto_user_v1_host_proto_goTypes = []any{
(*HostProfile)(nil), // 0: hyapp.user.v1.HostProfile (*HostProfile)(nil), // 0: hyapp.user.v1.HostProfile
(*Agency)(nil), // 1: hyapp.user.v1.Agency (*Agency)(nil), // 1: hyapp.user.v1.Agency
@ -6259,156 +6417,162 @@ var file_proto_user_v1_host_proto_goTypes = []any{
(*SetAgencyStatusResponse)(nil), // 72: hyapp.user.v1.SetAgencyStatusResponse (*SetAgencyStatusResponse)(nil), // 72: hyapp.user.v1.SetAgencyStatusResponse
(*SetAgencyJoinEnabledRequest)(nil), // 73: hyapp.user.v1.SetAgencyJoinEnabledRequest (*SetAgencyJoinEnabledRequest)(nil), // 73: hyapp.user.v1.SetAgencyJoinEnabledRequest
(*SetAgencyJoinEnabledResponse)(nil), // 74: hyapp.user.v1.SetAgencyJoinEnabledResponse (*SetAgencyJoinEnabledResponse)(nil), // 74: hyapp.user.v1.SetAgencyJoinEnabledResponse
nil, // 75: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry (*UpdateAgencyProfileRequest)(nil), // 75: hyapp.user.v1.UpdateAgencyProfileRequest
(*RequestMeta)(nil), // 76: hyapp.user.v1.RequestMeta (*UpdateAgencyProfileResponse)(nil), // 76: hyapp.user.v1.UpdateAgencyProfileResponse
nil, // 77: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry
(*RequestMeta)(nil), // 78: hyapp.user.v1.RequestMeta
} }
var file_proto_user_v1_host_proto_depIdxs = []int32{ var file_proto_user_v1_host_proto_depIdxs = []int32{
76, // 0: hyapp.user.v1.SearchAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 0: hyapp.user.v1.SearchAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 1: hyapp.user.v1.SearchAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency 1, // 1: hyapp.user.v1.SearchAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency
76, // 2: hyapp.user.v1.ApplyToAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 2: hyapp.user.v1.ApplyToAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
7, // 3: hyapp.user.v1.ApplyToAgencyResponse.application:type_name -> hyapp.user.v1.AgencyApplication 7, // 3: hyapp.user.v1.ApplyToAgencyResponse.application:type_name -> hyapp.user.v1.AgencyApplication
76, // 4: hyapp.user.v1.ReviewAgencyApplicationRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 4: hyapp.user.v1.ReviewAgencyApplicationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
7, // 5: hyapp.user.v1.ReviewAgencyApplicationResponse.application:type_name -> hyapp.user.v1.AgencyApplication 7, // 5: hyapp.user.v1.ReviewAgencyApplicationResponse.application:type_name -> hyapp.user.v1.AgencyApplication
0, // 6: hyapp.user.v1.ReviewAgencyApplicationResponse.host_profile:type_name -> hyapp.user.v1.HostProfile 0, // 6: hyapp.user.v1.ReviewAgencyApplicationResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
6, // 7: hyapp.user.v1.ReviewAgencyApplicationResponse.membership:type_name -> hyapp.user.v1.AgencyMembership 6, // 7: hyapp.user.v1.ReviewAgencyApplicationResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
76, // 8: hyapp.user.v1.KickAgencyHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 8: hyapp.user.v1.KickAgencyHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
6, // 9: hyapp.user.v1.KickAgencyHostResponse.membership:type_name -> hyapp.user.v1.AgencyMembership 6, // 9: hyapp.user.v1.KickAgencyHostResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
0, // 10: hyapp.user.v1.KickAgencyHostResponse.host_profile:type_name -> hyapp.user.v1.HostProfile 0, // 10: hyapp.user.v1.KickAgencyHostResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
76, // 11: hyapp.user.v1.InviteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 11: hyapp.user.v1.InviteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
8, // 12: hyapp.user.v1.InviteAgencyResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation 8, // 12: hyapp.user.v1.InviteAgencyResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
76, // 13: hyapp.user.v1.InviteBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 13: hyapp.user.v1.InviteBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta
8, // 14: hyapp.user.v1.InviteBDResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation 8, // 14: hyapp.user.v1.InviteBDResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
76, // 15: hyapp.user.v1.InviteHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 15: hyapp.user.v1.InviteHostRequest.meta:type_name -> hyapp.user.v1.RequestMeta
8, // 16: hyapp.user.v1.InviteHostResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation 8, // 16: hyapp.user.v1.InviteHostResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
76, // 17: hyapp.user.v1.ListBDLeaderBDsRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 17: hyapp.user.v1.ListBDLeaderBDsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
2, // 18: hyapp.user.v1.ListBDLeaderBDsResponse.bd_profiles:type_name -> hyapp.user.v1.BDProfile 2, // 18: hyapp.user.v1.ListBDLeaderBDsResponse.bd_profiles:type_name -> hyapp.user.v1.BDProfile
76, // 19: hyapp.user.v1.ListBDLeaderAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 19: hyapp.user.v1.ListBDLeaderAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 20: hyapp.user.v1.ListBDLeaderAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency 1, // 20: hyapp.user.v1.ListBDLeaderAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency
76, // 21: hyapp.user.v1.ListBDAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 21: hyapp.user.v1.ListBDAgenciesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 22: hyapp.user.v1.ListBDAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency 1, // 22: hyapp.user.v1.ListBDAgenciesResponse.agencies:type_name -> hyapp.user.v1.Agency
76, // 23: hyapp.user.v1.ListRoleInvitationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 23: hyapp.user.v1.ListRoleInvitationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
8, // 24: hyapp.user.v1.ListRoleInvitationsResponse.invitations:type_name -> hyapp.user.v1.RoleInvitation 8, // 24: hyapp.user.v1.ListRoleInvitationsResponse.invitations:type_name -> hyapp.user.v1.RoleInvitation
76, // 25: hyapp.user.v1.GetRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 25: hyapp.user.v1.GetRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
8, // 26: hyapp.user.v1.GetRoleInvitationResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation 8, // 26: hyapp.user.v1.GetRoleInvitationResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
76, // 27: hyapp.user.v1.ProcessRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 27: hyapp.user.v1.ProcessRoleInvitationRequest.meta:type_name -> hyapp.user.v1.RequestMeta
8, // 28: hyapp.user.v1.ProcessRoleInvitationResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation 8, // 28: hyapp.user.v1.ProcessRoleInvitationResponse.invitation:type_name -> hyapp.user.v1.RoleInvitation
0, // 29: hyapp.user.v1.ProcessRoleInvitationResponse.host_profile:type_name -> hyapp.user.v1.HostProfile 0, // 29: hyapp.user.v1.ProcessRoleInvitationResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
1, // 30: hyapp.user.v1.ProcessRoleInvitationResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 30: hyapp.user.v1.ProcessRoleInvitationResponse.agency:type_name -> hyapp.user.v1.Agency
6, // 31: hyapp.user.v1.ProcessRoleInvitationResponse.membership:type_name -> hyapp.user.v1.AgencyMembership 6, // 31: hyapp.user.v1.ProcessRoleInvitationResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
2, // 32: hyapp.user.v1.ProcessRoleInvitationResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile 2, // 32: hyapp.user.v1.ProcessRoleInvitationResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
76, // 33: hyapp.user.v1.GetHostProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 33: hyapp.user.v1.GetHostProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
0, // 34: hyapp.user.v1.GetHostProfileResponse.host_profile:type_name -> hyapp.user.v1.HostProfile 0, // 34: hyapp.user.v1.GetHostProfileResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
76, // 35: hyapp.user.v1.BatchGetHostProfilesRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 35: hyapp.user.v1.BatchGetHostProfilesRequest.meta:type_name -> hyapp.user.v1.RequestMeta
75, // 36: hyapp.user.v1.BatchGetHostProfilesResponse.host_profiles:type_name -> hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry 77, // 36: hyapp.user.v1.BatchGetHostProfilesResponse.host_profiles:type_name -> hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry
76, // 37: hyapp.user.v1.GetBDProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 37: hyapp.user.v1.GetBDProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
2, // 38: hyapp.user.v1.GetBDProfileResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile 2, // 38: hyapp.user.v1.GetBDProfileResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
76, // 39: hyapp.user.v1.GetCoinSellerProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 39: hyapp.user.v1.GetCoinSellerProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
3, // 40: hyapp.user.v1.GetCoinSellerProfileResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile 3, // 40: hyapp.user.v1.GetCoinSellerProfileResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile
76, // 41: hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 41: hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest.meta:type_name -> hyapp.user.v1.RequestMeta
4, // 42: hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse.coin_sellers:type_name -> hyapp.user.v1.CoinSellerListItem 4, // 42: hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse.coin_sellers:type_name -> hyapp.user.v1.CoinSellerListItem
76, // 43: hyapp.user.v1.GetUserRoleSummaryRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 43: hyapp.user.v1.GetUserRoleSummaryRequest.meta:type_name -> hyapp.user.v1.RequestMeta
5, // 44: hyapp.user.v1.GetUserRoleSummaryResponse.summary:type_name -> hyapp.user.v1.UserRoleSummary 5, // 44: hyapp.user.v1.GetUserRoleSummaryResponse.summary:type_name -> hyapp.user.v1.UserRoleSummary
76, // 45: hyapp.user.v1.GetAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 45: hyapp.user.v1.GetAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 46: hyapp.user.v1.GetAgencyResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 46: hyapp.user.v1.GetAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
76, // 47: hyapp.user.v1.CheckBusinessCapabilityRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 47: hyapp.user.v1.CheckBusinessCapabilityRequest.meta:type_name -> hyapp.user.v1.RequestMeta
76, // 48: hyapp.user.v1.GetAgencyMembersRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 48: hyapp.user.v1.GetAgencyMembersRequest.meta:type_name -> hyapp.user.v1.RequestMeta
6, // 49: hyapp.user.v1.GetAgencyMembersResponse.memberships:type_name -> hyapp.user.v1.AgencyMembership 6, // 49: hyapp.user.v1.GetAgencyMembersResponse.memberships:type_name -> hyapp.user.v1.AgencyMembership
76, // 50: hyapp.user.v1.GetAgencyApplicationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 50: hyapp.user.v1.GetAgencyApplicationsRequest.meta:type_name -> hyapp.user.v1.RequestMeta
7, // 51: hyapp.user.v1.GetAgencyApplicationsResponse.applications:type_name -> hyapp.user.v1.AgencyApplication 7, // 51: hyapp.user.v1.GetAgencyApplicationsResponse.applications:type_name -> hyapp.user.v1.AgencyApplication
76, // 52: hyapp.user.v1.CreateBDLeaderRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 52: hyapp.user.v1.CreateBDLeaderRequest.meta:type_name -> hyapp.user.v1.RequestMeta
2, // 53: hyapp.user.v1.CreateBDLeaderResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile 2, // 53: hyapp.user.v1.CreateBDLeaderResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
76, // 54: hyapp.user.v1.CreateBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 54: hyapp.user.v1.CreateBDRequest.meta:type_name -> hyapp.user.v1.RequestMeta
2, // 55: hyapp.user.v1.CreateBDResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile 2, // 55: hyapp.user.v1.CreateBDResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
76, // 56: hyapp.user.v1.SetBDStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 56: hyapp.user.v1.SetBDStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
2, // 57: hyapp.user.v1.SetBDStatusResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile 2, // 57: hyapp.user.v1.SetBDStatusResponse.bd_profile:type_name -> hyapp.user.v1.BDProfile
76, // 58: hyapp.user.v1.CreateCoinSellerRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 58: hyapp.user.v1.CreateCoinSellerRequest.meta:type_name -> hyapp.user.v1.RequestMeta
3, // 59: hyapp.user.v1.CreateCoinSellerResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile 3, // 59: hyapp.user.v1.CreateCoinSellerResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile
76, // 60: hyapp.user.v1.SetCoinSellerStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 60: hyapp.user.v1.SetCoinSellerStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
3, // 61: hyapp.user.v1.SetCoinSellerStatusResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile 3, // 61: hyapp.user.v1.SetCoinSellerStatusResponse.coin_seller_profile:type_name -> hyapp.user.v1.CoinSellerProfile
76, // 62: hyapp.user.v1.CreateAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 62: hyapp.user.v1.CreateAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 63: hyapp.user.v1.CreateAgencyResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 63: hyapp.user.v1.CreateAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
0, // 64: hyapp.user.v1.CreateAgencyResponse.host_profile:type_name -> hyapp.user.v1.HostProfile 0, // 64: hyapp.user.v1.CreateAgencyResponse.host_profile:type_name -> hyapp.user.v1.HostProfile
6, // 65: hyapp.user.v1.CreateAgencyResponse.membership:type_name -> hyapp.user.v1.AgencyMembership 6, // 65: hyapp.user.v1.CreateAgencyResponse.membership:type_name -> hyapp.user.v1.AgencyMembership
76, // 66: hyapp.user.v1.CloseAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 66: hyapp.user.v1.CloseAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 67: hyapp.user.v1.CloseAgencyResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 67: hyapp.user.v1.CloseAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
76, // 68: hyapp.user.v1.DeleteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 68: hyapp.user.v1.DeleteAgencyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 69: hyapp.user.v1.DeleteAgencyResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 69: hyapp.user.v1.DeleteAgencyResponse.agency:type_name -> hyapp.user.v1.Agency
76, // 70: hyapp.user.v1.SetAgencyStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 70: hyapp.user.v1.SetAgencyStatusRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 71: hyapp.user.v1.SetAgencyStatusResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 71: hyapp.user.v1.SetAgencyStatusResponse.agency:type_name -> hyapp.user.v1.Agency
76, // 72: hyapp.user.v1.SetAgencyJoinEnabledRequest.meta:type_name -> hyapp.user.v1.RequestMeta 78, // 72: hyapp.user.v1.SetAgencyJoinEnabledRequest.meta:type_name -> hyapp.user.v1.RequestMeta
1, // 73: hyapp.user.v1.SetAgencyJoinEnabledResponse.agency:type_name -> hyapp.user.v1.Agency 1, // 73: hyapp.user.v1.SetAgencyJoinEnabledResponse.agency:type_name -> hyapp.user.v1.Agency
0, // 74: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry.value:type_name -> hyapp.user.v1.HostProfile 78, // 74: hyapp.user.v1.UpdateAgencyProfileRequest.meta:type_name -> hyapp.user.v1.RequestMeta
9, // 75: hyapp.user.v1.UserHostService.SearchAgencies:input_type -> hyapp.user.v1.SearchAgenciesRequest 1, // 75: hyapp.user.v1.UpdateAgencyProfileResponse.agency:type_name -> hyapp.user.v1.Agency
11, // 76: hyapp.user.v1.UserHostService.ApplyToAgency:input_type -> hyapp.user.v1.ApplyToAgencyRequest 0, // 76: hyapp.user.v1.BatchGetHostProfilesResponse.HostProfilesEntry.value:type_name -> hyapp.user.v1.HostProfile
13, // 77: hyapp.user.v1.UserHostService.ReviewAgencyApplication:input_type -> hyapp.user.v1.ReviewAgencyApplicationRequest 9, // 77: hyapp.user.v1.UserHostService.SearchAgencies:input_type -> hyapp.user.v1.SearchAgenciesRequest
15, // 78: hyapp.user.v1.UserHostService.KickAgencyHost:input_type -> hyapp.user.v1.KickAgencyHostRequest 11, // 78: hyapp.user.v1.UserHostService.ApplyToAgency:input_type -> hyapp.user.v1.ApplyToAgencyRequest
17, // 79: hyapp.user.v1.UserHostService.InviteAgency:input_type -> hyapp.user.v1.InviteAgencyRequest 13, // 79: hyapp.user.v1.UserHostService.ReviewAgencyApplication:input_type -> hyapp.user.v1.ReviewAgencyApplicationRequest
19, // 80: hyapp.user.v1.UserHostService.InviteBD:input_type -> hyapp.user.v1.InviteBDRequest 15, // 80: hyapp.user.v1.UserHostService.KickAgencyHost:input_type -> hyapp.user.v1.KickAgencyHostRequest
21, // 81: hyapp.user.v1.UserHostService.InviteHost:input_type -> hyapp.user.v1.InviteHostRequest 17, // 81: hyapp.user.v1.UserHostService.InviteAgency:input_type -> hyapp.user.v1.InviteAgencyRequest
23, // 82: hyapp.user.v1.UserHostService.ListBDLeaderBDs:input_type -> hyapp.user.v1.ListBDLeaderBDsRequest 19, // 82: hyapp.user.v1.UserHostService.InviteBD:input_type -> hyapp.user.v1.InviteBDRequest
25, // 83: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:input_type -> hyapp.user.v1.ListBDLeaderAgenciesRequest 21, // 83: hyapp.user.v1.UserHostService.InviteHost:input_type -> hyapp.user.v1.InviteHostRequest
27, // 84: hyapp.user.v1.UserHostService.ListBDAgencies:input_type -> hyapp.user.v1.ListBDAgenciesRequest 23, // 84: hyapp.user.v1.UserHostService.ListBDLeaderBDs:input_type -> hyapp.user.v1.ListBDLeaderBDsRequest
29, // 85: hyapp.user.v1.UserHostService.ListRoleInvitations:input_type -> hyapp.user.v1.ListRoleInvitationsRequest 25, // 85: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:input_type -> hyapp.user.v1.ListBDLeaderAgenciesRequest
31, // 86: hyapp.user.v1.UserHostService.GetRoleInvitation:input_type -> hyapp.user.v1.GetRoleInvitationRequest 27, // 86: hyapp.user.v1.UserHostService.ListBDAgencies:input_type -> hyapp.user.v1.ListBDAgenciesRequest
33, // 87: hyapp.user.v1.UserHostService.ProcessRoleInvitation:input_type -> hyapp.user.v1.ProcessRoleInvitationRequest 29, // 87: hyapp.user.v1.UserHostService.ListRoleInvitations:input_type -> hyapp.user.v1.ListRoleInvitationsRequest
35, // 88: hyapp.user.v1.UserHostService.GetHostProfile:input_type -> hyapp.user.v1.GetHostProfileRequest 31, // 88: hyapp.user.v1.UserHostService.GetRoleInvitation:input_type -> hyapp.user.v1.GetRoleInvitationRequest
37, // 89: hyapp.user.v1.UserHostService.BatchGetHostProfiles:input_type -> hyapp.user.v1.BatchGetHostProfilesRequest 33, // 89: hyapp.user.v1.UserHostService.ProcessRoleInvitation:input_type -> hyapp.user.v1.ProcessRoleInvitationRequest
39, // 90: hyapp.user.v1.UserHostService.GetBDProfile:input_type -> hyapp.user.v1.GetBDProfileRequest 35, // 90: hyapp.user.v1.UserHostService.GetHostProfile:input_type -> hyapp.user.v1.GetHostProfileRequest
41, // 91: hyapp.user.v1.UserHostService.GetCoinSellerProfile:input_type -> hyapp.user.v1.GetCoinSellerProfileRequest 37, // 91: hyapp.user.v1.UserHostService.BatchGetHostProfiles:input_type -> hyapp.user.v1.BatchGetHostProfilesRequest
43, // 92: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:input_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest 39, // 92: hyapp.user.v1.UserHostService.GetBDProfile:input_type -> hyapp.user.v1.GetBDProfileRequest
45, // 93: hyapp.user.v1.UserHostService.GetUserRoleSummary:input_type -> hyapp.user.v1.GetUserRoleSummaryRequest 41, // 93: hyapp.user.v1.UserHostService.GetCoinSellerProfile:input_type -> hyapp.user.v1.GetCoinSellerProfileRequest
47, // 94: hyapp.user.v1.UserHostService.GetAgency:input_type -> hyapp.user.v1.GetAgencyRequest 43, // 94: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:input_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionRequest
49, // 95: hyapp.user.v1.UserHostService.CheckBusinessCapability:input_type -> hyapp.user.v1.CheckBusinessCapabilityRequest 45, // 95: hyapp.user.v1.UserHostService.GetUserRoleSummary:input_type -> hyapp.user.v1.GetUserRoleSummaryRequest
51, // 96: hyapp.user.v1.UserHostService.GetAgencyMembers:input_type -> hyapp.user.v1.GetAgencyMembersRequest 47, // 96: hyapp.user.v1.UserHostService.GetAgency:input_type -> hyapp.user.v1.GetAgencyRequest
53, // 97: hyapp.user.v1.UserHostService.GetAgencyApplications:input_type -> hyapp.user.v1.GetAgencyApplicationsRequest 49, // 97: hyapp.user.v1.UserHostService.CheckBusinessCapability:input_type -> hyapp.user.v1.CheckBusinessCapabilityRequest
55, // 98: hyapp.user.v1.UserHostAdminService.CreateBDLeader:input_type -> hyapp.user.v1.CreateBDLeaderRequest 51, // 98: hyapp.user.v1.UserHostService.GetAgencyMembers:input_type -> hyapp.user.v1.GetAgencyMembersRequest
57, // 99: hyapp.user.v1.UserHostAdminService.CreateBD:input_type -> hyapp.user.v1.CreateBDRequest 53, // 99: hyapp.user.v1.UserHostService.GetAgencyApplications:input_type -> hyapp.user.v1.GetAgencyApplicationsRequest
59, // 100: hyapp.user.v1.UserHostAdminService.SetBDStatus:input_type -> hyapp.user.v1.SetBDStatusRequest 75, // 100: hyapp.user.v1.UserHostService.UpdateAgencyProfile:input_type -> hyapp.user.v1.UpdateAgencyProfileRequest
61, // 101: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:input_type -> hyapp.user.v1.CreateCoinSellerRequest 55, // 101: hyapp.user.v1.UserHostAdminService.CreateBDLeader:input_type -> hyapp.user.v1.CreateBDLeaderRequest
63, // 102: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:input_type -> hyapp.user.v1.SetCoinSellerStatusRequest 57, // 102: hyapp.user.v1.UserHostAdminService.CreateBD:input_type -> hyapp.user.v1.CreateBDRequest
65, // 103: hyapp.user.v1.UserHostAdminService.CreateAgency:input_type -> hyapp.user.v1.CreateAgencyRequest 59, // 103: hyapp.user.v1.UserHostAdminService.SetBDStatus:input_type -> hyapp.user.v1.SetBDStatusRequest
67, // 104: hyapp.user.v1.UserHostAdminService.CloseAgency:input_type -> hyapp.user.v1.CloseAgencyRequest 61, // 104: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:input_type -> hyapp.user.v1.CreateCoinSellerRequest
69, // 105: hyapp.user.v1.UserHostAdminService.DeleteAgency:input_type -> hyapp.user.v1.DeleteAgencyRequest 63, // 105: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:input_type -> hyapp.user.v1.SetCoinSellerStatusRequest
71, // 106: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:input_type -> hyapp.user.v1.SetAgencyStatusRequest 65, // 106: hyapp.user.v1.UserHostAdminService.CreateAgency:input_type -> hyapp.user.v1.CreateAgencyRequest
73, // 107: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:input_type -> hyapp.user.v1.SetAgencyJoinEnabledRequest 67, // 107: hyapp.user.v1.UserHostAdminService.CloseAgency:input_type -> hyapp.user.v1.CloseAgencyRequest
10, // 108: hyapp.user.v1.UserHostService.SearchAgencies:output_type -> hyapp.user.v1.SearchAgenciesResponse 69, // 108: hyapp.user.v1.UserHostAdminService.DeleteAgency:input_type -> hyapp.user.v1.DeleteAgencyRequest
12, // 109: hyapp.user.v1.UserHostService.ApplyToAgency:output_type -> hyapp.user.v1.ApplyToAgencyResponse 71, // 109: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:input_type -> hyapp.user.v1.SetAgencyStatusRequest
14, // 110: hyapp.user.v1.UserHostService.ReviewAgencyApplication:output_type -> hyapp.user.v1.ReviewAgencyApplicationResponse 73, // 110: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:input_type -> hyapp.user.v1.SetAgencyJoinEnabledRequest
16, // 111: hyapp.user.v1.UserHostService.KickAgencyHost:output_type -> hyapp.user.v1.KickAgencyHostResponse 10, // 111: hyapp.user.v1.UserHostService.SearchAgencies:output_type -> hyapp.user.v1.SearchAgenciesResponse
18, // 112: hyapp.user.v1.UserHostService.InviteAgency:output_type -> hyapp.user.v1.InviteAgencyResponse 12, // 112: hyapp.user.v1.UserHostService.ApplyToAgency:output_type -> hyapp.user.v1.ApplyToAgencyResponse
20, // 113: hyapp.user.v1.UserHostService.InviteBD:output_type -> hyapp.user.v1.InviteBDResponse 14, // 113: hyapp.user.v1.UserHostService.ReviewAgencyApplication:output_type -> hyapp.user.v1.ReviewAgencyApplicationResponse
22, // 114: hyapp.user.v1.UserHostService.InviteHost:output_type -> hyapp.user.v1.InviteHostResponse 16, // 114: hyapp.user.v1.UserHostService.KickAgencyHost:output_type -> hyapp.user.v1.KickAgencyHostResponse
24, // 115: hyapp.user.v1.UserHostService.ListBDLeaderBDs:output_type -> hyapp.user.v1.ListBDLeaderBDsResponse 18, // 115: hyapp.user.v1.UserHostService.InviteAgency:output_type -> hyapp.user.v1.InviteAgencyResponse
26, // 116: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:output_type -> hyapp.user.v1.ListBDLeaderAgenciesResponse 20, // 116: hyapp.user.v1.UserHostService.InviteBD:output_type -> hyapp.user.v1.InviteBDResponse
28, // 117: hyapp.user.v1.UserHostService.ListBDAgencies:output_type -> hyapp.user.v1.ListBDAgenciesResponse 22, // 117: hyapp.user.v1.UserHostService.InviteHost:output_type -> hyapp.user.v1.InviteHostResponse
30, // 118: hyapp.user.v1.UserHostService.ListRoleInvitations:output_type -> hyapp.user.v1.ListRoleInvitationsResponse 24, // 118: hyapp.user.v1.UserHostService.ListBDLeaderBDs:output_type -> hyapp.user.v1.ListBDLeaderBDsResponse
32, // 119: hyapp.user.v1.UserHostService.GetRoleInvitation:output_type -> hyapp.user.v1.GetRoleInvitationResponse 26, // 119: hyapp.user.v1.UserHostService.ListBDLeaderAgencies:output_type -> hyapp.user.v1.ListBDLeaderAgenciesResponse
34, // 120: hyapp.user.v1.UserHostService.ProcessRoleInvitation:output_type -> hyapp.user.v1.ProcessRoleInvitationResponse 28, // 120: hyapp.user.v1.UserHostService.ListBDAgencies:output_type -> hyapp.user.v1.ListBDAgenciesResponse
36, // 121: hyapp.user.v1.UserHostService.GetHostProfile:output_type -> hyapp.user.v1.GetHostProfileResponse 30, // 121: hyapp.user.v1.UserHostService.ListRoleInvitations:output_type -> hyapp.user.v1.ListRoleInvitationsResponse
38, // 122: hyapp.user.v1.UserHostService.BatchGetHostProfiles:output_type -> hyapp.user.v1.BatchGetHostProfilesResponse 32, // 122: hyapp.user.v1.UserHostService.GetRoleInvitation:output_type -> hyapp.user.v1.GetRoleInvitationResponse
40, // 123: hyapp.user.v1.UserHostService.GetBDProfile:output_type -> hyapp.user.v1.GetBDProfileResponse 34, // 123: hyapp.user.v1.UserHostService.ProcessRoleInvitation:output_type -> hyapp.user.v1.ProcessRoleInvitationResponse
42, // 124: hyapp.user.v1.UserHostService.GetCoinSellerProfile:output_type -> hyapp.user.v1.GetCoinSellerProfileResponse 36, // 124: hyapp.user.v1.UserHostService.GetHostProfile:output_type -> hyapp.user.v1.GetHostProfileResponse
44, // 125: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:output_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse 38, // 125: hyapp.user.v1.UserHostService.BatchGetHostProfiles:output_type -> hyapp.user.v1.BatchGetHostProfilesResponse
46, // 126: hyapp.user.v1.UserHostService.GetUserRoleSummary:output_type -> hyapp.user.v1.GetUserRoleSummaryResponse 40, // 126: hyapp.user.v1.UserHostService.GetBDProfile:output_type -> hyapp.user.v1.GetBDProfileResponse
48, // 127: hyapp.user.v1.UserHostService.GetAgency:output_type -> hyapp.user.v1.GetAgencyResponse 42, // 127: hyapp.user.v1.UserHostService.GetCoinSellerProfile:output_type -> hyapp.user.v1.GetCoinSellerProfileResponse
50, // 128: hyapp.user.v1.UserHostService.CheckBusinessCapability:output_type -> hyapp.user.v1.CheckBusinessCapabilityResponse 44, // 128: hyapp.user.v1.UserHostService.ListActiveCoinSellersInMyRegion:output_type -> hyapp.user.v1.ListActiveCoinSellersInMyRegionResponse
52, // 129: hyapp.user.v1.UserHostService.GetAgencyMembers:output_type -> hyapp.user.v1.GetAgencyMembersResponse 46, // 129: hyapp.user.v1.UserHostService.GetUserRoleSummary:output_type -> hyapp.user.v1.GetUserRoleSummaryResponse
54, // 130: hyapp.user.v1.UserHostService.GetAgencyApplications:output_type -> hyapp.user.v1.GetAgencyApplicationsResponse 48, // 130: hyapp.user.v1.UserHostService.GetAgency:output_type -> hyapp.user.v1.GetAgencyResponse
56, // 131: hyapp.user.v1.UserHostAdminService.CreateBDLeader:output_type -> hyapp.user.v1.CreateBDLeaderResponse 50, // 131: hyapp.user.v1.UserHostService.CheckBusinessCapability:output_type -> hyapp.user.v1.CheckBusinessCapabilityResponse
58, // 132: hyapp.user.v1.UserHostAdminService.CreateBD:output_type -> hyapp.user.v1.CreateBDResponse 52, // 132: hyapp.user.v1.UserHostService.GetAgencyMembers:output_type -> hyapp.user.v1.GetAgencyMembersResponse
60, // 133: hyapp.user.v1.UserHostAdminService.SetBDStatus:output_type -> hyapp.user.v1.SetBDStatusResponse 54, // 133: hyapp.user.v1.UserHostService.GetAgencyApplications:output_type -> hyapp.user.v1.GetAgencyApplicationsResponse
62, // 134: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:output_type -> hyapp.user.v1.CreateCoinSellerResponse 76, // 134: hyapp.user.v1.UserHostService.UpdateAgencyProfile:output_type -> hyapp.user.v1.UpdateAgencyProfileResponse
64, // 135: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:output_type -> hyapp.user.v1.SetCoinSellerStatusResponse 56, // 135: hyapp.user.v1.UserHostAdminService.CreateBDLeader:output_type -> hyapp.user.v1.CreateBDLeaderResponse
66, // 136: hyapp.user.v1.UserHostAdminService.CreateAgency:output_type -> hyapp.user.v1.CreateAgencyResponse 58, // 136: hyapp.user.v1.UserHostAdminService.CreateBD:output_type -> hyapp.user.v1.CreateBDResponse
68, // 137: hyapp.user.v1.UserHostAdminService.CloseAgency:output_type -> hyapp.user.v1.CloseAgencyResponse 60, // 137: hyapp.user.v1.UserHostAdminService.SetBDStatus:output_type -> hyapp.user.v1.SetBDStatusResponse
70, // 138: hyapp.user.v1.UserHostAdminService.DeleteAgency:output_type -> hyapp.user.v1.DeleteAgencyResponse 62, // 138: hyapp.user.v1.UserHostAdminService.CreateCoinSeller:output_type -> hyapp.user.v1.CreateCoinSellerResponse
72, // 139: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:output_type -> hyapp.user.v1.SetAgencyStatusResponse 64, // 139: hyapp.user.v1.UserHostAdminService.SetCoinSellerStatus:output_type -> hyapp.user.v1.SetCoinSellerStatusResponse
74, // 140: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:output_type -> hyapp.user.v1.SetAgencyJoinEnabledResponse 66, // 140: hyapp.user.v1.UserHostAdminService.CreateAgency:output_type -> hyapp.user.v1.CreateAgencyResponse
108, // [108:141] is the sub-list for method output_type 68, // 141: hyapp.user.v1.UserHostAdminService.CloseAgency:output_type -> hyapp.user.v1.CloseAgencyResponse
75, // [75:108] is the sub-list for method input_type 70, // 142: hyapp.user.v1.UserHostAdminService.DeleteAgency:output_type -> hyapp.user.v1.DeleteAgencyResponse
75, // [75:75] is the sub-list for extension type_name 72, // 143: hyapp.user.v1.UserHostAdminService.SetAgencyStatus:output_type -> hyapp.user.v1.SetAgencyStatusResponse
75, // [75:75] is the sub-list for extension extendee 74, // 144: hyapp.user.v1.UserHostAdminService.SetAgencyJoinEnabled:output_type -> hyapp.user.v1.SetAgencyJoinEnabledResponse
0, // [0:75] is the sub-list for field type_name 111, // [111:145] is the sub-list for method output_type
77, // [77:111] is the sub-list for method input_type
77, // [77:77] is the sub-list for extension type_name
77, // [77:77] is the sub-list for extension extendee
0, // [0:77] is the sub-list for field type_name
} }
func init() { file_proto_user_v1_host_proto_init() } func init() { file_proto_user_v1_host_proto_init() }
@ -6417,13 +6581,14 @@ func file_proto_user_v1_host_proto_init() {
return return
} }
file_proto_user_v1_user_proto_init() file_proto_user_v1_user_proto_init()
file_proto_user_v1_host_proto_msgTypes[75].OneofWrappers = []any{}
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_proto_user_v1_host_proto_rawDesc, RawDescriptor: file_proto_user_v1_host_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 76, NumMessages: 78,
NumExtensions: 0, NumExtensions: 0,
NumServices: 2, NumServices: 2,
}, },

View File

@ -533,6 +533,19 @@ message SetAgencyJoinEnabledResponse {
Agency agency = 1; Agency agency = 1;
} }
message UpdateAgencyProfileRequest {
RequestMeta meta = 1;
string command_id = 2;
int64 operator_user_id = 3;
int64 agency_id = 4;
optional string name = 5;
optional string avatar = 6;
}
message UpdateAgencyProfileResponse {
Agency agency = 1;
}
// UserHostService user-service host domain gRPC // UserHostService user-service host domain gRPC
service UserHostService { service UserHostService {
rpc SearchAgencies(SearchAgenciesRequest) returns (SearchAgenciesResponse); rpc SearchAgencies(SearchAgenciesRequest) returns (SearchAgenciesResponse);
@ -558,6 +571,7 @@ service UserHostService {
rpc CheckBusinessCapability(CheckBusinessCapabilityRequest) returns (CheckBusinessCapabilityResponse); rpc CheckBusinessCapability(CheckBusinessCapabilityRequest) returns (CheckBusinessCapabilityResponse);
rpc GetAgencyMembers(GetAgencyMembersRequest) returns (GetAgencyMembersResponse); rpc GetAgencyMembers(GetAgencyMembersRequest) returns (GetAgencyMembersResponse);
rpc GetAgencyApplications(GetAgencyApplicationsRequest) returns (GetAgencyApplicationsResponse); rpc GetAgencyApplications(GetAgencyApplicationsRequest) returns (GetAgencyApplicationsResponse);
rpc UpdateAgencyProfile(UpdateAgencyProfileRequest) returns (UpdateAgencyProfileResponse);
} }
// UserHostAdminService admin admin-server // UserHostAdminService admin admin-server

View File

@ -42,6 +42,7 @@ const (
UserHostService_CheckBusinessCapability_FullMethodName = "/hyapp.user.v1.UserHostService/CheckBusinessCapability" UserHostService_CheckBusinessCapability_FullMethodName = "/hyapp.user.v1.UserHostService/CheckBusinessCapability"
UserHostService_GetAgencyMembers_FullMethodName = "/hyapp.user.v1.UserHostService/GetAgencyMembers" UserHostService_GetAgencyMembers_FullMethodName = "/hyapp.user.v1.UserHostService/GetAgencyMembers"
UserHostService_GetAgencyApplications_FullMethodName = "/hyapp.user.v1.UserHostService/GetAgencyApplications" UserHostService_GetAgencyApplications_FullMethodName = "/hyapp.user.v1.UserHostService/GetAgencyApplications"
UserHostService_UpdateAgencyProfile_FullMethodName = "/hyapp.user.v1.UserHostService/UpdateAgencyProfile"
) )
// UserHostServiceClient is the client API for UserHostService service. // UserHostServiceClient is the client API for UserHostService service.
@ -73,6 +74,7 @@ type UserHostServiceClient interface {
CheckBusinessCapability(ctx context.Context, in *CheckBusinessCapabilityRequest, opts ...grpc.CallOption) (*CheckBusinessCapabilityResponse, error) CheckBusinessCapability(ctx context.Context, in *CheckBusinessCapabilityRequest, opts ...grpc.CallOption) (*CheckBusinessCapabilityResponse, error)
GetAgencyMembers(ctx context.Context, in *GetAgencyMembersRequest, opts ...grpc.CallOption) (*GetAgencyMembersResponse, error) GetAgencyMembers(ctx context.Context, in *GetAgencyMembersRequest, opts ...grpc.CallOption) (*GetAgencyMembersResponse, error)
GetAgencyApplications(ctx context.Context, in *GetAgencyApplicationsRequest, opts ...grpc.CallOption) (*GetAgencyApplicationsResponse, error) GetAgencyApplications(ctx context.Context, in *GetAgencyApplicationsRequest, opts ...grpc.CallOption) (*GetAgencyApplicationsResponse, error)
UpdateAgencyProfile(ctx context.Context, in *UpdateAgencyProfileRequest, opts ...grpc.CallOption) (*UpdateAgencyProfileResponse, error)
} }
type userHostServiceClient struct { type userHostServiceClient struct {
@ -313,6 +315,16 @@ func (c *userHostServiceClient) GetAgencyApplications(ctx context.Context, in *G
return out, nil return out, nil
} }
func (c *userHostServiceClient) UpdateAgencyProfile(ctx context.Context, in *UpdateAgencyProfileRequest, opts ...grpc.CallOption) (*UpdateAgencyProfileResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UpdateAgencyProfileResponse)
err := c.cc.Invoke(ctx, UserHostService_UpdateAgencyProfile_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// UserHostServiceServer is the server API for UserHostService service. // UserHostServiceServer is the server API for UserHostService service.
// All implementations must embed UnimplementedUserHostServiceServer // All implementations must embed UnimplementedUserHostServiceServer
// for forward compatibility. // for forward compatibility.
@ -342,6 +354,7 @@ type UserHostServiceServer interface {
CheckBusinessCapability(context.Context, *CheckBusinessCapabilityRequest) (*CheckBusinessCapabilityResponse, error) CheckBusinessCapability(context.Context, *CheckBusinessCapabilityRequest) (*CheckBusinessCapabilityResponse, error)
GetAgencyMembers(context.Context, *GetAgencyMembersRequest) (*GetAgencyMembersResponse, error) GetAgencyMembers(context.Context, *GetAgencyMembersRequest) (*GetAgencyMembersResponse, error)
GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error) GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error)
UpdateAgencyProfile(context.Context, *UpdateAgencyProfileRequest) (*UpdateAgencyProfileResponse, error)
mustEmbedUnimplementedUserHostServiceServer() mustEmbedUnimplementedUserHostServiceServer()
} }
@ -421,6 +434,9 @@ func (UnimplementedUserHostServiceServer) GetAgencyMembers(context.Context, *Get
func (UnimplementedUserHostServiceServer) GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error) { func (UnimplementedUserHostServiceServer) GetAgencyApplications(context.Context, *GetAgencyApplicationsRequest) (*GetAgencyApplicationsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetAgencyApplications not implemented") return nil, status.Errorf(codes.Unimplemented, "method GetAgencyApplications not implemented")
} }
func (UnimplementedUserHostServiceServer) UpdateAgencyProfile(context.Context, *UpdateAgencyProfileRequest) (*UpdateAgencyProfileResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UpdateAgencyProfile not implemented")
}
func (UnimplementedUserHostServiceServer) mustEmbedUnimplementedUserHostServiceServer() {} func (UnimplementedUserHostServiceServer) mustEmbedUnimplementedUserHostServiceServer() {}
func (UnimplementedUserHostServiceServer) testEmbeddedByValue() {} func (UnimplementedUserHostServiceServer) testEmbeddedByValue() {}
@ -856,6 +872,24 @@ func _UserHostService_GetAgencyApplications_Handler(srv interface{}, ctx context
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _UserHostService_UpdateAgencyProfile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateAgencyProfileRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UserHostServiceServer).UpdateAgencyProfile(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: UserHostService_UpdateAgencyProfile_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UserHostServiceServer).UpdateAgencyProfile(ctx, req.(*UpdateAgencyProfileRequest))
}
return interceptor(ctx, in, info, handler)
}
// UserHostService_ServiceDesc is the grpc.ServiceDesc for UserHostService service. // UserHostService_ServiceDesc is the grpc.ServiceDesc for UserHostService service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -955,6 +989,10 @@ var UserHostService_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetAgencyApplications", MethodName: "GetAgencyApplications",
Handler: _UserHostService_GetAgencyApplications_Handler, Handler: _UserHostService_GetAgencyApplications_Handler,
}, },
{
MethodName: "UpdateAgencyProfile",
Handler: _UserHostService_UpdateAgencyProfile_Handler,
},
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{},
Metadata: "proto/user/v1/host.proto", Metadata: "proto/user/v1/host.proto",

View File

@ -0,0 +1,296 @@
# Agency 资料与房间 Flutter 对接
## 基础约定
本地开发地址:
```text
http://127.0.0.1:13000
```
所有接口都是登录接口,需要带登录 token。
请求头:
| Header | 必填 | 说明 |
| --- | --- | --- |
| `Authorization` | 是 | `Bearer <access_token>`。 |
| `X-App-Code` | 否 | App 编码,默认 `lalu`;登录态接口最终以 token 内 app_code 为准。 |
成功和失败都使用统一 envelope
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_xxx",
"data": {}
}
```
客户端分支只判断 `code`,排查问题记录 `request_id`
## 1. 查询用户所属 Agency 资料
地址:
```http
GET /api/v1/agencies/profile
```
参数:
| 参数 | 位置 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- | --- |
| `user_id` | query | 是 | string/int64 | 被查看的 host 用户 ID。 |
示例:
```http
GET /api/v1/agencies/profile?user_id=10001
Authorization: Bearer <access_token>
X-App-Code: lalu
```
返回值:
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_abc",
"data": {
"agency": {
"agency_id": "7001",
"owner_user_id": "99",
"region_id": 30,
"parent_bd_user_id": "501",
"name": "Yumi Star Agency",
"avatar": "https://cdn.example/agency.png",
"host_count": 20,
"status": "active",
"join_enabled": true,
"created_by_user_id": "1",
"created_at_ms": 1710000000000,
"updated_at_ms": 1710000001000
}
}
}
```
没有 active host 身份,或没有 active agency 归属时:
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_abc",
"data": {
"agency": null
}
}
```
字段说明:
| 字段 | 说明 |
| --- | --- |
| `agency_id` | Agency ID字符串。 |
| `owner_user_id` | Agency 会长用户 ID字符串。 |
| `name` | Agency 自己的名称,不再读 owner 用户昵称。 |
| `avatar` | Agency 自己的头像,不再读 owner 用户头像。 |
| `host_count` | 当前 active host 数量。 |
| `status` | 当前只展示 `active`。 |
| `join_enabled` | 是否允许用户申请加入。 |
| `created_at_ms` / `updated_at_ms` | Unix epoch milliseconds。 |
## 2. 查询 Agency 下所有 host 的房间
地址:
```http
GET /api/v1/agencies/rooms
```
参数:
| 参数 | 位置 | 必填 | 类型 | 默认 | 说明 |
| --- | --- | --- | --- | --- | --- |
| `user_id` | query | 是 | string/int64 | 无 | 被查看的 host 用户 ID。 |
| `limit` | query | 否 | int | 20 | 每页数量,最大 50。 |
| `cursor` | query | 否 | string | 空 | 下一页 cursor。 |
| `tab` | query | 否 | string | `hot` | `hot``new`。 |
| `query` | query | 否 | string | 空 | 搜索房间标题、房间 ID 或短号。 |
示例:
```http
GET /api/v1/agencies/rooms?user_id=10001&tab=hot&limit=20
Authorization: Bearer <access_token>
X-App-Code: lalu
```
返回值:
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_abc",
"data": {
"agency_id": "7001",
"rooms": [
{
"room_id": "room_101",
"im_group_id": "room_101",
"owner_user_id": "101",
"title": "Agency Room",
"cover_url": "https://cdn.example/room.png",
"mode": "voice",
"status": "active",
"locked": false,
"heat": 88,
"online_count": 12,
"seat_count": 8,
"occupied_seat_count": 3,
"visible_region_id": 30,
"app_code": "lalu",
"room_short_id": "M20",
"country_code": "AE",
"country_flag": "🇦🇪"
}
],
"next_cursor": "cursor_xxx"
}
}
```
没有 active host 身份,或没有 active agency 归属时:
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_abc",
"data": {
"agency_id": "",
"rooms": [],
"next_cursor": ""
}
}
```
字段说明:
| 字段 | 说明 |
| --- | --- |
| `agency_id` | 当前查询到的 Agency ID无归属时为空字符串。 |
| `rooms` | Agency 下所有 active host 的 active 房间。 |
| `next_cursor` | 下一页 cursor为空表示没有下一页。 |
| `room_id` | 房间 ID。 |
| `im_group_id` | 腾讯云 IM 房间群 ID进群使用这个字段。 |
| `owner_user_id` | 房主用户 ID字符串。 |
| `title` | 房间名。 |
| `cover_url` | 房间封面。 |
| `locked` | 是否锁房。 |
| `heat` | 房间热度。 |
| `online_count` | 在线人数。 |
| `seat_count` | 麦位数量。 |
| `occupied_seat_count` | 已占用麦位数量。 |
| `room_short_id` | 房间短号。 |
| `country_code` / `country_flag` | 房主国家展示字段。 |
## 3. 修改 Agency 资料
地址:
```http
POST /api/v1/agencies/profile/update
```
权限:
只有当前登录用户是 active Agency owner 时可以修改。普通 host、Agency 成员、BD、非 active owner 都不能修改。
参数:
| 参数 | 位置 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- | --- |
| `command_id` | body | 是 | string | 客户端生成的幂等 ID。 |
| `name` | body | 否 | string | 新 Agency 名称。 |
| `avatar` | body | 否 | string | 新 Agency 头像 URL。 |
`name``avatar` 至少传一个;传了就不能是空字符串。修改 Agency 资料不会修改 owner 用户昵称和头像。
示例:
```http
POST /api/v1/agencies/profile/update
Authorization: Bearer <access_token>
X-App-Code: lalu
Content-Type: application/json
{
"command_id": "cmd_agency_profile_001",
"name": "New Agency Name",
"avatar": "https://cdn.example/new-agency.png"
}
```
返回值:
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_abc",
"data": {
"agency": {
"agency_id": "7001",
"owner_user_id": "42",
"region_id": 30,
"name": "New Agency Name",
"avatar": "https://cdn.example/new-agency.png",
"host_count": 20,
"status": "active",
"join_enabled": true,
"created_at_ms": 1710000000000,
"updated_at_ms": 1710000005000
}
}
}
```
## 错误处理
失败返回:
```json
{
"code": "INVALID_ARGUMENT",
"message": "invalid argument",
"request_id": "req_abc"
}
```
| HTTP 状态码 | `code` | 处理方式 |
| --- | --- | --- |
| `400` | `INVALID_ARGUMENT` | 参数错误,例如 `user_id` 非法、`tab` 非法、`limit` 非法、缺少 `command_id``name/avatar` 都没传或传空。 |
| `401` | `UNAUTHORIZED` | token 缺失、无效或过期,重新登录。 |
| `403` | `PROFILE_REQUIRED` | 用户资料未完成,跳转资料补全。 |
| `403` | `PERMISSION_DENIED` | 修改接口中当前用户不是 active Agency owner不允许修改。 |
| `404` | `NOT_FOUND` | 修改接口中 Agency 事实不存在;刷新当前用户身份后再进入页面。 |
| `409` | `CONFLICT` | `command_id` 与已有不同命令冲突;重新生成新的 `command_id` 再提交。 |
| `502` | `UPSTREAM_ERROR` | 服务暂不可用,可以提示稍后重试。 |
客户端处理规则:
1. 查询资料时,`agency == null` 是正常空状态,不弹错误。
2. 查询房间时,`rooms == []` 是正常空列表,不弹错误。
3. 修改资料成功后,用返回的 `data.agency` 刷新页面,不要用 owner 用户资料覆盖。
4. 修改失败时保留本地未保存状态,让用户可以重试。
5. 所有失败日志记录 `request_id`
## 相关 IM
无。Agency 资料修改和 Agency 房间列表不会下发新的 IM房间卡片里的 `im_group_id` 只用于进入房间时加入腾讯云 IM 房间群。

View File

@ -615,6 +615,7 @@ type Agency struct {
RegionID int64 `json:"regionId"` RegionID int64 `json:"regionId"`
ParentBDUserID int64 `json:"parentBdUserId,string"` ParentBDUserID int64 `json:"parentBdUserId,string"`
Name string `json:"name"` Name string `json:"name"`
Avatar string `json:"avatar"`
Status string `json:"status"` Status string `json:"status"`
JoinEnabled bool `json:"joinEnabled"` JoinEnabled bool `json:"joinEnabled"`
MaxHosts int32 `json:"maxHosts"` MaxHosts int32 `json:"maxHosts"`
@ -895,6 +896,7 @@ func fromProtoAgency(agency *userv1.Agency) *Agency {
RegionID: agency.GetRegionId(), RegionID: agency.GetRegionId(),
ParentBDUserID: agency.GetParentBdUserId(), ParentBDUserID: agency.GetParentBdUserId(),
Name: agency.GetName(), Name: agency.GetName(),
Avatar: agency.GetAvatar(),
Status: agency.GetStatus(), Status: agency.GetStatus(),
JoinEnabled: agency.GetJoinEnabled(), JoinEnabled: agency.GetJoinEnabled(),
MaxHosts: agency.GetMaxHosts(), MaxHosts: agency.GetMaxHosts(),

View File

@ -213,7 +213,7 @@ type createAgencyRequest struct {
CommandID string `json:"commandId" binding:"required"` CommandID string `json:"commandId" binding:"required"`
OwnerUserID flexibleInt64 `json:"ownerUserId" binding:"required"` OwnerUserID flexibleInt64 `json:"ownerUserId" binding:"required"`
ParentBDUserID flexibleInt64 `json:"parentBdUserId"` ParentBDUserID flexibleInt64 `json:"parentBdUserId"`
Name string `json:"name" binding:"required"` Name string `json:"name"`
JoinEnabled *bool `json:"joinEnabled" binding:"required"` JoinEnabled *bool `json:"joinEnabled" binding:"required"`
Reason string `json:"reason"` Reason string `json:"reason"`
} }

View File

@ -45,6 +45,7 @@ type RoomGuardClient interface {
// RoomQueryClient 抽象 gateway 对 room-service 读模型查询的依赖。 // RoomQueryClient 抽象 gateway 对 room-service 读模型查询的依赖。
type RoomQueryClient interface { type RoomQueryClient interface {
ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*roomv1.ListRoomsResponse, error) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*roomv1.ListRoomsResponse, error)
ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error)
ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error)
ListRoomGiftLeaderboard(ctx context.Context, req *roomv1.ListRoomGiftLeaderboardRequest) (*roomv1.ListRoomGiftLeaderboardResponse, error) ListRoomGiftLeaderboard(ctx context.Context, req *roomv1.ListRoomGiftLeaderboardRequest) (*roomv1.ListRoomGiftLeaderboardResponse, error)
GetMyRoom(ctx context.Context, req *roomv1.GetMyRoomRequest) (*roomv1.GetMyRoomResponse, error) GetMyRoom(ctx context.Context, req *roomv1.GetMyRoomRequest) (*roomv1.GetMyRoomResponse, error)
@ -197,6 +198,10 @@ func (c *grpcRoomQueryClient) ListRooms(ctx context.Context, req *roomv1.ListRoo
return c.client.ListRooms(ctx, req) return c.client.ListRooms(ctx, req)
} }
func (c *grpcRoomQueryClient) ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
return c.client.ListRoomsByOwners(ctx, req)
}
func (c *grpcRoomQueryClient) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) { func (c *grpcRoomQueryClient) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
return c.client.ListRoomFeeds(ctx, req) return c.client.ListRoomFeeds(ctx, req)
} }

View File

@ -119,6 +119,7 @@ type UserHostClient interface {
ListActiveCoinSellersInMyRegion(ctx context.Context, req *userv1.ListActiveCoinSellersInMyRegionRequest) (*userv1.ListActiveCoinSellersInMyRegionResponse, error) ListActiveCoinSellersInMyRegion(ctx context.Context, req *userv1.ListActiveCoinSellersInMyRegionRequest) (*userv1.ListActiveCoinSellersInMyRegionResponse, error)
GetUserRoleSummary(ctx context.Context, req *userv1.GetUserRoleSummaryRequest) (*userv1.GetUserRoleSummaryResponse, error) GetUserRoleSummary(ctx context.Context, req *userv1.GetUserRoleSummaryRequest) (*userv1.GetUserRoleSummaryResponse, error)
GetAgency(ctx context.Context, req *userv1.GetAgencyRequest) (*userv1.GetAgencyResponse, error) GetAgency(ctx context.Context, req *userv1.GetAgencyRequest) (*userv1.GetAgencyResponse, error)
UpdateAgencyProfile(ctx context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error)
CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error)
GetAgencyMembers(ctx context.Context, req *userv1.GetAgencyMembersRequest) (*userv1.GetAgencyMembersResponse, error) GetAgencyMembers(ctx context.Context, req *userv1.GetAgencyMembersRequest) (*userv1.GetAgencyMembersResponse, error)
GetAgencyApplications(ctx context.Context, req *userv1.GetAgencyApplicationsRequest) (*userv1.GetAgencyApplicationsResponse, error) GetAgencyApplications(ctx context.Context, req *userv1.GetAgencyApplicationsRequest) (*userv1.GetAgencyApplicationsResponse, error)
@ -560,6 +561,10 @@ func (c *grpcUserHostClient) GetAgency(ctx context.Context, req *userv1.GetAgenc
return c.client.GetAgency(ctx, req) return c.client.GetAgency(ctx, req)
} }
func (c *grpcUserHostClient) UpdateAgencyProfile(ctx context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error) {
return c.client.UpdateAgencyProfile(ctx, req)
}
func (c *grpcUserHostClient) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) { func (c *grpcUserHostClient) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) {
return c.client.CheckBusinessCapability(ctx, req) return c.client.CheckBusinessCapability(ctx, req)
} }

View File

@ -183,6 +183,10 @@ func (f *fakeUserLeaderboardRoomQueryClient) ListRooms(context.Context, *roomv1.
return &roomv1.ListRoomsResponse{}, nil return &roomv1.ListRoomsResponse{}, nil
} }
func (f *fakeUserLeaderboardRoomQueryClient) ListRoomsByOwners(context.Context, *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
return &roomv1.ListRoomsResponse{}, nil
}
func (f *fakeUserLeaderboardRoomQueryClient) ListRoomFeeds(context.Context, *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) { func (f *fakeUserLeaderboardRoomQueryClient) ListRoomFeeds(context.Context, *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
return &roomv1.ListRoomsResponse{}, nil return &roomv1.ListRoomsResponse{}, nil
} }

View File

@ -81,6 +81,9 @@ type UserHandlers struct {
GetMyRoleSummary http.HandlerFunc GetMyRoleSummary http.HandlerFunc
SearchHostAgencies http.HandlerFunc SearchHostAgencies http.HandlerFunc
ApplyToHostAgency http.HandlerFunc ApplyToHostAgency http.HandlerFunc
GetAgencyProfile http.HandlerFunc
ListAgencyRooms http.HandlerFunc
UpdateAgencyProfile http.HandlerFunc
GetHostCenterAgency http.HandlerFunc GetHostCenterAgency http.HandlerFunc
GetHostCenterPlatformPolicy http.HandlerFunc GetHostCenterPlatformPolicy http.HandlerFunc
GetAgencyCenterOverview http.HandlerFunc GetAgencyCenterOverview http.HandlerFunc
@ -430,6 +433,9 @@ func (r routes) registerUserRoutes() {
r.profile("/users/me/role-summary", "", h.GetMyRoleSummary) r.profile("/users/me/role-summary", "", h.GetMyRoleSummary)
r.profile("/host/agencies/search", http.MethodGet, h.SearchHostAgencies) r.profile("/host/agencies/search", http.MethodGet, h.SearchHostAgencies)
r.profile("/host/agency-applications", http.MethodPost, h.ApplyToHostAgency) r.profile("/host/agency-applications", http.MethodPost, h.ApplyToHostAgency)
r.profile("/agencies/profile", http.MethodGet, h.GetAgencyProfile)
r.profile("/agencies/rooms", http.MethodGet, h.ListAgencyRooms)
r.profile("/agencies/profile/update", http.MethodPost, h.UpdateAgencyProfile)
r.profile("/host-center/agency", http.MethodGet, h.GetHostCenterAgency) r.profile("/host-center/agency", http.MethodGet, h.GetHostCenterAgency)
r.profile("/host-center/platform-policy", http.MethodGet, h.GetHostCenterPlatformPolicy) r.profile("/host-center/platform-policy", http.MethodGet, h.GetHostCenterPlatformPolicy)
r.profile("/agency-center/overview", http.MethodGet, h.GetAgencyCenterOverview) r.profile("/agency-center/overview", http.MethodGet, h.GetAgencyCenterOverview)

View File

@ -375,6 +375,7 @@ type fakeUserIdentityClient struct {
type fakeRoomQueryClient struct { type fakeRoomQueryClient struct {
lastList *roomv1.ListRoomsRequest lastList *roomv1.ListRoomsRequest
lastListOwners *roomv1.ListRoomsByOwnersRequest
lastFeeds *roomv1.ListRoomFeedsRequest lastFeeds *roomv1.ListRoomFeedsRequest
lastMyRoom *roomv1.GetMyRoomRequest lastMyRoom *roomv1.GetMyRoomRequest
lastCurrent *roomv1.GetCurrentRoomRequest lastCurrent *roomv1.GetCurrentRoomRequest
@ -384,6 +385,7 @@ type fakeRoomQueryClient struct {
lastOnline *roomv1.ListRoomOnlineUsersRequest lastOnline *roomv1.ListRoomOnlineUsersRequest
lastBannedUsers *roomv1.ListRoomBannedUsersRequest lastBannedUsers *roomv1.ListRoomBannedUsersRequest
resp *roomv1.ListRoomsResponse resp *roomv1.ListRoomsResponse
ownersResp *roomv1.ListRoomsResponse
feedsResp *roomv1.ListRoomsResponse feedsResp *roomv1.ListRoomsResponse
myRoomResp *roomv1.GetMyRoomResponse myRoomResp *roomv1.GetMyRoomResponse
currentResp *roomv1.GetCurrentRoomResponse currentResp *roomv1.GetCurrentRoomResponse
@ -393,6 +395,7 @@ type fakeRoomQueryClient struct {
onlineResp *roomv1.ListRoomOnlineUsersResponse onlineResp *roomv1.ListRoomOnlineUsersResponse
bannedUsersResp *roomv1.ListRoomBannedUsersResponse bannedUsersResp *roomv1.ListRoomBannedUsersResponse
err error err error
ownersErr error
feedsErr error feedsErr error
myRoomErr error myRoomErr error
currentErr error currentErr error
@ -479,6 +482,9 @@ type fakeUserHostClient struct {
lastGetAgency *userv1.GetAgencyRequest lastGetAgency *userv1.GetAgencyRequest
getAgencyResp *userv1.GetAgencyResponse getAgencyResp *userv1.GetAgencyResponse
getAgencyErr error getAgencyErr error
lastUpdateAgency *userv1.UpdateAgencyProfileRequest
updateAgencyResp *userv1.UpdateAgencyProfileResponse
updateAgencyErr error
lastMembers *userv1.GetAgencyMembersRequest lastMembers *userv1.GetAgencyMembersRequest
membersResp *userv1.GetAgencyMembersResponse membersResp *userv1.GetAgencyMembersResponse
membersErr error membersErr error
@ -1107,6 +1113,17 @@ func (f *fakeRoomQueryClient) ListRooms(_ context.Context, req *roomv1.ListRooms
return &roomv1.ListRoomsResponse{}, nil return &roomv1.ListRoomsResponse{}, nil
} }
func (f *fakeRoomQueryClient) ListRoomsByOwners(_ context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
f.lastListOwners = req
if f.ownersErr != nil {
return nil, f.ownersErr
}
if f.ownersResp != nil {
return f.ownersResp, nil
}
return &roomv1.ListRoomsResponse{}, nil
}
func (f *fakeRoomQueryClient) ListRoomFeeds(_ context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) { func (f *fakeRoomQueryClient) ListRoomFeeds(_ context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
f.lastFeeds = req f.lastFeeds = req
if f.feedsErr != nil { if f.feedsErr != nil {
@ -1653,6 +1670,23 @@ func (f *fakeUserHostClient) GetAgency(_ context.Context, req *userv1.GetAgencyR
return &userv1.GetAgencyResponse{}, nil return &userv1.GetAgencyResponse{}, nil
} }
func (f *fakeUserHostClient) UpdateAgencyProfile(_ context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error) {
f.lastUpdateAgency = req
if f.updateAgencyErr != nil {
return nil, f.updateAgencyErr
}
if f.updateAgencyResp != nil {
return f.updateAgencyResp, nil
}
return &userv1.UpdateAgencyProfileResponse{Agency: &userv1.Agency{
AgencyId: req.GetAgencyId(),
OwnerUserId: req.GetOperatorUserId(),
Name: req.GetName(),
Avatar: req.GetAvatar(),
Status: "active",
}}, nil
}
func (f *fakeUserHostClient) CheckBusinessCapability(_ context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) { func (f *fakeUserHostClient) CheckBusinessCapability(_ context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) {
f.lastCapability = req f.lastCapability = req
f.capabilities = append(f.capabilities, req.GetCapability()) f.capabilities = append(f.capabilities, req.GetCapability())
@ -5013,6 +5047,7 @@ func TestHostCenterAgencyUsesCurrentHostAgencyAndOwnerProfile(t *testing.T) {
OwnerUserId: 99, OwnerUserId: 99,
RegionId: 30, RegionId: 30,
Name: "Yumi Star Agency", Name: "Yumi Star Agency",
Avatar: "https://cdn.example/agency.png",
Status: "active", Status: "active",
}}, }},
} }
@ -5047,11 +5082,198 @@ func TestHostCenterAgencyUsesCurrentHostAgencyAndOwnerProfile(t *testing.T) {
} }
data := response.Data.(map[string]any) data := response.Data.(map[string]any)
agency := data["agency"].(map[string]any) agency := data["agency"].(map[string]any)
if agency["agency_id"] != "7001" || agency["short_id"] != "163003" || agency["avatar"] != "https://cdn.example/agency-owner.png" || agency["name"] != "Yumi Star Agency" { if agency["agency_id"] != "7001" || agency["short_id"] != "163003" || agency["avatar"] != "https://cdn.example/agency.png" || agency["name"] != "Yumi Star Agency" {
t.Fatalf("host center agency response mismatch: %+v", agency) t.Fatalf("host center agency response mismatch: %+v", agency)
} }
} }
func TestGetAgencyProfileReturnsIndependentAgencyAvatar(t *testing.T) {
hostClient := &fakeUserHostClient{
hostProfile: &userv1.HostProfile{UserId: 88, Status: "active", RegionId: 30, CurrentAgencyId: 7001},
getAgencyResp: &userv1.GetAgencyResponse{Agency: &userv1.Agency{
AgencyId: 7001,
OwnerUserId: 99,
RegionId: 30,
Name: "Independent Agency",
Avatar: "https://cdn.example/agency-avatar.png",
HostCount: 3,
Status: "active",
JoinEnabled: true,
}},
}
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
handler.SetUserHostClient(hostClient)
router := handler.Routes(auth.NewVerifier("secret"))
request := httptest.NewRequest(http.MethodGet, "/api/v1/agencies/profile?user_id=88", nil)
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
request.Header.Set("X-Request-ID", "req-agency-profile")
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
}
if hostClient.lastHost == nil || hostClient.lastHost.GetUserId() != 88 || hostClient.lastGetAgency == nil || hostClient.lastGetAgency.GetAgencyId() != 7001 {
t.Fatalf("agency profile upstream requests mismatch: host=%+v agency=%+v", hostClient.lastHost, hostClient.lastGetAgency)
}
var response httpkit.ResponseEnvelope
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
t.Fatalf("decode response failed: %v", err)
}
data := response.Data.(map[string]any)
agency := data["agency"].(map[string]any)
if agency["agency_id"] != "7001" || agency["owner_user_id"] != "99" || agency["name"] != "Independent Agency" || agency["avatar"] != "https://cdn.example/agency-avatar.png" || agency["host_count"] != float64(3) {
t.Fatalf("agency profile response mismatch: %+v", agency)
}
}
func TestGetAgencyProfileReturnsNullWhenTargetNotActiveHost(t *testing.T) {
hostClient := &fakeUserHostClient{hostProfile: &userv1.HostProfile{UserId: 88, Status: "inactive", RegionId: 30, CurrentAgencyId: 7001}}
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
handler.SetUserHostClient(hostClient)
router := handler.Routes(auth.NewVerifier("secret"))
request := httptest.NewRequest(http.MethodGet, "/api/v1/agencies/profile?user_id=88", nil)
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
request.Header.Set("X-Request-ID", "req-agency-profile-empty")
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
}
if hostClient.lastGetAgency != nil {
t.Fatalf("inactive host must not fetch agency: %+v", hostClient.lastGetAgency)
}
var response httpkit.ResponseEnvelope
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
t.Fatalf("decode response failed: %v", err)
}
data := response.Data.(map[string]any)
if data["agency"] != nil {
t.Fatalf("inactive host must return null agency: %+v", data)
}
}
func TestListAgencyRoomsUsesActiveAgencyHosts(t *testing.T) {
hostClient := &fakeUserHostClient{
hostProfile: &userv1.HostProfile{UserId: 88, Status: "active", RegionId: 30, CurrentAgencyId: 7001},
getAgencyResp: &userv1.GetAgencyResponse{Agency: &userv1.Agency{
AgencyId: 7001,
OwnerUserId: 99,
RegionId: 30,
Name: "Independent Agency",
Avatar: "https://cdn.example/agency-avatar.png",
Status: "active",
}},
membersResp: &userv1.GetAgencyMembersResponse{Memberships: []*userv1.AgencyMembership{
{MembershipId: 1, AgencyId: 7001, HostUserId: 101, Status: "active"},
{MembershipId: 2, AgencyId: 7001, HostUserId: 102, Status: "inactive"},
{MembershipId: 3, AgencyId: 7001, HostUserId: 99, Status: "active"},
}},
}
roomClient := &fakeRoomQueryClient{ownersResp: &roomv1.ListRoomsResponse{
Rooms: []*roomv1.RoomListItem{{
RoomId: "room-101",
OwnerUserId: 101,
Title: "Agency Room",
CoverUrl: "https://cdn.example/room.png",
Mode: "voice",
Status: "active",
Heat: 88,
OnlineCount: 12,
SeatCount: 8,
OccupiedSeatCount: 3,
RoomShortId: "M20",
CountryCode: "AE",
}},
NextCursor: "next-owner-room",
}}
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
handler.SetUserHostClient(hostClient)
handler.SetRoomQueryClient(roomClient)
router := handler.Routes(auth.NewVerifier("secret"))
request := httptest.NewRequest(http.MethodGet, "/api/v1/agencies/rooms?user_id=88&tab=new&limit=120&cursor=cursor-1&query=karaoke", nil)
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
request.Header.Set("X-Request-ID", "req-agency-rooms")
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
}
if hostClient.lastMembers == nil || hostClient.lastMembers.GetAgencyId() != 7001 || hostClient.lastMembers.GetStatus() != "active" {
t.Fatalf("agency members request mismatch: %+v", hostClient.lastMembers)
}
if roomClient.lastListOwners == nil {
t.Fatal("agency rooms must call ListRoomsByOwners")
}
ownerIDs := roomClient.lastListOwners.GetOwnerUserIds()
if len(ownerIDs) != 2 || ownerIDs[0] != 99 || ownerIDs[1] != 101 {
t.Fatalf("owner ids mismatch: got %v request=%+v", roomClient.lastListOwners.GetOwnerUserIds(), roomClient.lastListOwners)
}
if roomClient.lastListOwners.GetViewerUserId() != 42 || roomClient.lastListOwners.GetTab() != "new" || roomClient.lastListOwners.GetLimit() != 50 || roomClient.lastListOwners.GetCursor() != "cursor-1" || roomClient.lastListOwners.GetQuery() != "karaoke" {
t.Fatalf("agency rooms request mismatch: %+v", roomClient.lastListOwners)
}
var response httpkit.ResponseEnvelope
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
t.Fatalf("decode response failed: %v", err)
}
data := response.Data.(map[string]any)
rooms := data["rooms"].([]any)
first := rooms[0].(map[string]any)
if data["agency_id"] != "7001" || data["next_cursor"] != "next-owner-room" || first["room_id"] != "room-101" || first["owner_user_id"] != "101" || first["country_flag"] != "🇦🇪" {
t.Fatalf("agency rooms response mismatch: %+v", response)
}
}
func TestUpdateAgencyProfileForwardsOwnerCommand(t *testing.T) {
hostClient := &fakeUserHostClient{
roleSummary: &userv1.UserRoleSummary{UserId: 42, IsAgency: true, AgencyId: 7001},
getAgencyResp: &userv1.GetAgencyResponse{Agency: &userv1.Agency{AgencyId: 7001, OwnerUserId: 42, RegionId: 30, Name: "Old Agency", Avatar: "https://cdn.example/old.png", Status: "active"}},
updateAgencyResp: &userv1.UpdateAgencyProfileResponse{Agency: &userv1.Agency{
AgencyId: 7001,
OwnerUserId: 42,
RegionId: 30,
Name: "New Agency",
Avatar: "https://cdn.example/new.png",
Status: "active",
}},
}
handler := NewHandlerWithClients(&fakeRoomClient{}, nil, nil, &fakeUserProfileClient{})
handler.SetUserHostClient(hostClient)
router := handler.Routes(auth.NewVerifier("secret"))
request := httptest.NewRequest(http.MethodPost, "/api/v1/agencies/profile/update", bytes.NewReader([]byte(`{"command_id":"cmd-agency-profile","name":" New Agency ","avatar":" https://cdn.example/new.png "}`)))
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
request.Header.Set("X-Request-ID", "req-agency-profile-update")
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, request)
if recorder.Code != http.StatusOK {
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
}
if hostClient.lastUpdateAgency == nil ||
hostClient.lastUpdateAgency.GetCommandId() != "cmd-agency-profile" ||
hostClient.lastUpdateAgency.GetOperatorUserId() != 42 ||
hostClient.lastUpdateAgency.GetAgencyId() != 7001 ||
hostClient.lastUpdateAgency.GetName() != "New Agency" ||
hostClient.lastUpdateAgency.GetAvatar() != "https://cdn.example/new.png" {
t.Fatalf("update agency profile request mismatch: %+v", hostClient.lastUpdateAgency)
}
var response httpkit.ResponseEnvelope
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
t.Fatalf("decode response failed: %v", err)
}
data := response.Data.(map[string]any)
agency := data["agency"].(map[string]any)
if agency["agency_id"] != "7001" || agency["name"] != "New Agency" || agency["avatar"] != "https://cdn.example/new.png" {
t.Fatalf("update agency profile response mismatch: %+v", agency)
}
}
func TestHostCenterPlatformPolicyUsesCurrentHostRegion(t *testing.T) { func TestHostCenterPlatformPolicyUsesCurrentHostRegion(t *testing.T) {
hostClient := &fakeUserHostClient{hostProfile: &userv1.HostProfile{ hostClient := &fakeUserHostClient{hostProfile: &userv1.HostProfile{
UserId: 42, UserId: 42,

View File

@ -273,6 +273,10 @@ func (c *shareRoomQueryClient) ListRooms(context.Context, *roomv1.ListRoomsReque
return &roomv1.ListRoomsResponse{}, nil return &roomv1.ListRoomsResponse{}, nil
} }
func (c *shareRoomQueryClient) ListRoomsByOwners(context.Context, *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
return &roomv1.ListRoomsResponse{}, nil
}
func (c *shareRoomQueryClient) ListRoomFeeds(context.Context, *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) { func (c *shareRoomQueryClient) ListRoomFeeds(context.Context, *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
return &roomv1.ListRoomsResponse{}, nil return &roomv1.ListRoomsResponse{}, nil
} }

View File

@ -64,6 +64,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
UserCPClient: h.userCPClient, UserCPClient: h.userCPClient,
UserCountryClient: h.userCountryClient, UserCountryClient: h.userCountryClient,
UserHostClient: h.userHostClient, UserHostClient: h.userHostClient,
RoomQueryClient: h.roomQueryClient,
WalletClient: h.walletClient, WalletClient: h.walletClient,
GrowthLevelClient: h.growthLevelClient, GrowthLevelClient: h.growthLevelClient,
AchievementClient: h.achievementClient, AchievementClient: h.achievementClient,

View File

@ -0,0 +1,348 @@
package userapi
import (
"net/http"
"strconv"
"strings"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"hyapp/pkg/imgroup"
"hyapp/services/gateway-service/internal/auth"
"hyapp/services/gateway-service/internal/transport/http/httpkit"
roomv1 "hyapp.local/api/proto/room/v1"
userv1 "hyapp.local/api/proto/user/v1"
)
const maxAgencyRoomListLimit = 50
type agencyRoomsData struct {
AgencyID string `json:"agency_id"`
Rooms []agencyRoomItemData `json:"rooms"`
NextCursor string `json:"next_cursor"`
}
type agencyRoomItemData struct {
RoomID string `json:"room_id"`
IMGroupID string `json:"im_group_id"`
OwnerUserID string `json:"owner_user_id,omitempty"`
Title string `json:"title,omitempty"`
CoverURL string `json:"cover_url,omitempty"`
Mode string `json:"mode,omitempty"`
Status string `json:"status,omitempty"`
Locked bool `json:"locked"`
Heat int64 `json:"heat"`
OnlineCount int32 `json:"online_count"`
SeatCount int32 `json:"seat_count"`
OccupiedSeatCount int32 `json:"occupied_seat_count"`
VisibleRegionID int64 `json:"visible_region_id,omitempty"`
AppCode string `json:"app_code,omitempty"`
RoomShortID string `json:"room_short_id,omitempty"`
CountryCode string `json:"country_code,omitempty"`
CountryFlag string `json:"country_flag,omitempty"`
}
func (h *Handler) getAgencyProfile(writer http.ResponseWriter, request *http.Request) {
targetUserID, ok := positiveInt64Query(request, "user_id")
if !ok {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
agency, found, err := h.resolveAgencyForTargetHost(request, targetUserID)
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
if !found {
httpkit.WriteOK(writer, request, map[string]any{"agency": nil})
return
}
httpkit.WriteOK(writer, request, map[string]any{"agency": hostAgencyFromProto(agency)})
}
func (h *Handler) listAgencyRooms(writer http.ResponseWriter, request *http.Request) {
targetUserID, ok := positiveInt64Query(request, "user_id")
if !ok {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
limit, ok := parseAgencyRoomListLimit(request.URL.Query().Get("limit"))
if !ok {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
tab, ok := parseAgencyRoomListTab(request.URL.Query().Get("tab"))
if !ok {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
if h.roomQueryClient == nil {
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
return
}
agency, found, err := h.resolveAgencyForTargetHost(request, targetUserID)
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
if !found {
httpkit.WriteOK(writer, request, agencyRoomsData{Rooms: []agencyRoomItemData{}})
return
}
ownerUserIDs, err := h.activeAgencyHostUserIDs(request, agency)
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
if len(ownerUserIDs) == 0 {
httpkit.WriteOK(writer, request, agencyRoomsData{AgencyID: int64String(agency.GetAgencyId()), Rooms: []agencyRoomItemData{}})
return
}
resp, err := h.roomQueryClient.ListRoomsByOwners(request.Context(), &roomv1.ListRoomsByOwnersRequest{
Meta: httpkit.RoomMeta(request, "", ""),
ViewerUserId: auth.UserIDFromContext(request.Context()),
OwnerUserIds: ownerUserIDs,
Tab: tab,
Cursor: strings.TrimSpace(request.URL.Query().Get("cursor")),
Limit: limit,
Query: agencyRoomListQuery(request),
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
httpkit.WriteOK(writer, request, agencyRoomsData{
AgencyID: int64String(agency.GetAgencyId()),
Rooms: agencyRoomItemsFromProto(resp.GetRooms()),
NextCursor: resp.GetNextCursor(),
})
}
func (h *Handler) updateAgencyProfile(writer http.ResponseWriter, request *http.Request) {
agency, ok := h.resolveCurrentOwnerAgency(writer, request)
if !ok {
return
}
var body struct {
CommandID string `json:"command_id"`
CommandIDAlt string `json:"commandId"`
Name *string `json:"name"`
Avatar *string `json:"avatar"`
}
if !httpkit.Decode(writer, request, &body) {
return
}
commandID := strings.TrimSpace(body.CommandID)
if commandID == "" {
commandID = strings.TrimSpace(body.CommandIDAlt)
}
name := trimmedOptionalString(body.Name)
avatar := trimmedOptionalString(body.Avatar)
if commandID == "" || (name == nil && avatar == nil) || optionalStringIsEmpty(name) || optionalStringIsEmpty(avatar) {
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
return
}
resp, err := h.userHostClient.UpdateAgencyProfile(request.Context(), &userv1.UpdateAgencyProfileRequest{
Meta: httpkit.UserMeta(request, ""),
CommandId: commandID,
OperatorUserId: auth.UserIDFromContext(request.Context()),
AgencyId: agency.GetAgencyId(),
Name: name,
Avatar: avatar,
})
if err != nil {
httpkit.WriteRPCError(writer, request, err)
return
}
httpkit.WriteOK(writer, request, map[string]any{"agency": hostAgencyFromProto(resp.GetAgency())})
}
func (h *Handler) resolveAgencyForTargetHost(request *http.Request, targetUserID int64) (*userv1.Agency, bool, error) {
if h.userHostClient == nil {
return nil, false, status.Error(codes.Unavailable, "user host client unavailable")
}
profileResp, err := h.userHostClient.GetHostProfile(request.Context(), &userv1.GetHostProfileRequest{
Meta: httpkit.UserMeta(request, ""),
UserId: targetUserID,
})
if status.Code(err) == codes.NotFound {
return nil, false, nil
}
if err != nil {
return nil, false, err
}
profile := profileResp.GetHostProfile()
// 这两个公开查询看的是“被查询用户作为 active host 当前所属 agency”。非 host、停用 host、
// 或没有 active agency 归属都按空结果处理,避免向客户端暴露中间态/历史关系。
if profile == nil || profile.GetStatus() != agencyStatusActive || profile.GetCurrentAgencyId() <= 0 {
return nil, false, nil
}
agencyResp, err := h.userHostClient.GetAgency(request.Context(), &userv1.GetAgencyRequest{
Meta: httpkit.UserMeta(request, ""),
AgencyId: profile.GetCurrentAgencyId(),
})
if status.Code(err) == codes.NotFound {
return nil, false, nil
}
if err != nil {
return nil, false, err
}
agency := agencyResp.GetAgency()
if agency == nil || agency.GetAgencyId() != profile.GetCurrentAgencyId() || agency.GetStatus() != agencyStatusActive {
return nil, false, nil
}
return agency, true, nil
}
func (h *Handler) activeAgencyHostUserIDs(request *http.Request, agency *userv1.Agency) ([]int64, error) {
resp, err := h.userHostClient.GetAgencyMembers(request.Context(), &userv1.GetAgencyMembersRequest{
Meta: httpkit.UserMeta(request, ""),
AgencyId: agency.GetAgencyId(),
Status: membershipStatusActive,
})
if err != nil {
return nil, err
}
seen := make(map[int64]struct{}, len(resp.GetMemberships())+1)
ownerUserIDs := make([]int64, 0, len(resp.GetMemberships())+1)
appendOwner := func(userID int64) {
if userID <= 0 {
return
}
if _, exists := seen[userID]; exists {
return
}
seen[userID] = struct{}{}
ownerUserIDs = append(ownerUserIDs, userID)
}
// Agency owner 自动拥有 owner membership即使历史数据缺 owner membership也要把 owner 的 active 房间纳入组织房间列表。
appendOwner(agency.GetOwnerUserId())
for _, membership := range resp.GetMemberships() {
if membership.GetStatus() == membershipStatusActive {
appendOwner(membership.GetHostUserId())
}
}
return ownerUserIDs, nil
}
func agencyRoomItemsFromProto(rooms []*roomv1.RoomListItem) []agencyRoomItemData {
items := make([]agencyRoomItemData, 0, len(rooms))
for _, room := range rooms {
items = append(items, agencyRoomItemFromProto(room))
}
return items
}
func agencyRoomItemFromProto(room *roomv1.RoomListItem) agencyRoomItemData {
if room == nil {
return agencyRoomItemData{}
}
roomID := room.GetRoomId()
return agencyRoomItemData{
RoomID: roomID,
IMGroupID: agencyRoomIMGroupID(roomID),
OwnerUserID: int64String(room.GetOwnerUserId()),
Title: room.GetTitle(),
CoverURL: room.GetCoverUrl(),
Mode: room.GetMode(),
Status: room.GetStatus(),
Locked: room.GetLocked(),
Heat: room.GetHeat(),
OnlineCount: room.GetOnlineCount(),
SeatCount: room.GetSeatCount(),
OccupiedSeatCount: room.GetOccupiedSeatCount(),
VisibleRegionID: room.GetVisibleRegionId(),
AppCode: room.GetAppCode(),
RoomShortID: room.GetRoomShortId(),
CountryCode: room.GetCountryCode(),
CountryFlag: agencyRoomCountryFlag(room.GetCountryCode()),
}
}
func positiveInt64Query(request *http.Request, name string) (int64, bool) {
raw := strings.TrimSpace(request.URL.Query().Get(name))
value, err := strconv.ParseInt(raw, 10, 64)
return value, err == nil && value > 0
}
func parseAgencyRoomListLimit(raw string) (int32, bool) {
raw = strings.TrimSpace(raw)
if raw == "" {
return 0, true
}
value, err := strconv.ParseInt(raw, 10, 32)
if err != nil || value <= 0 {
return 0, false
}
if value > maxAgencyRoomListLimit {
value = maxAgencyRoomListLimit
}
return int32(value), true
}
func parseAgencyRoomListTab(raw string) (string, bool) {
switch strings.ToLower(strings.TrimSpace(raw)) {
case "", "hot":
return "hot", true
case "new":
return "new", true
default:
return "", false
}
}
func agencyRoomListQuery(request *http.Request) string {
if query := strings.TrimSpace(request.URL.Query().Get("query")); query != "" {
return query
}
return strings.TrimSpace(request.URL.Query().Get("q"))
}
func trimmedOptionalString(value *string) *string {
if value == nil {
return nil
}
trimmed := strings.TrimSpace(*value)
return &trimmed
}
func optionalStringIsEmpty(value *string) bool {
return value != nil && *value == ""
}
func agencyRoomIMGroupID(roomID string) string {
groupID, err := imgroup.RoomGroupID(roomID)
if err != nil {
return roomID
}
return groupID
}
func agencyRoomCountryFlag(country string) string {
country = strings.ToUpper(strings.TrimSpace(country))
if len(country) != 2 {
return ""
}
runes := []rune(country)
for _, value := range runes {
if value < 'A' || value > 'Z' {
return ""
}
}
const regionalIndicatorA = 0x1F1E6
return string([]rune{
regionalIndicatorA + (runes[0] - 'A'),
regionalIndicatorA + (runes[1] - 'A'),
})
}

View File

@ -17,6 +17,7 @@ type Handler struct {
userCPClient client.UserCPClient userCPClient client.UserCPClient
userCountryClient client.UserCountryQueryClient userCountryClient client.UserCountryQueryClient
userHostClient client.UserHostClient userHostClient client.UserHostClient
roomQueryClient client.RoomQueryClient
walletClient client.WalletClient walletClient client.WalletClient
growthLevelClient client.GrowthLevelClient growthLevelClient client.GrowthLevelClient
achievementClient client.AchievementClient achievementClient client.AchievementClient
@ -31,6 +32,7 @@ type Config struct {
UserCPClient client.UserCPClient UserCPClient client.UserCPClient
UserCountryClient client.UserCountryQueryClient UserCountryClient client.UserCountryQueryClient
UserHostClient client.UserHostClient UserHostClient client.UserHostClient
RoomQueryClient client.RoomQueryClient
WalletClient client.WalletClient WalletClient client.WalletClient
GrowthLevelClient client.GrowthLevelClient GrowthLevelClient client.GrowthLevelClient
AchievementClient client.AchievementClient AchievementClient client.AchievementClient
@ -46,6 +48,7 @@ func New(config Config) *Handler {
userCPClient: config.UserCPClient, userCPClient: config.UserCPClient,
userCountryClient: config.UserCountryClient, userCountryClient: config.UserCountryClient,
userHostClient: config.UserHostClient, userHostClient: config.UserHostClient,
roomQueryClient: config.RoomQueryClient,
walletClient: config.WalletClient, walletClient: config.WalletClient,
growthLevelClient: config.GrowthLevelClient, growthLevelClient: config.GrowthLevelClient,
achievementClient: config.AchievementClient, achievementClient: config.AchievementClient,
@ -65,6 +68,9 @@ func (h *Handler) UserHandlers() httproutes.UserHandlers {
GetMyRoleSummary: h.getMyRoleSummary, GetMyRoleSummary: h.getMyRoleSummary,
SearchHostAgencies: h.searchHostAgencies, SearchHostAgencies: h.searchHostAgencies,
ApplyToHostAgency: h.applyToHostAgency, ApplyToHostAgency: h.applyToHostAgency,
GetAgencyProfile: h.getAgencyProfile,
ListAgencyRooms: h.listAgencyRooms,
UpdateAgencyProfile: h.updateAgencyProfile,
GetHostCenterAgency: h.getHostCenterAgency, GetHostCenterAgency: h.getHostCenterAgency,
GetHostCenterPlatformPolicy: h.getHostCenterPlatformPolicy, GetHostCenterPlatformPolicy: h.getHostCenterPlatformPolicy,
GetAgencyCenterOverview: h.getAgencyCenterOverview, GetAgencyCenterOverview: h.getAgencyCenterOverview,

View File

@ -59,9 +59,6 @@ func (h *Handler) getHostCenterAgency(writer http.ResponseWriter, request *http.
if owner.DisplayUserID != "" { if owner.DisplayUserID != "" {
data.ShortID = owner.DisplayUserID data.ShortID = owner.DisplayUserID
} }
if owner.Avatar != "" {
data.Avatar = owner.Avatar
}
} }
} }

View File

@ -24,6 +24,7 @@ const (
defaultRoomListLimit = 20 defaultRoomListLimit = 20
maxRoomListLimit = 50 maxRoomListLimit = 50
maxRoomListQueryRunes = 64 maxRoomListQueryRunes = 64
maxRoomOwnerIDFilters = 500
roomHotHeatWeight = 650000 roomHotHeatWeight = 650000
roomHotOnlineWeight = 300000 roomHotOnlineWeight = 300000
roomHotMicWeight = 50000 roomHotMicWeight = 50000
@ -102,6 +103,45 @@ func (s *Service) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (
return roomListResponseFromEntries(tab, query, countryCode, viewerCountryCode, allVisibleRegions, entries, limit), nil return roomListResponseFromEntries(tab, query, countryCode, viewerCountryCode, allVisibleRegions, entries, limit), nil
} }
func (s *Service) ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
if req.GetViewerUserId() <= 0 {
// owner 集合必须由 gateway 在鉴权后根据业务归属注入room-service 不接受匿名组织页查询。
return nil, xerr.New(xerr.InvalidArgument, "viewer_user_id is required")
}
tab := normalizeRoomListTab(req.GetTab())
if tab == "" {
return nil, xerr.New(xerr.InvalidArgument, "tab is invalid")
}
ownerUserIDs := normalizeRoomOwnerFilters(req.GetOwnerUserIds())
if len(ownerUserIDs) == 0 {
return roomListResponseFromEntries(tab, "", "", "", false, nil, normalizeRoomListLimit(req.GetLimit())), nil
}
limit := normalizeRoomListLimit(req.GetLimit())
query, err := normalizeRoomListQuery(req.GetQuery())
if err != nil {
return nil, err
}
cursor, err := decodeRoomListCursor(tab, query, "", "", false, req.GetCursor())
if err != nil {
return nil, err
}
entries, err := s.repository.ListRoomListEntries(ctx, RoomListQuery{
AppCode: appcode.FromContext(ctx),
Tab: tab,
OwnerUserIDs: ownerUserIDs,
Query: query,
Limit: limit + 1,
CursorSortScore: cursor.SortScore,
CursorCreatedAtMS: cursor.CreatedAtMS,
CursorRoomID: cursor.RoomID,
})
if err != nil {
return nil, err
}
return roomListResponseFromEntries(tab, query, "", "", false, entries, limit), nil
}
func (s *Service) listRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, error) { func (s *Service) listRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, error) {
if s != nil && s.roomListCache != nil && roomListCacheEligible(query) { if s != nil && s.roomListCache != nil && roomListCacheEligible(query) {
entries, ok, err := s.roomListCache.ListRoomListEntries(ctx, query) entries, ok, err := s.roomListCache.ListRoomListEntries(ctx, query)
@ -118,7 +158,7 @@ func (s *Service) listRoomListEntries(ctx context.Context, query RoomListQuery)
func roomListCacheEligible(query RoomListQuery) bool { func roomListCacheEligible(query RoomListQuery) bool {
// 搜索、全区白名单和内部定向查询仍走 MySQL避免为了低频条件维护过宽的 Redis 索引。 // 搜索、全区白名单和内部定向查询仍走 MySQL避免为了低频条件维护过宽的 Redis 索引。
if strings.TrimSpace(query.Query) != "" || query.AllVisibleRegions || query.OwnerUserID > 0 { if strings.TrimSpace(query.Query) != "" || query.AllVisibleRegions || query.OwnerUserID > 0 || len(query.OwnerUserIDs) > 0 {
return false return false
} }
return query.Tab == roomListTabHot || query.Tab == roomListTabNew return query.Tab == roomListTabHot || query.Tab == roomListTabNew
@ -439,6 +479,25 @@ func normalizeRoomListLimit(limit int32) int {
return int(limit) return int(limit)
} }
func normalizeRoomOwnerFilters(ownerUserIDs []int64) []int64 {
seen := make(map[int64]struct{}, len(ownerUserIDs))
ids := make([]int64, 0, len(ownerUserIDs))
for _, userID := range ownerUserIDs {
if userID <= 0 {
continue
}
if _, exists := seen[userID]; exists {
continue
}
seen[userID] = struct{}{}
ids = append(ids, userID)
if len(ids) >= maxRoomOwnerIDFilters {
break
}
}
return ids
}
// normalizeVisibleRegionID 把负数区域收敛到 GLOBAL 桶,避免非法区域影响 SQL 查询边界。 // normalizeVisibleRegionID 把负数区域收敛到 GLOBAL 桶,避免非法区域影响 SQL 查询边界。
func normalizeVisibleRegionID(regionID int64) int64 { func normalizeVisibleRegionID(regionID int64) int64 {
if regionID < 0 { if regionID < 0 {

View File

@ -84,6 +84,48 @@ func TestListRoomsFallsBackToMySQLWhenCacheMisses(t *testing.T) {
} }
} }
func TestListRoomsByOwnersReturnsActiveRoomsForAgencyHosts(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
svc := roomservice.New(roomservice.Config{
NodeID: "node-list-by-owners-test",
LeaseTTL: 10 * time.Second,
RankLimit: 20,
SnapshotEveryN: 1,
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
createPinnedListRoom(t, ctx, svc, "room-agency-owner", "agency-owner", 6201, 7101, "US")
createPinnedListRoom(t, ctx, svc, "room-agency-member", "agency-member", 6202, 7202, "AE")
createPinnedListRoom(t, ctx, svc, "room-outside-agency", "outside-agency", 6203, 7101, "US")
createPinnedListRoom(t, ctx, svc, "room-agency-closed", "agency-closed", 6202, 7202, "AE")
if _, err := svc.CloseRoom(ctx, &roomv1.CloseRoomRequest{
Meta: roomservice.NewRequestMeta("room-agency-closed", 6202),
Reason: "closed fixture",
}); err != nil {
t.Fatalf("close agency room fixture failed: %v", err)
}
resp, err := svc.ListRoomsByOwners(ctx, &roomv1.ListRoomsByOwnersRequest{
Meta: &roomv1.RequestMeta{AppCode: appcode.Default},
ViewerUserId: 4001,
OwnerUserIds: []int64{6201, 6202},
Tab: "new",
Limit: 10,
})
if err != nil {
t.Fatalf("list rooms by owners failed: %v", err)
}
got := roomIDs(resp.GetRooms())
want := map[string]bool{"room-agency-owner": true, "room-agency-member": true}
if len(got) != len(want) {
t.Fatalf("owner-filtered room count mismatch: got=%v", got)
}
for _, roomID := range got {
if !want[roomID] {
t.Fatalf("owner-filtered rooms must include only active agency host rooms, got=%v", got)
}
}
}
type fakeRoomListCache struct { type fakeRoomListCache struct {
entries []roomservice.RoomListEntry entries []roomservice.RoomListEntry
ok bool ok bool

View File

@ -497,6 +497,8 @@ type RoomListQuery struct {
Tab string Tab string
// OwnerUserID 保留给内部定向读模型;公开 Mine 顶部卡片走 GetMyRoom。 // OwnerUserID 保留给内部定向读模型;公开 Mine 顶部卡片走 GetMyRoom。
OwnerUserID int64 OwnerUserID int64
// OwnerUserIDs 是业务方预先解析出的房主集合,用于 Agency 等组织页批量取房间卡片。
OwnerUserIDs []int64
// Query 非空时按 room_id 或 title 做包含匹配。 // Query 非空时按 room_id 或 title 做包含匹配。
Query string Query string
// CountryCode 非空时只返回房主国家命中的房间gateway 必须先校验它属于当前用户区域。 // CountryCode 非空时只返回房主国家命中的房间gateway 必须先校验它属于当前用户区域。

View File

@ -572,6 +572,9 @@ const roomFollowSelectColumns = `
JOIN room_list_entries r ON r.app_code = f.app_code AND r.room_id = f.room_id` JOIN room_list_entries r ON r.app_code = f.app_code AND r.room_id = f.room_id`
func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) { func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
if len(query.OwnerUserIDs) > 0 {
return buildRoomListByOwnersQuerySQL(query)
}
regionID := query.VisibleRegionID regionID := query.VisibleRegionID
if regionID < 0 { if regionID < 0 {
regionID = 0 regionID = 0
@ -674,6 +677,40 @@ func buildRoomListQuerySQL(query roomservice.RoomListQuery) (string, []any) {
return selectSQL + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY " + pinRankExpr + " ASC, " + pinWeightExpr + " DESC, " + pinExpiresExpr + " DESC, r.sort_score DESC, r.room_id ASC\n\tLIMIT ?", args return selectSQL + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY " + pinRankExpr + " ASC, " + pinWeightExpr + " DESC, " + pinExpiresExpr + " DESC, r.sort_score DESC, r.room_id ASC\n\tLIMIT ?", args
} }
func buildRoomListByOwnersQuerySQL(query roomservice.RoomListQuery) (string, []any) {
where := []string{"app_code = ?", "status = ?"}
args := []any{appcode.Normalize(query.AppCode), "active"}
placeholders := make([]string, 0, len(query.OwnerUserIDs))
for _, ownerUserID := range query.OwnerUserIDs {
placeholders = append(placeholders, "?")
args = append(args, ownerUserID)
}
where = append(where, "owner_user_id IN ("+strings.Join(placeholders, ",")+")")
if strings.TrimSpace(query.Query) != "" {
where = append(where, "(room_id LIKE ? ESCAPE '\\\\' OR room_short_id LIKE ? ESCAPE '\\\\' OR title LIKE ? ESCAPE '\\\\')")
like := "%" + escapeRoomListLike(query.Query) + "%"
args = append(args, like, like, like)
}
if query.Tab == "new" {
if query.CursorRoomID != "" {
where = append(where, "(created_at_ms < ? OR (created_at_ms = ? AND room_id > ?))")
args = append(args, query.CursorCreatedAtMS, query.CursorCreatedAtMS, query.CursorRoomID)
}
args = append(args, query.Limit)
return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY created_at_ms DESC, room_id ASC\n\tLIMIT ?", args
}
if query.CursorRoomID != "" {
where = append(where, "(sort_score < ? OR (sort_score = ? AND room_id > ?))")
args = append(args, query.CursorSortScore, query.CursorSortScore, query.CursorRoomID)
}
args = append(args, query.Limit)
return roomListSelectColumns + "\n\tWHERE " + strings.Join(where, " AND ") + "\n\tORDER BY sort_score DESC, room_id ASC\n\tLIMIT ?", args
}
func normalizeRoomListSQLCountryCode(countryCode string) string { func normalizeRoomListSQLCountryCode(countryCode string) string {
countryCode = strings.ToUpper(strings.TrimSpace(countryCode)) countryCode = strings.ToUpper(strings.TrimSpace(countryCode))
if len(countryCode) < 2 || len(countryCode) > 3 { if len(countryCode) < 2 || len(countryCode) > 3 {

View File

@ -485,6 +485,13 @@ func (s *Server) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*
return mapServiceResult(s.svc.ListRooms(ctx, req)) return mapServiceResult(s.svc.ListRooms(ctx, req))
} }
// ListRoomsByOwners 代理到 owner 批量房间卡片读模型。
func (s *Server) ListRoomsByOwners(ctx context.Context, req *roomv1.ListRoomsByOwnersRequest) (*roomv1.ListRoomsResponse, error) {
// owner 集合由上游业务归属解析后注入room-service 只按房间 owner 投影批量读取卡片。
ctx = contextWithMetaApp(ctx, req.GetMeta())
return mapServiceResult(s.svc.ListRoomsByOwners(ctx, req))
}
// ListRoomFeeds 代理到 Mine 页用户房间流读模型。 // ListRoomFeeds 代理到 Mine 页用户房间流读模型。
func (s *Server) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) { func (s *Server) ListRoomFeeds(ctx context.Context, req *roomv1.ListRoomFeedsRequest) (*roomv1.ListRoomsResponse, error) {
// feed 查询只读用户到房间索引,并 join 房间卡片投影,不扫描 Room Cell 内存集合。 // feed 查询只读用户到房间索引,并 join 房间卡片投影,不扫描 Room Cell 内存集合。

View File

@ -820,6 +820,7 @@ CREATE TABLE IF NOT EXISTS agencies (
owner_user_id BIGINT NOT NULL COMMENT '房主用户 ID', owner_user_id BIGINT NOT NULL COMMENT '房主用户 ID',
parent_bd_user_id BIGINT NOT NULL COMMENT '父级BD用户 ID', parent_bd_user_id BIGINT NOT NULL COMMENT '父级BD用户 ID',
name VARCHAR(128) NOT NULL COMMENT '名称', name VARCHAR(128) NOT NULL COMMENT '名称',
avatar VARCHAR(512) NOT NULL DEFAULT '' COMMENT '公会头像',
status VARCHAR(32) NOT NULL COMMENT '业务状态', status VARCHAR(32) NOT NULL COMMENT '业务状态',
join_enabled BOOLEAN NOT NULL COMMENT '加入是否启用', join_enabled BOOLEAN NOT NULL COMMENT '加入是否启用',
max_hosts INT NOT NULL COMMENT '最大主播', max_hosts INT NOT NULL COMMENT '最大主播',

View File

@ -0,0 +1,8 @@
ALTER TABLE agencies
ADD COLUMN avatar VARCHAR(512) NOT NULL DEFAULT '' COMMENT '公会头像' AFTER name;
UPDATE agencies a
JOIN users u
ON u.app_code = a.app_code AND u.user_id = a.owner_user_id
SET a.avatar = COALESCE(u.avatar, '')
WHERE a.avatar = '';

View File

@ -126,6 +126,8 @@ const (
CommandTypeDeleteAgency = "admin_delete_agency" CommandTypeDeleteAgency = "admin_delete_agency"
// CommandTypeSetAgencyJoinEnabled 记录后台设置 Agency 入会开关命令。 // CommandTypeSetAgencyJoinEnabled 记录后台设置 Agency 入会开关命令。
CommandTypeSetAgencyJoinEnabled = "admin_set_agency_join_enabled" CommandTypeSetAgencyJoinEnabled = "admin_set_agency_join_enabled"
// CommandTypeUpdateAgencyProfile 记录 Agency owner 修改独立资料的命令。
CommandTypeUpdateAgencyProfile = "update_agency_profile"
// CommandTypeCreateCoinSeller 记录后台创建币商身份命令。 // CommandTypeCreateCoinSeller 记录后台创建币商身份命令。
CommandTypeCreateCoinSeller = "admin_create_coin_seller" CommandTypeCreateCoinSeller = "admin_create_coin_seller"
// CommandTypeSetCoinSellerStatus 记录后台启用或停用币商身份命令。 // CommandTypeSetCoinSellerStatus 记录后台启用或停用币商身份命令。
@ -167,7 +169,7 @@ type Agency struct {
RegionID int64 RegionID int64
ParentBDUserID int64 ParentBDUserID int64
Name string Name string
OwnerAvatar string Avatar string
ActiveHostCount int32 ActiveHostCount int32
Status string Status string
JoinEnabled bool JoinEnabled bool

View File

@ -389,3 +389,25 @@ type SetAgencyJoinEnabledCommand struct {
EventID int64 EventID int64
NowMs int64 NowMs int64
} }
// UpdateAgencyProfileInput 是 Agency owner 修改独立组织资料的外部输入。
type UpdateAgencyProfileInput struct {
CommandID string
OperatorUserID int64
AgencyID int64
Name *string
Avatar *string
RequestID string
}
// UpdateAgencyProfileCommand 是修改 Agency 独立资料事务需要的完整命令。
type UpdateAgencyProfileCommand struct {
CommandID string
OperatorUserID int64
AgencyID int64
Name *string
Avatar *string
RequestID string
EventID int64
NowMs int64
}

View File

@ -44,6 +44,7 @@ type Repository interface {
ListActiveCoinSellersInMyRegion(ctx context.Context, userID int64) ([]hostdomain.CoinSellerListItem, error) ListActiveCoinSellersInMyRegion(ctx context.Context, userID int64) ([]hostdomain.CoinSellerListItem, error)
GetUserRoleSummary(ctx context.Context, userID int64) (hostdomain.UserRoleSummary, error) GetUserRoleSummary(ctx context.Context, userID int64) (hostdomain.UserRoleSummary, error)
GetAgency(ctx context.Context, agencyID int64) (hostdomain.Agency, error) GetAgency(ctx context.Context, agencyID int64) (hostdomain.Agency, error)
UpdateAgencyProfile(ctx context.Context, command UpdateAgencyProfileCommand) (hostdomain.Agency, error)
HasActiveAgencyOwner(ctx context.Context, userID int64) (int64, bool, error) HasActiveAgencyOwner(ctx context.Context, userID int64) (int64, bool, error)
HasActiveManagerProfile(ctx context.Context, userID int64) (bool, error) HasActiveManagerProfile(ctx context.Context, userID int64) (bool, error)
HasActiveManagerCapability(ctx context.Context, userID int64, capability string) (bool, error) HasActiveManagerCapability(ctx context.Context, userID int64, capability string) (bool, error)
@ -207,15 +208,55 @@ func (s *Service) GetAgency(ctx context.Context, agencyID int64) (hostdomain.Age
return s.repository.GetAgency(ctx, agencyID) return s.repository.GetAgency(ctx, agencyID)
} }
// UpdateAgencyProfile 只修改 Agency 独立组织资料,不回写 owner 用户昵称或头像。
func (s *Service) UpdateAgencyProfile(ctx context.Context, command UpdateAgencyProfileInput) (hostdomain.Agency, error) {
if err := s.requireWriteDependencies(); err != nil {
return hostdomain.Agency{}, err
}
if strings.TrimSpace(command.CommandID) == "" || command.OperatorUserID <= 0 || command.AgencyID <= 0 {
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "command_id, operator_user_id and agency_id are required")
}
if command.Name == nil && command.Avatar == nil {
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "name or avatar is required")
}
var name *string
if command.Name != nil {
trimmed := strings.TrimSpace(*command.Name)
if trimmed == "" {
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "agency name is required")
}
name = &trimmed
}
var avatar *string
if command.Avatar != nil {
trimmed := strings.TrimSpace(*command.Avatar)
if trimmed == "" {
return hostdomain.Agency{}, xerr.New(xerr.InvalidArgument, "agency avatar is required")
}
avatar = &trimmed
}
return s.repository.UpdateAgencyProfile(ctx, UpdateAgencyProfileCommand{
CommandID: strings.TrimSpace(command.CommandID),
OperatorUserID: command.OperatorUserID,
AgencyID: command.AgencyID,
Name: name,
Avatar: avatar,
RequestID: strings.TrimSpace(command.RequestID),
EventID: s.nextEventIDRange(1),
NowMs: s.now().UnixMilli(),
})
}
// InviteAgency 由 BD 或 BD Leader 创建 Agency owner 邀请;目标用户接受前不创建 Agency 身份。 // InviteAgency 由 BD 或 BD Leader 创建 Agency owner 邀请;目标用户接受前不创建 Agency 身份。
func (s *Service) InviteAgency(ctx context.Context, command InviteAgencyInput) (hostdomain.RoleInvitation, error) { func (s *Service) InviteAgency(ctx context.Context, command InviteAgencyInput) (hostdomain.RoleInvitation, error) {
if err := s.requireWriteDependencies(); err != nil { if err := s.requireWriteDependencies(); err != nil {
return hostdomain.RoleInvitation{}, err return hostdomain.RoleInvitation{}, err
} }
// Agency 名称在邀请动作里固化,接受时按这份快照创建 Agency避免目标确认后前端再传入不同名称。 // Agency 名称允许邀请方显式覆盖;为空时在目标接受并真正创建 Agency 时复制 owner 当前昵称/短 ID
agencyName := strings.TrimSpace(command.AgencyName) agencyName := strings.TrimSpace(command.AgencyName)
if strings.TrimSpace(command.CommandID) == "" || command.InviterUserID <= 0 || command.TargetUserID <= 0 || agencyName == "" { if strings.TrimSpace(command.CommandID) == "" || command.InviterUserID <= 0 || command.TargetUserID <= 0 {
return hostdomain.RoleInvitation{}, xerr.New(xerr.InvalidArgument, "command_id, inviter_user_id, target_user_id and agency_name are required") return hostdomain.RoleInvitation{}, xerr.New(xerr.InvalidArgument, "command_id, inviter_user_id and target_user_id are required")
} }
nowMs := s.now().UnixMilli() nowMs := s.now().UnixMilli()
@ -500,8 +541,8 @@ func (s *Service) CreateAgency(ctx context.Context, command CreateAgencyInput) (
return hostdomain.CreateAgencyResult{}, err return hostdomain.CreateAgencyResult{}, err
} }
name := strings.TrimSpace(command.Name) name := strings.TrimSpace(command.Name)
if strings.TrimSpace(command.CommandID) == "" || command.AdminUserID <= 0 || command.OwnerUserID <= 0 || name == "" { if strings.TrimSpace(command.CommandID) == "" || command.AdminUserID <= 0 || command.OwnerUserID <= 0 {
return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "command_id, admin_user_id, owner_user_id and name are required") return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "command_id, admin_user_id and owner_user_id are required")
} }
if command.ParentBDUserID < 0 { if command.ParentBDUserID < 0 {
return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "parent_bd_user_id must not be negative") return hostdomain.CreateAgencyResult{}, xerr.New(xerr.InvalidArgument, "parent_bd_user_id must not be negative")

View File

@ -847,7 +847,7 @@ func TestAdminCreateAgencyControlsAppSearch(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("SearchAgencies list failed: %v", err) t.Fatalf("SearchAgencies list failed: %v", err)
} }
if len(agencies) != 1 || agencies[0].AgencyID != created.Agency.AgencyID || agencies[0].OwnerAvatar != "https://cdn.example/owner-901.png" || agencies[0].ActiveHostCount != 1 { if len(agencies) != 1 || agencies[0].AgencyID != created.Agency.AgencyID || agencies[0].Avatar != "https://cdn.example/owner-901.png" || agencies[0].ActiveHostCount != 1 {
t.Fatalf("created agency list should be scoped by country with display fields: %+v", agencies) t.Fatalf("created agency list should be scoped by country with display fields: %+v", agencies)
} }
if agencies[0].RegionID != 30 { if agencies[0].RegionID != 30 {
@ -972,6 +972,96 @@ func TestAdminCreateAgencyControlsAppSearch(t *testing.T) {
} }
} }
func TestAgencyProfileDefaultsAndStaysIndependent(t *testing.T) {
ctx := context.Background()
repository := mysqltest.NewRepository(t)
repository.PutUser(userdomain.User{
UserID: 921,
DefaultDisplayUserID: displayID(921),
CurrentDisplayUserID: displayID(921),
Username: "Owner Nick",
Avatar: "https://cdn.example/owner-old.png",
Country: "CN",
RegionID: 30,
ProfileCompleted: true,
ProfileCompletedAtMs: 1,
OnboardingStatus: userdomain.OnboardingStatusCompleted,
Status: userdomain.StatusActive,
})
seedActiveUser(t, repository, 922, 30)
svc := newHostService(repository, 5200, 6200)
created, err := svc.CreateAgency(ctx, hostservice.CreateAgencyInput{
CommandID: "admin-create-agency-default-profile",
AdminUserID: 1,
OwnerUserID: 921,
JoinEnabled: true,
RequestID: "req-agency-default-profile",
})
if err != nil {
t.Fatalf("CreateAgency with default profile failed: %v", err)
}
if created.Agency.Name != "Owner Nick" || created.Agency.Avatar != "https://cdn.example/owner-old.png" {
t.Fatalf("agency must copy owner profile once on create: %+v", created.Agency)
}
newName := "Agency New"
newAvatar := "https://cdn.example/agency-new.png"
updated, err := svc.UpdateAgencyProfile(ctx, hostservice.UpdateAgencyProfileInput{
CommandID: "agency-profile-update-owner",
OperatorUserID: 921,
AgencyID: created.Agency.AgencyID,
Name: &newName,
Avatar: &newAvatar,
RequestID: "req-agency-profile-update-owner",
})
if err != nil {
t.Fatalf("UpdateAgencyProfile by owner failed: %v", err)
}
if updated.Name != newName || updated.Avatar != newAvatar {
t.Fatalf("agency profile update mismatch: %+v", updated)
}
owner, err := repository.GetUser(ctx, 921)
if err != nil {
t.Fatalf("GetUser after agency update failed: %v", err)
}
if owner.Username != "Owner Nick" || owner.Avatar != "https://cdn.example/owner-old.png" {
t.Fatalf("agency profile update must not modify owner user: %+v", owner)
}
repository.PutUser(userdomain.User{
UserID: 921,
DefaultDisplayUserID: displayID(921),
CurrentDisplayUserID: displayID(921),
Username: "Owner New",
Avatar: "https://cdn.example/owner-new.png",
Country: "CN",
RegionID: 30,
ProfileCompleted: true,
ProfileCompletedAtMs: 1,
OnboardingStatus: userdomain.OnboardingStatusCompleted,
Status: userdomain.StatusActive,
})
afterUserChange, err := svc.GetAgency(ctx, created.Agency.AgencyID)
if err != nil {
t.Fatalf("GetAgency after owner profile change failed: %v", err)
}
if afterUserChange.Name != newName || afterUserChange.Avatar != newAvatar {
t.Fatalf("owner profile change must not sync back to agency: %+v", afterUserChange)
}
_, err = svc.UpdateAgencyProfile(ctx, hostservice.UpdateAgencyProfileInput{
CommandID: "agency-profile-update-non-owner",
OperatorUserID: 922,
AgencyID: created.Agency.AgencyID,
Name: &newName,
RequestID: "req-agency-profile-update-non-owner",
})
if got := xerr.CodeOf(err); got != xerr.PermissionDenied {
t.Fatalf("non owner agency update must be denied: got %s err=%v", got, err)
}
}
func TestAdminCreateAgencyWithoutParentBD(t *testing.T) { func TestAdminCreateAgencyWithoutParentBD(t *testing.T) {
ctx := context.Background() ctx := context.Background()
repository := mysqltest.NewRepository(t) repository := mysqltest.NewRepository(t)

View File

@ -315,8 +315,12 @@ func (r *Repository) CreateAgency(ctx context.Context, command hostservice.Creat
return hostdomain.CreateAgencyResult{}, err return hostdomain.CreateAgencyResult{}, err
} }
agencyName, agencyAvatar, err := defaultAgencyProfileFromOwner(ctx, tx, command.OwnerUserID, command.Name)
if err != nil {
return hostdomain.CreateAgencyResult{}, err
}
// max_hosts 是历史兼容字段,当前业务不再限制主播数量,新建 Agency 固化为 0。 // max_hosts 是历史兼容字段,当前业务不再限制主播数量,新建 Agency 固化为 0。
agency := hostdomain.Agency{AgencyID: command.AgencyID, OwnerUserID: command.OwnerUserID, RegionID: regionID, ParentBDUserID: command.ParentBDUserID, Name: command.Name, Status: hostdomain.AgencyStatusActive, JoinEnabled: command.JoinEnabled, MaxHosts: 0, CreatedByUserID: command.AdminUserID, CreatedAtMs: command.NowMs, UpdatedAtMs: command.NowMs} agency := hostdomain.Agency{AgencyID: command.AgencyID, OwnerUserID: command.OwnerUserID, RegionID: regionID, ParentBDUserID: command.ParentBDUserID, Name: agencyName, Avatar: agencyAvatar, Status: hostdomain.AgencyStatusActive, JoinEnabled: command.JoinEnabled, MaxHosts: 0, CreatedByUserID: command.AdminUserID, CreatedAtMs: command.NowMs, UpdatedAtMs: command.NowMs}
if err := insertAgency(ctx, tx, agency); err != nil { if err := insertAgency(ctx, tx, agency); err != nil {
return hostdomain.CreateAgencyResult{}, mapHostDuplicateError(err) return hostdomain.CreateAgencyResult{}, mapHostDuplicateError(err)
} }
@ -510,6 +514,53 @@ func (r *Repository) SetAgencyJoinEnabled(ctx context.Context, command hostservi
}) })
} }
// UpdateAgencyProfile 只允许 active Agency owner 修改组织独立资料。
func (r *Repository) UpdateAgencyProfile(ctx context.Context, command hostservice.UpdateAgencyProfileCommand) (hostdomain.Agency, error) {
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
return hostdomain.Agency{}, err
}
defer tx.Rollback()
if existing, ok, err := commandResult(ctx, tx, command.CommandID); err != nil {
return hostdomain.Agency{}, err
} else if ok {
if err := requireCommandResult(existing, hostdomain.CommandTypeUpdateAgencyProfile, hostdomain.ResultTypeAgency); err != nil {
return hostdomain.Agency{}, err
}
return queryAgency(ctx, tx, "WHERE agency_id = ?", existing.ResultID)
}
agency, err := queryAgency(ctx, tx, "WHERE agency_id = ? FOR UPDATE", command.AgencyID)
if err != nil {
return hostdomain.Agency{}, err
}
if agency.Status != hostdomain.AgencyStatusActive || agency.OwnerUserID != command.OperatorUserID {
// Agency 资料的写权限只属于当前 active owner普通成员、关闭团队和历史 owner 都不能改。
return hostdomain.Agency{}, xerr.New(xerr.PermissionDenied, "permission denied")
}
if command.Name != nil {
agency.Name = *command.Name
}
if command.Avatar != nil {
agency.Avatar = *command.Avatar
}
agency.UpdatedAtMs = command.NowMs
if err := updateAgencyProfile(ctx, tx, agency); err != nil {
return hostdomain.Agency{}, err
}
if err := insertCommandResult(ctx, tx, hostdomain.CommandResult{CommandID: command.CommandID, CommandType: hostdomain.CommandTypeUpdateAgencyProfile, ResultType: hostdomain.ResultTypeAgency, ResultID: agency.AgencyID, CreatedAtMs: command.NowMs}); err != nil {
return hostdomain.Agency{}, mapHostDuplicateError(err)
}
if err := insertHostOutbox(ctx, tx, command.EventID, "AgencyChanged", "agency", agency.AgencyID, command.NowMs); err != nil {
return hostdomain.Agency{}, err
}
if err := tx.Commit(); err != nil {
return hostdomain.Agency{}, err
}
return agency, nil
}
func (r *Repository) updateAgencyAdmin(ctx context.Context, commandID string, commandType string, agencyID int64, eventID int64, nowMs int64, mutate func(hostdomain.Agency) hostdomain.Agency) (hostdomain.Agency, error) { func (r *Repository) updateAgencyAdmin(ctx context.Context, commandID string, commandType string, agencyID int64, eventID int64, nowMs int64, mutate func(hostdomain.Agency) hostdomain.Agency) (hostdomain.Agency, error) {
tx, err := r.db.BeginTx(ctx, nil) tx, err := r.db.BeginTx(ctx, nil)
if err != nil { if err != nil {

View File

@ -50,8 +50,15 @@ var (
), 0), ), 0),
source, first_became_host_at_ms, created_at_ms, updated_at_ms`, userRegionProjection("host_profiles", "user_id")) source, first_became_host_at_ms, created_at_ms, updated_at_ms`, userRegionProjection("host_profiles", "user_id"))
agencyColumns = fmt.Sprintf(` agencyColumns = fmt.Sprintf(`
agency_id, owner_user_id, %s, parent_bd_user_id, name, status, agency_id, owner_user_id, %s, parent_bd_user_id, name, avatar, status,
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms`, userRegionProjection("agencies", "owner_user_id")) join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms,
COALESCE((
SELECT COUNT(*)
FROM agency_memberships active_member
WHERE active_member.app_code = agencies.app_code
AND active_member.agency_id = agencies.agency_id
AND active_member.status = '%s'
), 0)`, userRegionProjection("agencies", "owner_user_id"), hostdomain.MembershipStatusActive)
bdProfileColumns = fmt.Sprintf(` bdProfileColumns = fmt.Sprintf(`
user_id, role, %s, COALESCE(parent_leader_user_id, 0), status, user_id, role, %s, COALESCE(parent_leader_user_id, 0), status,
created_by_user_id, created_at_ms, updated_at_ms`, userRegionProjection("bd_profiles", "user_id")) created_by_user_id, created_at_ms, updated_at_ms`, userRegionProjection("bd_profiles", "user_id"))
@ -118,6 +125,29 @@ func userRegionValue(ctx context.Context, q sqlQueryer, userID int64, lockClause
return regionID, err return regionID, err
} }
func defaultAgencyProfileFromOwner(ctx context.Context, tx *sql.Tx, ownerUserID int64, explicitName string) (string, string, error) {
snapshot, err := roleInvitationUserSnapshotByID(ctx, tx, ownerUserID)
if err != nil {
return "", "", err
}
name := strings.TrimSpace(explicitName)
if name == "" {
// Agency 的默认资料只在创建身份这一刻从 owner 用户资料复制一次;
// 后续用户资料和 Agency 资料完全分离,不能再在查询层动态兜底。
name = firstNonBlank(snapshot.Username, snapshot.DisplayUserID, fmt.Sprintf("%d", ownerUserID))
}
return name, strings.TrimSpace(snapshot.Avatar), nil
}
func firstNonBlank(values ...string) string {
for _, value := range values {
if trimmed := strings.TrimSpace(value); trimmed != "" {
return trimmed
}
}
return ""
}
func currentUserRegion(ctx context.Context, q sqlQueryer, userID int64, lockClause string) (int64, error) { func currentUserRegion(ctx context.Context, q sqlQueryer, userID int64, lockClause string) (int64, error) {
// Host 领域不拥有 users 表,但所有角色流转都依赖用户当前有效区域。 // Host 领域不拥有 users 表,但所有角色流转都依赖用户当前有效区域。
// 调用方需要串行化用户身份变化时传入 FOR UPDATE 来锁住 users 行。 // 调用方需要串行化用户身份变化时传入 FOR UPDATE 来锁住 users 行。

View File

@ -512,12 +512,17 @@ func (r *Repository) acceptAgencyInvitation(ctx context.Context, tx *sql.Tx, com
// Agency、拥有者 host_profile、拥有者成员关系是同一业务事实的三张表投影 // Agency、拥有者 host_profile、拥有者成员关系是同一业务事实的三张表投影
// 必须全部创建成功后邀请才能进入已接受状态。 // 必须全部创建成功后邀请才能进入已接受状态。
agencyName, agencyAvatar, err := defaultAgencyProfileFromOwner(ctx, tx, invitation.TargetUserID, invitation.AgencyName)
if err != nil {
return false, false, err
}
agency := hostdomain.Agency{ agency := hostdomain.Agency{
AgencyID: command.AgencyID, AgencyID: command.AgencyID,
OwnerUserID: invitation.TargetUserID, OwnerUserID: invitation.TargetUserID,
RegionID: targetRegionID, RegionID: targetRegionID,
ParentBDUserID: invitation.ParentBDUserID, ParentBDUserID: invitation.ParentBDUserID,
Name: invitation.AgencyName, Name: agencyName,
Avatar: agencyAvatar,
Status: hostdomain.AgencyStatusActive, Status: hostdomain.AgencyStatusActive,
JoinEnabled: true, JoinEnabled: true,
// max_hosts 是历史兼容字段,当前业务不再限制主播数量。 // max_hosts 是历史兼容字段,当前业务不再限制主播数量。

View File

@ -31,13 +31,13 @@ func (r *Repository) SearchAgencies(ctx context.Context, command hostservice.Sea
COALESCE(owner.region_id, 0), COALESCE(owner.region_id, 0),
a.parent_bd_user_id, a.parent_bd_user_id,
a.name, a.name,
a.avatar,
a.status, a.status,
a.join_enabled, a.join_enabled,
a.max_hosts, a.max_hosts,
a.created_by_user_id, a.created_by_user_id,
a.created_at_ms, a.created_at_ms,
a.updated_at_ms, a.updated_at_ms,
COALESCE(owner.avatar, ''),
COUNT(active_member.membership_id) COUNT(active_member.membership_id)
FROM agencies a FROM agencies a
INNER JOIN users owner INNER JOIN users owner
@ -65,13 +65,13 @@ func (r *Repository) SearchAgencies(ctx context.Context, command hostservice.Sea
owner.region_id, owner.region_id,
a.parent_bd_user_id, a.parent_bd_user_id,
a.name, a.name,
a.avatar,
a.status, a.status,
a.join_enabled, a.join_enabled,
a.max_hosts, a.max_hosts,
a.created_by_user_id, a.created_by_user_id,
a.created_at_ms, a.created_at_ms,
a.updated_at_ms, a.updated_at_ms
owner.avatar
ORDER BY a.created_at_ms DESC, a.agency_id DESC ORDER BY a.created_at_ms DESC, a.agency_id DESC
LIMIT ? LIMIT ?
` `
@ -618,12 +618,14 @@ func scanAgency(scanner rowScanner) (hostdomain.Agency, error) {
&agency.RegionID, &agency.RegionID,
&agency.ParentBDUserID, &agency.ParentBDUserID,
&agency.Name, &agency.Name,
&agency.Avatar,
&agency.Status, &agency.Status,
&agency.JoinEnabled, &agency.JoinEnabled,
&agency.MaxHosts, &agency.MaxHosts,
&agency.CreatedByUserID, &agency.CreatedByUserID,
&agency.CreatedAtMs, &agency.CreatedAtMs,
&agency.UpdatedAtMs, &agency.UpdatedAtMs,
&agency.ActiveHostCount,
) )
return agency, err return agency, err
} }
@ -636,13 +638,13 @@ func scanSearchAgency(scanner rowScanner) (hostdomain.Agency, error) {
&agency.RegionID, &agency.RegionID,
&agency.ParentBDUserID, &agency.ParentBDUserID,
&agency.Name, &agency.Name,
&agency.Avatar,
&agency.Status, &agency.Status,
&agency.JoinEnabled, &agency.JoinEnabled,
&agency.MaxHosts, &agency.MaxHosts,
&agency.CreatedByUserID, &agency.CreatedByUserID,
&agency.CreatedAtMs, &agency.CreatedAtMs,
&agency.UpdatedAtMs, &agency.UpdatedAtMs,
&agency.OwnerAvatar,
&agency.ActiveHostCount, &agency.ActiveHostCount,
) )
return agency, err return agency, err

View File

@ -181,10 +181,10 @@ func insertAgency(ctx context.Context, tx *sql.Tx, agency hostdomain.Agency) err
// 第一阶段只有接受 Agency 邀请时会创建 Agency。 // 第一阶段只有接受 Agency 邀请时会创建 Agency。
_, err := tx.ExecContext(ctx, ` _, err := tx.ExecContext(ctx, `
INSERT INTO agencies ( INSERT INTO agencies (
app_code, agency_id, owner_user_id, parent_bd_user_id, name, status, app_code, agency_id, owner_user_id, parent_bd_user_id, name, avatar, status,
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, appcode.FromContext(ctx), agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs) `, appcode.FromContext(ctx), agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Avatar, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs)
return err return err
} }
@ -198,6 +198,16 @@ func updateAgencyAdminState(ctx context.Context, tx *sql.Tx, agency hostdomain.A
return err return err
} }
func updateAgencyProfile(ctx context.Context, tx *sql.Tx, agency hostdomain.Agency) error {
// Agency 资料是独立组织资料;这里绝不更新 users 表,也不从 owner 用户资料重新派生。
_, err := tx.ExecContext(ctx, `
UPDATE agencies
SET name = ?, avatar = ?, updated_at_ms = ?
WHERE app_code = ? AND agency_id = ?
`, agency.Name, agency.Avatar, agency.UpdatedAtMs, appcode.FromContext(ctx), agency.AgencyID)
return err
}
func insertBDProfile(ctx context.Context, tx *sql.Tx, profile hostdomain.BDProfile) error { func insertBDProfile(ctx context.Context, tx *sql.Tx, profile hostdomain.BDProfile) error {
// 普通 BD 身份行和 host_profile 相互独立BD 用户不会自动成为 Host也不会隐式拥有 BD Leader 权限。 // 普通 BD 身份行和 host_profile 相互独立BD 用户不会自动成为 Host也不会隐式拥有 BD Leader 权限。
_, err := tx.ExecContext(ctx, ` _, err := tx.ExecContext(ctx, `

View File

@ -855,18 +855,19 @@ func (r *Repository) PutAgency(agency hostdomain.Agency) {
_, err := r.schema.DB.ExecContext(context.Background(), ` _, err := r.schema.DB.ExecContext(context.Background(), `
INSERT INTO agencies ( INSERT INTO agencies (
agency_id, owner_user_id, parent_bd_user_id, name, status, agency_id, owner_user_id, parent_bd_user_id, name, avatar, status,
join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms join_enabled, max_hosts, created_by_user_id, created_at_ms, updated_at_ms
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE ON DUPLICATE KEY UPDATE
owner_user_id = VALUES(owner_user_id), owner_user_id = VALUES(owner_user_id),
parent_bd_user_id = VALUES(parent_bd_user_id), parent_bd_user_id = VALUES(parent_bd_user_id),
name = VALUES(name), name = VALUES(name),
avatar = VALUES(avatar),
status = VALUES(status), status = VALUES(status),
join_enabled = VALUES(join_enabled), join_enabled = VALUES(join_enabled),
max_hosts = VALUES(max_hosts), max_hosts = VALUES(max_hosts),
updated_at_ms = VALUES(updated_at_ms) updated_at_ms = VALUES(updated_at_ms)
`, agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs) `, agency.AgencyID, agency.OwnerUserID, agency.ParentBDUserID, agency.Name, agency.Avatar, agency.Status, agency.JoinEnabled, agency.MaxHosts, agency.CreatedByUserID, agency.CreatedAtMs, agency.UpdatedAtMs)
if err != nil { if err != nil {
r.t.Fatalf("seed agency %d failed: %v", agency.AgencyID, err) r.t.Fatalf("seed agency %d failed: %v", agency.AgencyID, err)
} }

View File

@ -434,7 +434,7 @@ func toProtoAgency(agency hostdomain.Agency) *userv1.Agency {
CreatedByUserId: agency.CreatedByUserID, CreatedByUserId: agency.CreatedByUserID,
CreatedAtMs: agency.CreatedAtMs, CreatedAtMs: agency.CreatedAtMs,
UpdatedAtMs: agency.UpdatedAtMs, UpdatedAtMs: agency.UpdatedAtMs,
Avatar: agency.OwnerAvatar, Avatar: agency.Avatar,
HostCount: agency.ActiveHostCount, HostCount: agency.ActiveHostCount,
} }
} }

View File

@ -393,6 +393,26 @@ func (s *Server) GetAgency(ctx context.Context, req *userv1.GetAgencyRequest) (*
return &userv1.GetAgencyResponse{Agency: toProtoAgency(agency)}, nil return &userv1.GetAgencyResponse{Agency: toProtoAgency(agency)}, nil
} }
// UpdateAgencyProfile 修改 Agency 独立资料;用户资料和 Agency 资料不会互相回写。
func (s *Server) UpdateAgencyProfile(ctx context.Context, req *userv1.UpdateAgencyProfileRequest) (*userv1.UpdateAgencyProfileResponse, error) {
if s.hostSvc == nil {
return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "host service is not configured"))
}
ctx = contextWithApp(ctx, req.GetMeta())
agency, err := s.hostSvc.UpdateAgencyProfile(ctx, hostservice.UpdateAgencyProfileInput{
CommandID: req.GetCommandId(),
OperatorUserID: req.GetOperatorUserId(),
AgencyID: req.GetAgencyId(),
Name: req.Name,
Avatar: req.Avatar,
RequestID: req.GetMeta().GetRequestId(),
})
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &userv1.UpdateAgencyProfileResponse{Agency: toProtoAgency(agency)}, nil
}
// CheckBusinessCapability 返回 H5/App 业务入口可用性,具体身份规则由 host service 统一判断。 // CheckBusinessCapability 返回 H5/App 业务入口可用性,具体身份规则由 host service 统一判断。
func (s *Server) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) { func (s *Server) CheckBusinessCapability(ctx context.Context, req *userv1.CheckBusinessCapabilityRequest) (*userv1.CheckBusinessCapabilityResponse, error) {
if s.hostSvc == nil { if s.hostSvc == nil {