From e5b4e1ebeba646d58e2b283de8ff142572364bfb Mon Sep 17 00:00:00 2001 From: "lijunwen.gigoo" Date: Fri, 10 Oct 2025 17:45:52 +0800 Subject: [PATCH] feat(plugin): search & category list & call info --- .../product_public_api/public_api.go | 290 +++++++++++++++++- backend/application/plugin/plugin.go | 6 +- backend/domain/user/entity/user.go | 7 + backend/domain/user/service/user.go | 2 +- backend/domain/user/service/user_saas_impl.go | 31 +- idl/marketplace/public_api.thrift | 13 +- 6 files changed, 319 insertions(+), 30 deletions(-) diff --git a/backend/api/model/marketplace/product_public_api/public_api.go b/backend/api/model/marketplace/product_public_api/public_api.go index 8609021ab..451b38729 100644 --- a/backend/api/model/marketplace/product_public_api/public_api.go +++ b/backend/api/model/marketplace/product_public_api/public_api.go @@ -28165,6 +28165,238 @@ func (p *ProductCallRateLimit) String() string { } +type UserInfo struct { + // User name + Name string `thrift:"name,1" form:"name" json:"name" query:"name"` + // User icon + Icon string `thrift:"icon,2" form:"icon" json:"icon" query:"icon"` + // User role + Role string `thrift:"role,3" form:"role" json:"role" query:"role"` +} + +func NewUserInfo() *UserInfo { + return &UserInfo{} +} + +func (p *UserInfo) InitDefault() { +} + +func (p *UserInfo) GetName() (v string) { + return p.Name +} + +func (p *UserInfo) GetIcon() (v string) { + return p.Icon +} + +func (p *UserInfo) GetRole() (v string) { + return p.Role +} + +var fieldIDToName_UserInfo = map[int16]string{ + 1: "name", + 2: "icon", + 3: "role", +} + +func (p *UserInfo) Read(iprot thrift.TProtocol) (err error) { + var fieldTypeId thrift.TType + var fieldId int16 + + if _, err = iprot.ReadStructBegin(); err != nil { + goto ReadStructBeginError + } + + for { + _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() + if err != nil { + goto ReadFieldBeginError + } + if fieldTypeId == thrift.STOP { + break + } + + switch fieldId { + case 1: + if fieldTypeId == thrift.STRING { + if err = p.ReadField1(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 2: + if fieldTypeId == thrift.STRING { + if err = p.ReadField2(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + case 3: + if fieldTypeId == thrift.STRING { + if err = p.ReadField3(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + default: + if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } + } + if err = iprot.ReadFieldEnd(); err != nil { + goto ReadFieldEndError + } + } + if err = iprot.ReadStructEnd(); err != nil { + goto ReadStructEndError + } + + return nil +ReadStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) +ReadFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) +ReadFieldError: + return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_UserInfo[fieldId]), err) +SkipFieldError: + return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) + +ReadFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) +ReadStructEndError: + return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) +} + +func (p *UserInfo) ReadField1(iprot thrift.TProtocol) error { + + var _field string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = v + } + p.Name = _field + return nil +} +func (p *UserInfo) ReadField2(iprot thrift.TProtocol) error { + + var _field string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = v + } + p.Icon = _field + return nil +} +func (p *UserInfo) ReadField3(iprot thrift.TProtocol) error { + + var _field string + if v, err := iprot.ReadString(); err != nil { + return err + } else { + _field = v + } + p.Role = _field + return nil +} + +func (p *UserInfo) Write(oprot thrift.TProtocol) (err error) { + var fieldId int16 + if err = oprot.WriteStructBegin("UserInfo"); err != nil { + goto WriteStructBeginError + } + if p != nil { + if err = p.writeField1(oprot); err != nil { + fieldId = 1 + goto WriteFieldError + } + if err = p.writeField2(oprot); err != nil { + fieldId = 2 + goto WriteFieldError + } + if err = p.writeField3(oprot); err != nil { + fieldId = 3 + goto WriteFieldError + } + } + if err = oprot.WriteFieldStop(); err != nil { + goto WriteFieldStopError + } + if err = oprot.WriteStructEnd(); err != nil { + goto WriteStructEndError + } + return nil +WriteStructBeginError: + return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) +WriteFieldError: + return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) +WriteFieldStopError: + return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) +WriteStructEndError: + return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) +} + +func (p *UserInfo) writeField1(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("name", thrift.STRING, 1); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(p.Name); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) +} +func (p *UserInfo) writeField2(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("icon", thrift.STRING, 2); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(p.Icon); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 2 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 2 end error: ", p), err) +} +func (p *UserInfo) writeField3(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("role", thrift.STRING, 3); err != nil { + goto WriteFieldBeginError + } + if err := oprot.WriteString(p.Role); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 3 end error: ", p), err) +} + +func (p *UserInfo) String() string { + if p == nil { + return "" + } + return fmt.Sprintf("UserInfo(%+v)", *p) + +} + type GetProductCallInfoData struct { // mcp configuration json string McpJSON string `thrift:"mcp_json,1" form:"mcp_json" json:"mcp_json" query:"mcp_json"` @@ -28174,6 +28406,8 @@ type GetProductCallInfoData struct { CallCountLimit *ProductCallCountLimit `thrift:"call_count_limit,3" form:"call_count_limit" json:"call_count_limit" query:"call_count_limit"` // Plugin tool call rate limit CallRateLimit *ProductCallRateLimit `thrift:"call_rate_limit,4" form:"call_rate_limit" json:"call_rate_limit" query:"call_rate_limit"` + // User info + UserInfo *UserInfo `thrift:"user_info,5" form:"user_info" json:"user_info" query:"user_info"` } func NewGetProductCallInfoData() *GetProductCallInfoData { @@ -28209,11 +28443,21 @@ func (p *GetProductCallInfoData) GetCallRateLimit() (v *ProductCallRateLimit) { return p.CallRateLimit } +var GetProductCallInfoData_UserInfo_DEFAULT *UserInfo + +func (p *GetProductCallInfoData) GetUserInfo() (v *UserInfo) { + if !p.IsSetUserInfo() { + return GetProductCallInfoData_UserInfo_DEFAULT + } + return p.UserInfo +} + var fieldIDToName_GetProductCallInfoData = map[int16]string{ 1: "mcp_json", 2: "user_level", 3: "call_count_limit", 4: "call_rate_limit", + 5: "user_info", } func (p *GetProductCallInfoData) IsSetCallCountLimit() bool { @@ -28224,6 +28468,10 @@ func (p *GetProductCallInfoData) IsSetCallRateLimit() bool { return p.CallRateLimit != nil } +func (p *GetProductCallInfoData) IsSetUserInfo() bool { + return p.UserInfo != nil +} + func (p *GetProductCallInfoData) Read(iprot thrift.TProtocol) (err error) { var fieldTypeId thrift.TType var fieldId int16 @@ -28274,6 +28522,14 @@ func (p *GetProductCallInfoData) Read(iprot thrift.TProtocol) (err error) { } else if err = iprot.Skip(fieldTypeId); err != nil { goto SkipFieldError } + case 5: + if fieldTypeId == thrift.STRUCT { + if err = p.ReadField5(iprot); err != nil { + goto ReadFieldError + } + } else if err = iprot.Skip(fieldTypeId); err != nil { + goto SkipFieldError + } default: if err = iprot.Skip(fieldTypeId); err != nil { goto SkipFieldError @@ -28341,6 +28597,14 @@ func (p *GetProductCallInfoData) ReadField4(iprot thrift.TProtocol) error { p.CallRateLimit = _field return nil } +func (p *GetProductCallInfoData) ReadField5(iprot thrift.TProtocol) error { + _field := NewUserInfo() + if err := _field.Read(iprot); err != nil { + return err + } + p.UserInfo = _field + return nil +} func (p *GetProductCallInfoData) Write(oprot thrift.TProtocol) (err error) { var fieldId int16 @@ -28364,6 +28628,10 @@ func (p *GetProductCallInfoData) Write(oprot thrift.TProtocol) (err error) { fieldId = 4 goto WriteFieldError } + if err = p.writeField5(oprot); err != nil { + fieldId = 5 + goto WriteFieldError + } } if err = oprot.WriteFieldStop(); err != nil { goto WriteFieldStopError @@ -28446,6 +28714,22 @@ WriteFieldBeginError: WriteFieldEndError: return thrift.PrependError(fmt.Sprintf("%T write field 4 end error: ", p), err) } +func (p *GetProductCallInfoData) writeField5(oprot thrift.TProtocol) (err error) { + if err = oprot.WriteFieldBegin("user_info", thrift.STRUCT, 5); err != nil { + goto WriteFieldBeginError + } + if err := p.UserInfo.Write(oprot); err != nil { + return err + } + if err = oprot.WriteFieldEnd(); err != nil { + goto WriteFieldEndError + } + return nil +WriteFieldBeginError: + return thrift.PrependError(fmt.Sprintf("%T write field 5 begin error: ", p), err) +WriteFieldEndError: + return thrift.PrependError(fmt.Sprintf("%T write field 5 end error: ", p), err) +} func (p *GetProductCallInfoData) String() string { if p == nil { @@ -28456,9 +28740,9 @@ func (p *GetProductCallInfoData) String() string { } type GetProductCallInfoResponse struct { - Code int32 `thrift:"Code,1,required" form:"Code,required" json:"Code,required" query:"Code,required"` - Message string `thrift:"Message,2,required" form:"Message,required" json:"Message,required" query:"Message,required"` - Data *GetProductCallInfoData `thrift:"Data,3,optional" form:"Data" json:"Data,omitempty" query:"Data"` + Code int32 `thrift:"Code,1,required" form:"code,required" json:"code,required"` + Message string `thrift:"Message,2,required" form:"message,required" json:"message,required"` + Data *GetProductCallInfoData `thrift:"Data,3,optional" form:"data" json:"data,omitempty"` BaseResp *base.BaseResp `thrift:"BaseResp,255,optional" form:"BaseResp" json:"BaseResp,omitempty" query:"BaseResp"` } diff --git a/backend/application/plugin/plugin.go b/backend/application/plugin/plugin.go index eb6d8aa4b..62c142cd8 100644 --- a/backend/application/plugin/plugin.go +++ b/backend/application/plugin/plugin.go @@ -584,7 +584,7 @@ func (p *PluginApplicationService) GetProductCallInfo(ctx context.Context, req * }, nil } - _, err = p.userSVC.GetSaasUserInfo(ctx) + userInfo, err := p.userSVC.GetSaasUserInfo(ctx) if err != nil { logs.CtxErrorf(ctx, "GetSaasUserInfo failed: %v", err) return &productAPI.GetProductCallInfoResponse{ @@ -605,6 +605,10 @@ func (p *PluginApplicationService) GetProductCallInfo(ctx context.Context, req * // Build response data data := &productAPI.GetProductCallInfoData{ UserLevel: productAPI.UserLevel_Free, + UserInfo: &productAPI.UserInfo{ + Name: userInfo.NickName, + Icon: userInfo.AvatarURL, + }, } data.CallCountLimit = &productAPI.ProductCallCountLimit{ diff --git a/backend/domain/user/entity/user.go b/backend/domain/user/entity/user.go index 7561d980b..3d4803116 100644 --- a/backend/domain/user/entity/user.go +++ b/backend/domain/user/entity/user.go @@ -39,3 +39,10 @@ type UserBenefit struct { TotalCount int32 IsUnlimited bool } + +type SaasUserData struct { + UserID string `json:"user_id"` + UserName string `json:"user_name"` + NickName string `json:"nick_name"` + AvatarURL string `json:"avatar_url"` +} diff --git a/backend/domain/user/service/user.go b/backend/domain/user/service/user.go index 7ec6bdac1..250afcf89 100644 --- a/backend/domain/user/service/user.go +++ b/backend/domain/user/service/user.go @@ -81,6 +81,6 @@ type User interface { } type SaasUserProvider interface { - GetSaasUserInfo(ctx context.Context) (user *entity.User, err error) + GetSaasUserInfo(ctx context.Context) (user *entity.SaasUserData, err error) GetUserBenefit(ctx context.Context) (benefit *entity.UserBenefit, err error) } diff --git a/backend/domain/user/service/user_saas_impl.go b/backend/domain/user/service/user_saas_impl.go index 22e233782..ed65ddac1 100644 --- a/backend/domain/user/service/user_saas_impl.go +++ b/backend/domain/user/service/user_saas_impl.go @@ -19,7 +19,6 @@ package service import ( "context" "encoding/json" - "strconv" "github.com/coze-dev/coze-studio/backend/domain/user/entity" "github.com/coze-dev/coze-studio/backend/pkg/errorx" @@ -41,7 +40,7 @@ func NewCozeUserService() *CozeUserService { } // GetUserInfo calls the /v1/users/me endpoint -func (s *CozeUserService) GetUserInfo(ctx context.Context) (*entity.User, error) { +func (s *CozeUserService) GetUserInfo(ctx context.Context) (*entity.SaasUserData, error) { resp, err := s.client.Get(ctx, "/v1/users/me") if err != nil { logs.CtxErrorf(ctx, "failed to call GetUserInfo API: %v", err) @@ -49,31 +48,19 @@ func (s *CozeUserService) GetUserInfo(ctx context.Context) (*entity.User, error) } // Parse the data field - var userData struct { - UserID string `json:"user_id"` - UserName string `json:"user_name"` - NickName string `json:"nick_name"` - AvatarURL string `json:"avatar_url"` - } + var userData entity.SaasUserData if err := json.Unmarshal(resp.Data, &userData); err != nil { logs.CtxErrorf(ctx, "failed to parse user data: %v", err) return nil, errorx.New(errno.ErrUserResourceNotFound, errorx.KV("reason", "data parse failed")) } - // Convert user_id from string to int64 - userIDInt64, err := strconv.ParseInt(userData.UserID, 10, 64) - if err != nil { - logs.CtxErrorf(ctx, "failed to parse user_id: %v", err) - return nil, errorx.New(errno.ErrUserResourceNotFound, errorx.KV("reason", "invalid user_id format")) - } - - // Map to entity.User - return &entity.User{ - UserID: userIDInt64, - Name: userData.NickName, // nick_name maps to Name (nickname) - UniqueName: userData.UserName, // user_name maps to UniqueName - IconURL: userData.AvatarURL, // avatar_url maps to IconURL + // Map to entity.SaasUserData + return &entity.SaasUserData{ + UserID: userData.UserID, + UserName: userData.UserName, + NickName: userData.NickName, + AvatarURL: userData.AvatarURL, }, nil } @@ -157,7 +144,7 @@ func getCozeUserService() *CozeUserService { return cozeUserService } -func (u *userImpl) GetSaasUserInfo(ctx context.Context) (*entity.User, error) { +func (u *userImpl) GetSaasUserInfo(ctx context.Context) (*entity.SaasUserData, error) { return getCozeUserService().GetUserInfo(ctx) } diff --git a/idl/marketplace/public_api.thrift b/idl/marketplace/public_api.thrift index af5f793e4..1fe374bc5 100644 --- a/idl/marketplace/public_api.thrift +++ b/idl/marketplace/public_api.thrift @@ -697,17 +697,24 @@ struct ProductCallRateLimit { 2: map call_rate_limit_by_user_level, // Plugin tool call rate limit by user level } +struct UserInfo { + 1: string name, // User name + 2: string icon, // User icon + 3: string role, // User role +} + struct GetProductCallInfoData { 1: string mcp_json, // mcp configuration json string 2: UserLevel user_level, // Payment level 3: ProductCallCountLimit call_count_limit, // Plugin tool call count limit 4: ProductCallRateLimit call_rate_limit, // Plugin tool call rate limit + 5: UserInfo user_info, // User info } struct GetProductCallInfoResponse { - 1 : required i32 Code (agw.key = "code") , - 2 : required string Message (agw.key = "message"), - 3 : optional GetProductCallInfoData Data (agw.key = "data") , + 1 : required i32 Code (agw.key = "code", api.body= "code") , + 2 : required string Message (agw.key = "message", api.body= "message"), + 3 : optional GetProductCallInfoData Data (agw.key = "data", api.body= "data") , 255: optional base.BaseResp BaseResp }