feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conf
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"github.com/bytedance/sonic"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
func InitConfig(ctx context.Context) (err error) {
cwd, err := os.Getwd()
if err != nil {
logs.Warnf("[InitConfig] Failed to get current working directory: %v", err)
cwd = os.Getenv("PWD")
}
basePath := path.Join(cwd, "resources", "conf", "plugin")
err = loadPluginProductMeta(ctx, basePath)
if err != nil {
return err
}
err = loadOAuthSchema(ctx, basePath)
if err != nil {
return err
}
return nil
}
var oauthSchema string
func GetOAuthSchema() string {
return oauthSchema
}
func loadOAuthSchema(ctx context.Context, basePath string) (err error) {
filePath := path.Join(basePath, "common", "oauth_schema.json")
file, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("read file '%s' failed, err=%v", filePath, err)
}
if !isValidJSON(file) {
return fmt.Errorf("invalid json, filePath=%s", filePath)
}
oauthSchema = string(file)
return nil
}
func isValidJSON(data []byte) bool {
var js json.RawMessage
return sonic.Unmarshal(data, &js) == nil
}

View File

@@ -0,0 +1,278 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package conf
import (
"context"
"fmt"
"os"
"path"
"strings"
"github.com/getkin/kin-openapi/openapi3"
"golang.org/x/mod/semver"
"gopkg.in/yaml.v3"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
type pluginProductMeta struct {
PluginID int64 `yaml:"plugin_id" validate:"required"`
ProductID int64 `yaml:"product_id" validate:"required"`
Deprecated bool `yaml:"deprecated"`
Version string `yaml:"version" validate:"required"`
PluginType common.PluginType `yaml:"plugin_type" validate:"required"`
OpenapiDocFile string `yaml:"openapi_doc_file" validate:"required"`
Manifest *entity.PluginManifest `yaml:"manifest" validate:"required"`
Tools []*toolProductMeta `yaml:"tools" validate:"required"`
}
type toolProductMeta struct {
ToolID int64 `yaml:"tool_id" validate:"required"`
Deprecated bool `yaml:"deprecated"`
Method string `yaml:"method" validate:"required"`
SubURL string `yaml:"sub_url" validate:"required"`
}
var (
pluginProducts map[int64]*PluginInfo
toolProducts map[int64]*ToolInfo
)
func GetToolProduct(toolID int64) (*ToolInfo, bool) {
ti, ok := toolProducts[toolID]
return ti, ok
}
func MGetToolProducts(toolIDs []int64) []*ToolInfo {
tools := make([]*ToolInfo, 0, len(toolIDs))
for _, toolID := range toolIDs {
ti, ok := toolProducts[toolID]
if !ok {
continue
}
tools = append(tools, ti)
}
return tools
}
func GetPluginProduct(pluginID int64) (*PluginInfo, bool) {
pl, ok := pluginProducts[pluginID]
return pl, ok
}
func MGetPluginProducts(pluginIDs []int64) []*PluginInfo {
plugins := make([]*PluginInfo, 0, len(pluginIDs))
for _, pluginID := range pluginIDs {
pl, ok := pluginProducts[pluginID]
if !ok {
continue
}
plugins = append(plugins, pl)
}
return plugins
}
func GetAllPluginProducts() []*PluginInfo {
plugins := make([]*PluginInfo, 0, len(pluginProducts))
for _, pl := range pluginProducts {
plugins = append(plugins, pl)
}
return plugins
}
type PluginInfo struct {
Info *model.PluginInfo
ToolIDs []int64
}
func (pi PluginInfo) GetPluginAllTools() (tools []*ToolInfo) {
tools = make([]*ToolInfo, 0, len(pi.ToolIDs))
for _, toolID := range pi.ToolIDs {
ti, ok := toolProducts[toolID]
if !ok {
continue
}
tools = append(tools, ti)
}
return tools
}
type ToolInfo struct {
Info *entity.ToolInfo
}
func loadPluginProductMeta(ctx context.Context, basePath string) (err error) {
root := path.Join(basePath, "pluginproduct")
metaFile := path.Join(root, "plugin_meta.yaml")
file, err := os.ReadFile(metaFile)
if err != nil {
return fmt.Errorf("read file '%s' failed, err=%v", metaFile, err)
}
var pluginsMeta []*pluginProductMeta
err = yaml.Unmarshal(file, &pluginsMeta)
if err != nil {
return fmt.Errorf("unmarshal file '%s' failed, err=%v", metaFile, err)
}
pluginProducts = make(map[int64]*PluginInfo, len(pluginsMeta))
toolProducts = map[int64]*ToolInfo{}
for _, m := range pluginsMeta {
if !checkPluginMetaInfo(ctx, m) {
continue
}
err = m.Manifest.Validate(true)
if err != nil {
logs.CtxErrorf(ctx, "plugin manifest validates failed, err=%v", err)
continue
}
docPath := path.Join(root, m.OpenapiDocFile)
loader := openapi3.NewLoader()
_doc, err := loader.LoadFromFile(docPath)
if err != nil {
logs.CtxErrorf(ctx, "load file '%s', err=%v", docPath, err)
continue
}
doc := ptr.Of(model.Openapi3T(*_doc))
err = doc.Validate(ctx)
if err != nil {
logs.CtxErrorf(ctx, "the openapi3 doc '%s' validates failed, err=%v", m.OpenapiDocFile, err)
continue
}
pi := &PluginInfo{
Info: &model.PluginInfo{
ID: m.PluginID,
RefProductID: &m.ProductID,
PluginType: m.PluginType,
Version: ptr.Of(m.Version),
IconURI: ptr.Of(m.Manifest.LogoURL),
ServerURL: ptr.Of(doc.Servers[0].URL),
Manifest: m.Manifest,
OpenapiDoc: doc,
},
ToolIDs: make([]int64, 0, len(m.Tools)),
}
if pluginProducts[m.PluginID] != nil {
logs.CtxErrorf(ctx, "duplicate plugin id '%d'", m.PluginID)
continue
}
pluginProducts[m.PluginID] = pi
apis := make(map[entity.UniqueToolAPI]*model.Openapi3Operation, len(doc.Paths))
for subURL, pathItem := range doc.Paths {
for method, op := range pathItem.Operations() {
api := entity.UniqueToolAPI{
SubURL: subURL,
Method: strings.ToUpper(method),
}
apis[api] = model.NewOpenapi3Operation(op)
}
}
for _, t := range m.Tools {
if t.Deprecated {
continue
}
_, ok := toolProducts[t.ToolID]
if ok {
logs.CtxErrorf(ctx, "duplicate tool id '%d'", t.ToolID)
continue
}
api := entity.UniqueToolAPI{
SubURL: t.SubURL,
Method: strings.ToUpper(t.Method),
}
op, ok := apis[api]
if !ok {
logs.CtxErrorf(ctx, "api '[%s]:%s' not found in doc '%s'", api.Method, api.SubURL, docPath)
continue
}
if err = op.Validate(ctx); err != nil {
logs.CtxErrorf(ctx, "the openapi3 operation of tool '[%s]:%s' in '%s' validates failed, err=%v",
t.Method, t.SubURL, m.OpenapiDocFile, err)
continue
}
pi.ToolIDs = append(pi.ToolIDs, t.ToolID)
toolProducts[t.ToolID] = &ToolInfo{
Info: &entity.ToolInfo{
ID: t.ToolID,
PluginID: m.PluginID,
Version: ptr.Of(m.Version),
Method: ptr.Of(t.Method),
SubURL: ptr.Of(t.SubURL),
Operation: op,
ActivatedStatus: ptr.Of(model.ActivateTool),
DebugStatus: ptr.Of(common.APIDebugStatus_DebugPassed),
},
}
}
if len(pi.ToolIDs) == 0 {
delete(pluginProducts, m.PluginID)
}
}
return nil
}
func checkPluginMetaInfo(ctx context.Context, m *pluginProductMeta) (continued bool) {
if m.Deprecated {
return false
}
if !semver.IsValid(m.Version) {
logs.CtxErrorf(ctx, "invalid version '%s'", m.Version)
return false
}
if m.PluginID <= 0 {
logs.CtxErrorf(ctx, "invalid plugin id '%d'", m.PluginID)
return false
}
if m.ProductID <= 0 {
logs.CtxErrorf(ctx, "invalid product id '%d'", m.ProductID)
return false
}
_, ok := toolProducts[m.PluginID]
if ok {
logs.CtxErrorf(ctx, "duplicate plugin id '%d'", m.PluginID)
return false
}
if m.PluginType != common.PluginType_PLUGIN {
logs.CtxErrorf(ctx, "invalid plugin type '%s'", m.PluginType)
return false
}
return true
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package entity
type PageInfo struct {
Name *string
Page int
Size int
SortBy *SortField
OrderByACS *bool
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package entity
import (
"strings"
)
const (
larkPluginOAuthHostName = "open.larkoffice.com"
larkOAuthHostName = "open.feishu.cn"
)
func GetOAuthProvider(tokenURL string) OAuthProvider {
if strings.Contains(tokenURL, larkPluginOAuthHostName) {
return OAuthProviderOfLarkPlugin
}
if strings.Contains(tokenURL, larkOAuthHostName) {
return OAuthProviderOfLark
}
return OAuthProviderOfStandard
}
type SortField string
const (
SortByCreatedAt SortField = "created_at"
SortByUpdatedAt SortField = "updated_at"
)
type OAuthProvider string
const (
OAuthProviderOfLarkPlugin OAuthProvider = "lark_plugin"
OAuthProviderOfLark OAuthProvider = "lark"
OAuthProviderOfStandard OAuthProvider = "standard"
)

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package entity
import (
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
)
type AuthorizationCodeMeta struct {
UserID string
PluginID int64
IsDraft bool
}
type AuthorizationCodeInfo struct {
RecordID int64
Meta *AuthorizationCodeMeta
Config *model.OAuthAuthorizationCodeConfig
AccessToken string
RefreshToken string
TokenExpiredAtMS int64
NextTokenRefreshAtMS *int64
LastActiveAtMS int64
}
func (a *AuthorizationCodeInfo) GetNextTokenRefreshAtMS() int64 {
if a == nil {
return 0
}
return ptr.FromOrDefault(a.NextTokenRefreshAtMS, 0)
}
type OAuthInfo struct {
OAuthMode model.AuthzSubType
AuthorizationCode *AuthorizationCodeInfo
}
type OAuthState struct {
ClientName OAuthProvider `json:"client_name"`
UserID string `json:"user_id"`
PluginID int64 `json:"plugin_id"`
IsDraft bool `json:"is_draft"`
}

View File

@@ -0,0 +1,217 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package entity
import (
"context"
"net/http"
"strconv"
"github.com/bytedance/sonic"
"github.com/getkin/kin-openapi/openapi3"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
type PluginInfo struct {
*model.PluginInfo
}
func NewPluginInfo(info *model.PluginInfo) *PluginInfo {
return &PluginInfo{
PluginInfo: info,
}
}
func NewPluginInfos(infos []*model.PluginInfo) []*PluginInfo {
res := make([]*PluginInfo, 0, len(infos))
for _, info := range infos {
res = append(res, NewPluginInfo(info))
}
return res
}
func (p PluginInfo) GetServerURL() string {
return ptr.FromOrDefault(p.ServerURL, "")
}
func (p PluginInfo) GetRefProductID() int64 {
return ptr.FromOrDefault(p.RefProductID, 0)
}
func (p PluginInfo) GetVersion() string {
return ptr.FromOrDefault(p.Version, "")
}
func (p PluginInfo) GetVersionDesc() string {
return ptr.FromOrDefault(p.VersionDesc, "")
}
func (p PluginInfo) GetAPPID() int64 {
return ptr.FromOrDefault(p.APPID, 0)
}
type ToolExample struct {
RequestExample string
ResponseExample string
}
func (p PluginInfo) GetToolExample(ctx context.Context, toolName string) *ToolExample {
if p.OpenapiDoc == nil ||
p.OpenapiDoc.Components == nil ||
len(p.OpenapiDoc.Components.Examples) == 0 {
return nil
}
example, ok := p.OpenapiDoc.Components.Examples[toolName]
if !ok {
return nil
}
if example.Value == nil || example.Value.Value == nil {
return nil
}
val, ok := example.Value.Value.(map[string]any)
if !ok {
return nil
}
reqExample, ok := val["ReqExample"]
if !ok {
return nil
}
reqExampleStr, err := sonic.MarshalString(reqExample)
if err != nil {
logs.CtxErrorf(ctx, "marshal request example failed, err=%v", err)
return nil
}
respExample, ok := val["RespExample"]
if !ok {
return nil
}
respExampleStr, err := sonic.MarshalString(respExample)
if err != nil {
logs.CtxErrorf(ctx, "marshal response example failed, err=%v", err)
return nil
}
return &ToolExample{
RequestExample: reqExampleStr,
ResponseExample: respExampleStr,
}
}
type ToolInfo = model.ToolInfo
type AgentToolIdentity struct {
ToolID int64
ToolName *string
AgentID int64
VersionMs *int64
}
type VersionTool = model.VersionTool
type VersionPlugin = model.VersionPlugin
type VersionAgentTool = model.VersionAgentTool
type ExecuteToolOpt = model.ExecuteToolOpt
type ProjectInfo = model.ProjectInfo
type PluginManifest = model.PluginManifest
func NewDefaultPluginManifest() *PluginManifest {
return &model.PluginManifest{
SchemaVersion: "v1",
API: model.APIDesc{
Type: model.PluginTypeOfCloud,
},
Auth: &model.AuthV2{
Type: model.AuthzTypeOfNone,
},
CommonParams: map[model.HTTPParamLocation][]*plugin_develop_common.CommonParamSchema{
model.ParamInBody: {},
model.ParamInHeader: {
{
Name: "User-Agent",
Value: "Coze/1.0",
},
},
model.ParamInPath: {},
model.ParamInQuery: {},
},
}
}
func NewDefaultOpenapiDoc() *model.Openapi3T {
return &model.Openapi3T{
OpenAPI: "3.0.1",
Info: &openapi3.Info{
Version: "v1",
},
Paths: openapi3.Paths{},
Servers: openapi3.Servers{},
}
}
type UniqueToolAPI struct {
SubURL string
Method string
}
func DefaultOpenapi3Responses() openapi3.Responses {
return openapi3.Responses{
strconv.Itoa(http.StatusOK): {
Value: &openapi3.Response{
Description: ptr.Of("description is required"),
Content: openapi3.Content{
model.MediaTypeJson: &openapi3.MediaType{
Schema: &openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: openapi3.TypeObject,
Properties: map[string]*openapi3.SchemaRef{},
},
},
},
},
},
},
}
}
func DefaultOpenapi3RequestBody() *openapi3.RequestBodyRef {
return &openapi3.RequestBodyRef{
Value: &openapi3.RequestBody{
Content: map[string]*openapi3.MediaType{
model.MediaTypeJson: {
Schema: &openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: openapi3.TypeObject,
Properties: map[string]*openapi3.SchemaRef{},
},
},
},
},
},
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"errors"
"fmt"
"gorm.io/gen"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewAgentToolVersionDAO(db *gorm.DB, idGen idgen.IDGenerator) *AgentToolVersionDAO {
return &AgentToolVersionDAO{
idGen: idGen,
query: query.Use(db),
}
}
type AgentToolVersionDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type agentToolVersionPO model.AgentToolVersion
func (a agentToolVersionPO) ToDO() *entity.ToolInfo {
return &entity.ToolInfo{
ID: a.ToolID,
PluginID: a.PluginID,
Version: &a.ToolVersion,
Method: &a.Method,
SubURL: &a.SubURL,
Operation: a.Operation,
}
}
// TODO(@maronghong): 简化查询代码,封装查询条件
func (at *AgentToolVersionDAO) GetWithToolName(ctx context.Context, agentID int64, toolName string, agentVersion *string) (tool *entity.ToolInfo, exist bool, err error) {
table := at.query.AgentToolVersion
conds := []gen.Condition{
table.AgentID.Eq(agentID),
table.ToolName.Eq(toolName),
}
var tl *model.AgentToolVersion
if agentVersion == nil || *agentVersion == "" {
tl, err = table.WithContext(ctx).
Where(conds...).
Order(table.CreatedAt.Desc()).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
} else {
conds = append(conds, table.AgentVersion.Eq(*agentVersion))
tl, err = table.WithContext(ctx).
Where(conds...).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
}
tool = agentToolVersionPO(*tl).ToDO()
return tool, true, nil
}
func (at *AgentToolVersionDAO) Get(ctx context.Context, agentID int64, vAgentTool entity.VersionAgentTool) (tool *entity.ToolInfo, exist bool, err error) {
table := at.query.AgentToolVersion
conds := []gen.Condition{
table.AgentID.Eq(agentID),
table.ToolID.Eq(vAgentTool.ToolID),
}
var tl *model.AgentToolVersion
if vAgentTool.AgentVersion == nil || *vAgentTool.AgentVersion == "" {
tl, err = table.WithContext(ctx).
Where(conds...).
Order(table.CreatedAt.Desc()).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
} else {
conds = append(conds, table.AgentVersion.Eq(*vAgentTool.AgentVersion))
tl, err = table.WithContext(ctx).
Where(conds...).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
}
tool = agentToolVersionPO(*tl).ToDO()
return tool, true, nil
}
func (at *AgentToolVersionDAO) MGet(ctx context.Context, agentID int64, vAgentTools []entity.VersionAgentTool) (tools []*entity.ToolInfo, err error) {
tools = make([]*entity.ToolInfo, 0, len(vAgentTools))
table := at.query.AgentToolVersion
chunks := slices.Chunks(vAgentTools, 20)
noVersion := make([]entity.VersionAgentTool, 0, len(vAgentTools))
for _, chunk := range chunks {
var q query.IAgentToolVersionDo
for _, v := range chunk {
if v.AgentVersion == nil || *v.AgentVersion == "" {
noVersion = append(noVersion, v)
continue
}
if q == nil {
q = table.WithContext(ctx).
Where(
table.Where(
table.ToolID.Eq(chunk[0].ToolID),
table.AgentVersion.Eq(*chunk[0].AgentVersion),
),
)
} else {
q = q.Or(
table.ToolID.Eq(v.ToolID),
table.AgentVersion.Eq(*v.AgentVersion),
)
}
}
if q == nil {
continue
}
tls, err := q.Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, agentToolVersionPO(*tl).ToDO())
}
}
for _, v := range noVersion {
tool, exist, err := at.Get(ctx, agentID, v)
if err != nil {
return nil, err
}
if !exist {
continue
}
tools = append(tools, tool)
}
return tools, nil
}
func (at *AgentToolVersionDAO) BatchCreate(ctx context.Context, agentID int64, agentVersion string,
tools []*entity.ToolInfo) (err error) {
tls := make([]*model.AgentToolVersion, 0, len(tools))
for _, tl := range tools {
if tl.Version == nil || *tl.Version == "" {
return fmt.Errorf("invalid tool version")
}
id, err := at.idGen.GenID(ctx)
if err != nil {
return err
}
tls = append(tls, &model.AgentToolVersion{
ID: id,
AgentID: agentID,
PluginID: tl.PluginID,
ToolID: tl.ID,
AgentVersion: agentVersion,
ToolVersion: *tl.Version,
SubURL: tl.GetSubURL(),
Method: tl.GetMethod(),
ToolName: tl.GetName(),
Operation: tl.Operation,
})
}
err = at.query.Transaction(func(tx *query.Query) error {
table := tx.AgentToolVersion
return table.WithContext(ctx).CreateInBatches(tls, 10)
})
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,276 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"errors"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewAgentToolDraftDAO(db *gorm.DB, idGen idgen.IDGenerator) *AgentToolDraftDAO {
return &AgentToolDraftDAO{
idGen: idGen,
query: query.Use(db),
}
}
type AgentToolDraftDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type agentToolDraftPO model.AgentToolDraft
func (a agentToolDraftPO) ToDO() *entity.ToolInfo {
return &entity.ToolInfo{
ID: a.ToolID,
PluginID: a.PluginID,
CreatedAt: a.CreatedAt,
Version: &a.ToolVersion,
Method: &a.Method,
SubURL: &a.SubURL,
Operation: a.Operation,
}
}
func (at *AgentToolDraftDAO) Get(ctx context.Context, agentID, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
table := at.query.AgentToolDraft
tl, err := table.WithContext(ctx).
Where(
table.AgentID.Eq(agentID),
table.ToolID.Eq(toolID),
).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
tool = agentToolDraftPO(*tl).ToDO()
return tool, true, nil
}
func (at *AgentToolDraftDAO) GetWithToolName(ctx context.Context, agentID int64, toolName string) (tool *entity.ToolInfo, exist bool, err error) {
table := at.query.AgentToolDraft
tl, err := table.WithContext(ctx).
Where(
table.AgentID.Eq(agentID),
table.ToolName.Eq(toolName),
).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
tool = agentToolDraftPO(*tl).ToDO()
return tool, true, nil
}
func (at *AgentToolDraftDAO) MGet(ctx context.Context, agentID int64, toolIDs []int64) (tools []*entity.ToolInfo, err error) {
tools = make([]*entity.ToolInfo, 0, len(toolIDs))
table := at.query.AgentToolDraft
chunks := slices.Chunks(toolIDs, 20)
for _, chunk := range chunks {
tls, err := table.WithContext(ctx).
Where(
table.AgentID.Eq(agentID),
table.ToolID.In(chunk...),
).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, agentToolDraftPO(*tl).ToDO())
}
}
return tools, nil
}
func (at *AgentToolDraftDAO) GetAll(ctx context.Context, agentID int64) (tools []*entity.ToolInfo, err error) {
const limit = 20
table := at.query.AgentToolDraft
cursor := int64(0)
for {
tls, err := table.WithContext(ctx).
Where(
table.AgentID.Eq(agentID),
table.ID.Gt(cursor),
).
Order(table.ID.Asc()).
Limit(limit).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, agentToolDraftPO(*tl).ToDO())
}
if len(tls) < limit {
break
}
cursor = tls[len(tls)-1].ID
}
return tools, nil
}
func (at *AgentToolDraftDAO) UpdateWithToolName(ctx context.Context, agentID int64, toolName string, tool *entity.ToolInfo) (err error) {
m := &model.AgentToolDraft{
Operation: tool.Operation,
}
table := at.query.AgentToolDraft
_, err = table.WithContext(ctx).
Where(
table.AgentID.Eq(agentID),
table.ToolName.Eq(toolName),
).
Updates(m)
if err != nil {
return err
}
return nil
}
func (at *AgentToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx, agentID int64, tools []*entity.ToolInfo) (err error) {
tls := make([]*model.AgentToolDraft, 0, len(tools))
for _, tl := range tools {
id, err := at.idGen.GenID(ctx)
if err != nil {
return err
}
m := &model.AgentToolDraft{
ID: id,
ToolID: tl.ID,
PluginID: tl.PluginID,
AgentID: agentID,
SubURL: tl.GetSubURL(),
Method: tl.GetMethod(),
ToolVersion: tl.GetVersion(),
ToolName: tl.GetName(),
Operation: tl.Operation,
}
tls = append(tls, m)
}
table := tx.AgentToolDraft
err = table.WithContext(ctx).CreateInBatches(tls, 20)
if err != nil {
return err
}
return nil
}
func (at *AgentToolDraftDAO) DeleteAll(ctx context.Context, agentID int64) (err error) {
const limit = 20
table := at.query.AgentToolDraft
for {
info, err := table.WithContext(ctx).
Where(table.AgentID.Eq(agentID)).
Limit(limit).
Delete()
if err != nil {
return err
}
if info.RowsAffected == 0 || info.RowsAffected < limit {
break
}
}
return nil
}
func (at *AgentToolDraftDAO) GetAllPluginIDs(ctx context.Context, agentID int64) (pluginIDs []int64, err error) {
const size = 100
table := at.query.AgentToolDraft
cursor := int64(0)
for {
tls, err := table.WithContext(ctx).
Select(table.PluginID, table.ID).
Where(
table.AgentID.Eq(agentID),
table.ID.Gt(cursor),
).
Order(table.ID.Asc()).
Limit(size).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
pluginIDs = append(pluginIDs, tl.PluginID)
}
if len(tls) < size {
break
}
cursor = tls[len(tls)-1].ID
}
return slices.Unique(pluginIDs), nil
}
func (at *AgentToolDraftDAO) DeleteAllWithTX(ctx context.Context, tx *query.QueryTx, agentID int64) (err error) {
const limit = 20
table := tx.AgentToolDraft
for {
info, err := table.WithContext(ctx).
Where(table.AgentID.Eq(agentID)).
Limit(limit).
Delete()
if err != nil {
return err
}
if info.RowsAffected == 0 || info.RowsAffected < limit {
break
}
}
return nil
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"errors"
"time"
redisV9 "github.com/redis/go-redis/v9"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
)
type OAuthCache struct {
cacheCli *redisV9.Client
}
func NewOAuthCache(cacheCli *redisV9.Client) *OAuthCache {
return &OAuthCache{
cacheCli: cacheCli,
}
}
func (o *OAuthCache) Get(ctx context.Context, key string) (value string, exist bool, err error) {
cmd := o.cacheCli.Get(ctx, key)
if cmd.Err() != nil {
if errors.Is(cmd.Err(), redisV9.Nil) {
return "", false, nil
}
return "", false, cmd.Err()
}
return cmd.Val(), true, nil
}
func (o *OAuthCache) Set(ctx context.Context, key string, value string, expiration *time.Duration) (err error) {
_expiration := ptr.FromOrDefault(expiration, 0)
cmd := o.cacheCli.Set(ctx, key, value, _expiration)
return cmd.Err()
}

View File

@@ -0,0 +1,28 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
const TableNameAgentToolDraft = "agent_tool_draft"
// AgentToolDraft Draft Agent Tool
type AgentToolDraft struct {
ID int64 `gorm:"column:id;primaryKey;comment:Primary Key ID" json:"id"` // Primary Key ID
AgentID int64 `gorm:"column:agent_id;not null;comment:Agent ID" json:"agent_id"` // Agent ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
ToolID int64 `gorm:"column:tool_id;not null;comment:Tool ID" json:"tool_id"` // Tool ID
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
SubURL string `gorm:"column:sub_url;not null;comment:Sub URL Path" json:"sub_url"` // Sub URL Path
Method string `gorm:"column:method;not null;comment:HTTP Request Method" json:"method"` // HTTP Request Method
ToolName string `gorm:"column:tool_name;not null;comment:Tool Name" json:"tool_name"` // Tool Name
ToolVersion string `gorm:"column:tool_version;not null;comment:Tool Version, e.g. v1.0.0" json:"tool_version"` // Tool Version, e.g. v1.0.0
Operation *plugin.Openapi3Operation `gorm:"column:operation;comment:Tool Openapi Operation Schema;serializer:json" json:"operation"` // Tool Openapi Operation Schema
}
// TableName AgentToolDraft's table name
func (*AgentToolDraft) TableName() string {
return TableNameAgentToolDraft
}

View File

@@ -0,0 +1,29 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
const TableNameAgentToolVersion = "agent_tool_version"
// AgentToolVersion Agent Tool Version
type AgentToolVersion struct {
ID int64 `gorm:"column:id;primaryKey;comment:Primary Key ID" json:"id"` // Primary Key ID
AgentID int64 `gorm:"column:agent_id;not null;comment:Agent ID" json:"agent_id"` // Agent ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
ToolID int64 `gorm:"column:tool_id;not null;comment:Tool ID" json:"tool_id"` // Tool ID
AgentVersion string `gorm:"column:agent_version;not null;comment:Agent Tool Version" json:"agent_version"` // Agent Tool Version
ToolName string `gorm:"column:tool_name;not null;comment:Tool Name" json:"tool_name"` // Tool Name
ToolVersion string `gorm:"column:tool_version;not null;comment:Tool Version, e.g. v1.0.0" json:"tool_version"` // Tool Version, e.g. v1.0.0
SubURL string `gorm:"column:sub_url;not null;comment:Sub URL Path" json:"sub_url"` // Sub URL Path
Method string `gorm:"column:method;not null;comment:HTTP Request Method" json:"method"` // HTTP Request Method
Operation *plugin.Openapi3Operation `gorm:"column:operation;comment:Tool Openapi Operation Schema;serializer:json" json:"operation"` // Tool Openapi Operation Schema
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
}
// TableName AgentToolVersion's table name
func (*AgentToolVersion) TableName() string {
return TableNameAgentToolVersion
}

View File

@@ -0,0 +1,31 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
const TableNamePlugin = "plugin"
// Plugin Latest Plugin
type Plugin struct {
ID int64 `gorm:"column:id;primaryKey;comment:Plugin ID" json:"id"` // Plugin ID
SpaceID int64 `gorm:"column:space_id;not null;comment:Space ID" json:"space_id"` // Space ID
DeveloperID int64 `gorm:"column:developer_id;not null;comment:Developer ID" json:"developer_id"` // Developer ID
AppID int64 `gorm:"column:app_id;not null;comment:Application ID" json:"app_id"` // Application ID
IconURI string `gorm:"column:icon_uri;not null;comment:Icon URI" json:"icon_uri"` // Icon URI
ServerURL string `gorm:"column:server_url;not null;comment:Server URL" json:"server_url"` // Server URL
PluginType int32 `gorm:"column:plugin_type;not null;comment:Plugin Type, 1:http, 6:local" json:"plugin_type"` // Plugin Type, 1:http, 6:local
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
UpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
Version string `gorm:"column:version;not null;comment:Plugin Version, e.g. v1.0.0" json:"version"` // Plugin Version, e.g. v1.0.0
VersionDesc string `gorm:"column:version_desc;comment:Plugin Version Description" json:"version_desc"` // Plugin Version Description
Manifest *plugin.PluginManifest `gorm:"column:manifest;comment:Plugin Manifest;serializer:json" json:"manifest"` // Plugin Manifest
OpenapiDoc *plugin.Openapi3T `gorm:"column:openapi_doc;comment:OpenAPI Document, only stores the root;serializer:json" json:"openapi_doc"` // OpenAPI Document, only stores the root
}
// TableName Plugin's table name
func (*Plugin) TableName() string {
return TableNamePlugin
}

View File

@@ -0,0 +1,33 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"gorm.io/gorm"
)
const TableNamePluginDraft = "plugin_draft"
// PluginDraft Draft Plugin
type PluginDraft struct {
ID int64 `gorm:"column:id;primaryKey;comment:Plugin ID" json:"id"` // Plugin ID
SpaceID int64 `gorm:"column:space_id;not null;comment:Space ID" json:"space_id"` // Space ID
DeveloperID int64 `gorm:"column:developer_id;not null;comment:Developer ID" json:"developer_id"` // Developer ID
AppID int64 `gorm:"column:app_id;not null;comment:Application ID" json:"app_id"` // Application ID
IconURI string `gorm:"column:icon_uri;not null;comment:Icon URI" json:"icon_uri"` // Icon URI
ServerURL string `gorm:"column:server_url;not null;comment:Server URL" json:"server_url"` // Server URL
PluginType int32 `gorm:"column:plugin_type;not null;comment:Plugin Type, 1:http, 6:local" json:"plugin_type"` // Plugin Type, 1:http, 6:local
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
UpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:Delete Time" json:"deleted_at"` // Delete Time
Manifest *plugin.PluginManifest `gorm:"column:manifest;comment:Plugin Manifest;serializer:json" json:"manifest"` // Plugin Manifest
OpenapiDoc *plugin.Openapi3T `gorm:"column:openapi_doc;comment:OpenAPI Document, only stores the root;serializer:json" json:"openapi_doc"` // OpenAPI Document, only stores the root
}
// TableName PluginDraft's table name
func (*PluginDraft) TableName() string {
return TableNamePluginDraft
}

View File

@@ -0,0 +1,30 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
const TableNamePluginOauthAuth = "plugin_oauth_auth"
// PluginOauthAuth Plugin OAuth Authorization Code Info
type PluginOauthAuth struct {
ID int64 `gorm:"column:id;primaryKey;comment:Primary Key" json:"id"` // Primary Key
UserID string `gorm:"column:user_id;not null;comment:User ID" json:"user_id"` // User ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
IsDraft bool `gorm:"column:is_draft;not null;comment:Is Draft Plugin" json:"is_draft"` // Is Draft Plugin
OauthConfig *plugin.OAuthAuthorizationCodeConfig `gorm:"column:oauth_config;comment:Authorization Code OAuth Config;serializer:json" json:"oauth_config"` // Authorization Code OAuth Config
AccessToken string `gorm:"column:access_token;not null;comment:Access Token" json:"access_token"` // Access Token
RefreshToken string `gorm:"column:refresh_token;not null;comment:Refresh Token" json:"refresh_token"` // Refresh Token
TokenExpiredAt int64 `gorm:"column:token_expired_at;comment:Token Expired in Milliseconds" json:"token_expired_at"` // Token Expired in Milliseconds
NextTokenRefreshAt int64 `gorm:"column:next_token_refresh_at;comment:Next Token Refresh Time in Milliseconds" json:"next_token_refresh_at"` // Next Token Refresh Time in Milliseconds
LastActiveAt int64 `gorm:"column:last_active_at;comment:Last active time in Milliseconds" json:"last_active_at"` // Last active time in Milliseconds
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
UpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
}
// TableName PluginOauthAuth's table name
func (*PluginOauthAuth) TableName() string {
return TableNamePluginOauthAuth
}

View File

@@ -0,0 +1,35 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"gorm.io/gorm"
)
const TableNamePluginVersion = "plugin_version"
// PluginVersion Plugin Version
type PluginVersion struct {
ID int64 `gorm:"column:id;primaryKey;comment:Primary Key ID" json:"id"` // Primary Key ID
SpaceID int64 `gorm:"column:space_id;not null;comment:Space ID" json:"space_id"` // Space ID
DeveloperID int64 `gorm:"column:developer_id;not null;comment:Developer ID" json:"developer_id"` // Developer ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
AppID int64 `gorm:"column:app_id;not null;comment:Application ID" json:"app_id"` // Application ID
IconURI string `gorm:"column:icon_uri;not null;comment:Icon URI" json:"icon_uri"` // Icon URI
ServerURL string `gorm:"column:server_url;not null;comment:Server URL" json:"server_url"` // Server URL
PluginType int32 `gorm:"column:plugin_type;not null;comment:Plugin Type, 1:http, 6:local" json:"plugin_type"` // Plugin Type, 1:http, 6:local
Version string `gorm:"column:version;not null;comment:Plugin Version, e.g. v1.0.0" json:"version"` // Plugin Version, e.g. v1.0.0
VersionDesc string `gorm:"column:version_desc;comment:Plugin Version Description" json:"version_desc"` // Plugin Version Description
Manifest *plugin.PluginManifest `gorm:"column:manifest;comment:Plugin Manifest;serializer:json" json:"manifest"` // Plugin Manifest
OpenapiDoc *plugin.Openapi3T `gorm:"column:openapi_doc;comment:OpenAPI Document, only stores the root;serializer:json" json:"openapi_doc"` // OpenAPI Document, only stores the root
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:Delete Time" json:"deleted_at"` // Delete Time
}
// TableName PluginVersion's table name
func (*PluginVersion) TableName() string {
return TableNamePluginVersion
}

View File

@@ -0,0 +1,27 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
const TableNameTool = "tool"
// Tool Latest Tool
type Tool struct {
ID int64 `gorm:"column:id;primaryKey;comment:Tool ID" json:"id"` // Tool ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
UpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
Version string `gorm:"column:version;not null;comment:Tool Version, e.g. v1.0.0" json:"version"` // Tool Version, e.g. v1.0.0
SubURL string `gorm:"column:sub_url;not null;comment:Sub URL Path" json:"sub_url"` // Sub URL Path
Method string `gorm:"column:method;not null;comment:HTTP Request Method" json:"method"` // HTTP Request Method
Operation *plugin.Openapi3Operation `gorm:"column:operation;comment:Tool Openapi Operation Schema;serializer:json" json:"operation"` // Tool Openapi Operation Schema
ActivatedStatus int32 `gorm:"column:activated_status;not null;comment:0:activated; 1:deactivated" json:"activated_status"` // 0:activated; 1:deactivated
}
// TableName Tool's table name
func (*Tool) TableName() string {
return TableNameTool
}

View File

@@ -0,0 +1,27 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
const TableNameToolDraft = "tool_draft"
// ToolDraft Draft Tool
type ToolDraft struct {
ID int64 `gorm:"column:id;primaryKey;comment:Tool ID" json:"id"` // Tool ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
UpdatedAt int64 `gorm:"column:updated_at;not null;autoUpdateTime:milli;comment:Update Time in Milliseconds" json:"updated_at"` // Update Time in Milliseconds
SubURL string `gorm:"column:sub_url;not null;comment:Sub URL Path" json:"sub_url"` // Sub URL Path
Method string `gorm:"column:method;not null;comment:HTTP Request Method" json:"method"` // HTTP Request Method
Operation *plugin.Openapi3Operation `gorm:"column:operation;comment:Tool Openapi Operation Schema;serializer:json" json:"operation"` // Tool Openapi Operation Schema
DebugStatus int32 `gorm:"column:debug_status;not null;comment:0:not pass; 1:pass" json:"debug_status"` // 0:not pass; 1:pass
ActivatedStatus int32 `gorm:"column:activated_status;not null;comment:0:activated; 1:deactivated" json:"activated_status"` // 0:activated; 1:deactivated
}
// TableName ToolDraft's table name
func (*ToolDraft) TableName() string {
return TableNameToolDraft
}

View File

@@ -0,0 +1,30 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package model
import (
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"gorm.io/gorm"
)
const TableNameToolVersion = "tool_version"
// ToolVersion Tool Version
type ToolVersion struct {
ID int64 `gorm:"column:id;primaryKey;comment:Primary Key ID" json:"id"` // Primary Key ID
ToolID int64 `gorm:"column:tool_id;not null;comment:Tool ID" json:"tool_id"` // Tool ID
PluginID int64 `gorm:"column:plugin_id;not null;comment:Plugin ID" json:"plugin_id"` // Plugin ID
Version string `gorm:"column:version;not null;comment:Tool Version, e.g. v1.0.0" json:"version"` // Tool Version, e.g. v1.0.0
SubURL string `gorm:"column:sub_url;not null;comment:Sub URL Path" json:"sub_url"` // Sub URL Path
Method string `gorm:"column:method;not null;comment:HTTP Request Method" json:"method"` // HTTP Request Method
Operation *plugin.Openapi3Operation `gorm:"column:operation;comment:Tool Openapi Operation Schema;serializer:json" json:"operation"` // Tool Openapi Operation Schema
CreatedAt int64 `gorm:"column:created_at;not null;autoCreateTime:milli;comment:Create Time in Milliseconds" json:"created_at"` // Create Time in Milliseconds
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;comment:Delete Time" json:"deleted_at"` // Delete Time
}
// TableName ToolVersion's table name
func (*ToolVersion) TableName() string {
return TableNameToolVersion
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
type PluginSelectedOption struct {
PluginID bool
OpenapiDoc bool
Manifest bool
IconURI bool
Version bool
}
type ToolSelectedOption struct {
ToolID bool
ToolMethod bool
ToolSubURL bool
DebugStatus bool
ActivatedStatus bool
}

View File

@@ -0,0 +1,253 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"encoding/json"
"errors"
"fmt"
"gorm.io/gen/field"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewPluginDAO(db *gorm.DB, idGen idgen.IDGenerator) *PluginDAO {
return &PluginDAO{
idGen: idGen,
query: query.Use(db),
}
}
type PluginDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type pluginPO model.Plugin
func (p pluginPO) ToDO() *entity.PluginInfo {
return entity.NewPluginInfo(&plugin.PluginInfo{
ID: p.ID,
SpaceID: p.SpaceID,
DeveloperID: p.DeveloperID,
IconURI: &p.IconURI,
ServerURL: &p.ServerURL,
PluginType: plugin_develop_common.PluginType(p.PluginType),
CreatedAt: p.CreatedAt,
UpdatedAt: p.UpdatedAt,
Version: &p.Version,
VersionDesc: &p.VersionDesc,
Manifest: p.Manifest,
OpenapiDoc: p.OpenapiDoc,
})
}
func (p *PluginDAO) getSelected(opt *PluginSelectedOption) (selected []field.Expr) {
if opt == nil {
return selected
}
table := p.query.Plugin
if opt.PluginID {
selected = append(selected, table.ID)
}
if opt.OpenapiDoc {
selected = append(selected, table.OpenapiDoc)
}
if opt.Version {
selected = append(selected, table.Version)
}
if opt.Manifest {
selected = append(selected, table.Manifest)
}
if opt.IconURI {
selected = append(selected, table.IconURI)
}
return selected
}
func (p *PluginDAO) Get(ctx context.Context, pluginID int64, opt *PluginSelectedOption) (plugin *entity.PluginInfo, exist bool, err error) {
table := p.query.Plugin
pl, err := table.WithContext(ctx).
Where(table.ID.Eq(pluginID)).
Select(p.getSelected(opt)...).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
plugin = pluginPO(*pl).ToDO()
return plugin, true, nil
}
func (p *PluginDAO) MGet(ctx context.Context, pluginIDs []int64, opt *PluginSelectedOption) (plugins []*entity.PluginInfo, err error) {
plugins = make([]*entity.PluginInfo, 0, len(pluginIDs))
table := p.query.Plugin
chunks := slices.Chunks(pluginIDs, 10)
for _, chunk := range chunks {
pls, err := table.WithContext(ctx).
Select(p.getSelected(opt)...).
Where(table.ID.In(chunk...)).
Find()
if err != nil {
return nil, err
}
for _, pl := range pls {
plugins = append(plugins, pluginPO(*pl).ToDO())
}
}
return plugins, nil
}
func (p *PluginDAO) List(ctx context.Context, spaceID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error) {
if pageInfo.SortBy == nil || pageInfo.OrderByACS == nil {
return nil, 0, fmt.Errorf("sortBy or orderByACS is empty")
}
var orderExpr field.Expr
table := p.query.Plugin
switch *pageInfo.SortBy {
case entity.SortByCreatedAt:
if *pageInfo.OrderByACS {
orderExpr = table.CreatedAt.Asc()
} else {
orderExpr = table.CreatedAt.Desc()
}
case entity.SortByUpdatedAt:
if *pageInfo.OrderByACS {
orderExpr = table.UpdatedAt.Asc()
} else {
orderExpr = table.UpdatedAt.Desc()
}
default:
return nil, 0, fmt.Errorf("invalid sortBy '%v'", *pageInfo.SortBy)
}
offset := (pageInfo.Page - 1) * pageInfo.Size
pls, total, err := table.WithContext(ctx).
Where(table.SpaceID.Eq(spaceID)).
Order(orderExpr).
FindByPage(offset, pageInfo.Size)
if err != nil {
return nil, 0, err
}
plugins = make([]*entity.PluginInfo, 0, len(pls))
for _, pl := range pls {
plugins = append(plugins, pluginPO(*pl).ToDO())
}
return plugins, total, nil
}
func (p *PluginDAO) UpsertWithTX(ctx context.Context, tx *query.QueryTx, plugin *entity.PluginInfo) (err error) {
table := tx.Plugin
_, err = table.WithContext(ctx).Select(table.ID).Where(table.ID.Eq(plugin.ID)).First()
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
m := &model.Plugin{
ID: plugin.ID,
SpaceID: plugin.SpaceID,
DeveloperID: plugin.DeveloperID,
AppID: plugin.GetAPPID(),
Manifest: plugin.Manifest,
OpenapiDoc: plugin.OpenapiDoc,
PluginType: int32(plugin.PluginType),
IconURI: plugin.GetIconURI(),
ServerURL: plugin.GetServerURL(),
Version: plugin.GetVersion(),
VersionDesc: plugin.GetVersionDesc(),
}
return table.WithContext(ctx).Create(m)
}
updateMap := map[string]any{}
if plugin.APPID != nil {
updateMap[table.AppID.ColumnName().String()] = *plugin.APPID
}
if plugin.IconURI != nil {
updateMap[table.IconURI.ColumnName().String()] = *plugin.IconURI
}
if plugin.Version != nil {
updateMap[table.Version.ColumnName().String()] = *plugin.Version
}
if plugin.VersionDesc != nil {
updateMap[table.VersionDesc.ColumnName().String()] = *plugin.VersionDesc
}
if plugin.ServerURL != nil {
updateMap[table.ServerURL.ColumnName().String()] = *plugin.ServerURL
}
if plugin.Manifest != nil {
b, err := json.Marshal(plugin.Manifest)
if err != nil {
return err
}
updateMap[table.Manifest.ColumnName().String()] = b
}
if plugin.OpenapiDoc != nil {
b, err := json.Marshal(plugin.OpenapiDoc)
if err != nil {
return err
}
updateMap[table.OpenapiDoc.ColumnName().String()] = b
}
_, err = table.WithContext(ctx).
Where(table.ID.Eq(plugin.ID)).
Updates(updateMap)
if err != nil {
return err
}
return nil
}
func (p *PluginDAO) DeleteWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {
table := tx.Plugin
_, err = table.WithContext(ctx).
Where(table.ID.Eq(pluginID)).
Delete()
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,348 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"encoding/json"
"errors"
"fmt"
"gorm.io/gen/field"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewPluginDraftDAO(db *gorm.DB, idGen idgen.IDGenerator) *PluginDraftDAO {
return &PluginDraftDAO{
idGen: idGen,
query: query.Use(db),
}
}
type PluginDraftDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type pluginDraftPO model.PluginDraft
func (p pluginDraftPO) ToDO() *entity.PluginInfo {
return entity.NewPluginInfo(&plugin.PluginInfo{
ID: p.ID,
SpaceID: p.SpaceID,
DeveloperID: p.DeveloperID,
APPID: &p.AppID,
IconURI: &p.IconURI,
ServerURL: &p.ServerURL,
PluginType: plugin_develop_common.PluginType(p.PluginType),
CreatedAt: p.CreatedAt,
UpdatedAt: p.UpdatedAt,
Manifest: p.Manifest,
OpenapiDoc: p.OpenapiDoc,
})
}
func (p *PluginDraftDAO) getSelected(opt *PluginSelectedOption) (selected []field.Expr) {
if opt == nil {
return selected
}
table := p.query.PluginDraft
if opt.PluginID {
selected = append(selected, table.ID)
}
if opt.OpenapiDoc {
selected = append(selected, table.OpenapiDoc)
}
if opt.Manifest {
selected = append(selected, table.Manifest)
}
if opt.IconURI {
selected = append(selected, table.IconURI)
}
return selected
}
func (p *PluginDraftDAO) Create(ctx context.Context, plugin *entity.PluginInfo) (pluginID int64, err error) {
id, err := p.idGen.GenID(ctx)
if err != nil {
return 0, err
}
mf, err := plugin.Manifest.EncryptAuthPayload()
if err != nil {
return 0, fmt.Errorf("EncryptAuthPayload failed, err=%w", err)
}
table := p.query.PluginDraft
err = table.WithContext(ctx).Create(&model.PluginDraft{
ID: id,
SpaceID: plugin.SpaceID,
DeveloperID: plugin.DeveloperID,
PluginType: int32(plugin.PluginType),
IconURI: plugin.GetIconURI(),
ServerURL: plugin.GetServerURL(),
AppID: plugin.GetAPPID(),
Manifest: mf,
OpenapiDoc: plugin.OpenapiDoc,
})
if err != nil {
return 0, err
}
return id, nil
}
func (p *PluginDraftDAO) Get(ctx context.Context, pluginID int64, opt *PluginSelectedOption) (plugin *entity.PluginInfo, exist bool, err error) {
table := p.query.PluginDraft
pl, err := table.WithContext(ctx).
Select(p.getSelected(opt)...).
Where(table.ID.Eq(pluginID)).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
plugin = pluginDraftPO(*pl).ToDO()
return plugin, true, nil
}
func (p *PluginDraftDAO) GetAPPAllPlugins(ctx context.Context, appID int64, opt *PluginSelectedOption) (plugins []*entity.PluginInfo, err error) {
table := p.query.PluginDraft
cursor := int64(0)
limit := 20
for {
pls, err := table.WithContext(ctx).
Select(p.getSelected(opt)...).
Where(
table.AppID.Eq(appID),
table.ID.Gt(cursor),
).
Order(table.ID.Asc()).
Limit(limit).
Find()
if err != nil {
return nil, err
}
for _, pl := range pls {
plugins = append(plugins, pluginDraftPO(*pl).ToDO())
}
if len(pls) < limit {
break
}
cursor = pls[len(pls)-1].ID
}
return plugins, nil
}
func (p *PluginDraftDAO) MGet(ctx context.Context, pluginIDs []int64, opt *PluginSelectedOption) (plugins []*entity.PluginInfo, err error) {
plugins = make([]*entity.PluginInfo, 0, len(pluginIDs))
table := p.query.PluginDraft
chunks := slices.Chunks(pluginIDs, 20)
for _, chunk := range chunks {
pls, err := table.WithContext(ctx).
Select(p.getSelected(opt)...).
Where(table.ID.In(chunk...)).
Find()
if err != nil {
return nil, err
}
for _, pl := range pls {
plugins = append(plugins, pluginDraftPO(*pl).ToDO())
}
}
return plugins, nil
}
func (p *PluginDraftDAO) List(ctx context.Context, spaceID, appID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error) {
if pageInfo.SortBy == nil || pageInfo.OrderByACS == nil {
return nil, 0, fmt.Errorf("sortBy or orderByACS is empty")
}
var orderExpr field.Expr
table := p.query.PluginDraft
switch *pageInfo.SortBy {
case entity.SortByCreatedAt:
if *pageInfo.OrderByACS {
orderExpr = table.CreatedAt.Asc()
} else {
orderExpr = table.CreatedAt.Desc()
}
case entity.SortByUpdatedAt:
if *pageInfo.OrderByACS {
orderExpr = table.UpdatedAt.Asc()
} else {
orderExpr = table.UpdatedAt.Desc()
}
default:
return nil, 0, fmt.Errorf("invalid sortBy '%v'", *pageInfo.SortBy)
}
offset := (pageInfo.Page - 1) * pageInfo.Size
pls, total, err := table.WithContext(ctx).
Where(
table.SpaceID.Eq(spaceID),
table.AppID.Eq(appID),
).
Order(orderExpr).
FindByPage(offset, pageInfo.Size)
if err != nil {
return nil, 0, err
}
plugins = make([]*entity.PluginInfo, 0, len(pls))
for _, pl := range pls {
plugins = append(plugins, pluginDraftPO(*pl).ToDO())
}
return plugins, total, nil
}
func (p *PluginDraftDAO) Update(ctx context.Context, plugin *entity.PluginInfo) (err error) {
mf, err := plugin.Manifest.EncryptAuthPayload()
if err != nil {
return fmt.Errorf("EncryptAuthPayload failed, err=%w", err)
}
m := &model.PluginDraft{
Manifest: mf,
OpenapiDoc: plugin.OpenapiDoc,
}
if plugin.IconURI != nil {
m.IconURI = *plugin.IconURI
}
table := p.query.PluginDraft
_, err = table.WithContext(ctx).
Where(table.ID.Eq(plugin.ID)).
Updates(m)
if err != nil {
return err
}
return nil
}
func (p *PluginDraftDAO) CreateWithTX(ctx context.Context, tx *query.QueryTx, plugin *entity.PluginInfo) (pluginID int64, err error) {
id, err := p.idGen.GenID(ctx)
if err != nil {
return 0, err
}
mf, err := plugin.Manifest.EncryptAuthPayload()
if err != nil {
return 0, fmt.Errorf("EncryptAuthPayload failed, err=%w", err)
}
table := tx.PluginDraft
err = table.WithContext(ctx).Create(&model.PluginDraft{
ID: id,
SpaceID: plugin.SpaceID,
DeveloperID: plugin.DeveloperID,
PluginType: int32(plugin.PluginType),
IconURI: plugin.GetIconURI(),
ServerURL: plugin.GetServerURL(),
AppID: plugin.GetAPPID(),
Manifest: mf,
OpenapiDoc: plugin.OpenapiDoc,
})
if err != nil {
return 0, err
}
return id, nil
}
func (p *PluginDraftDAO) UpdateWithTX(ctx context.Context, tx *query.QueryTx, plugin *entity.PluginInfo) (err error) {
table := tx.PluginDraft
updateMap := map[string]any{}
if plugin.Manifest != nil {
mf, err := plugin.Manifest.EncryptAuthPayload()
if err != nil {
return fmt.Errorf("EncryptAuthPayload failed, err=%w", err)
}
mfBytes, err := json.Marshal(mf)
if err != nil {
return err
}
updateMap[table.Manifest.ColumnName().String()] = mfBytes
}
if plugin.OpenapiDoc != nil {
doc, err := json.Marshal(plugin.OpenapiDoc)
if err != nil {
return err
}
updateMap[table.OpenapiDoc.ColumnName().String()] = doc
}
if plugin.IconURI != nil {
updateMap[table.IconURI.ColumnName().String()] = *plugin.IconURI
}
if plugin.ServerURL != nil {
updateMap[table.ServerURL.ColumnName().String()] = *plugin.ServerURL
}
if plugin.APPID != nil {
updateMap[table.AppID.ColumnName().String()] = *plugin.APPID
}
_, err = table.WithContext(ctx).
Where(table.ID.Eq(plugin.ID)).
UpdateColumns(updateMap)
if err != nil {
return err
}
return nil
}
func (p *PluginDraftDAO) DeleteWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {
table := tx.PluginDraft
_, err = table.WithContext(ctx).
Where(table.ID.Eq(pluginID)).
Delete()
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,320 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"encoding/json"
"errors"
"fmt"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/domain/plugin/utils"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewPluginOAuthAuthDAO(db *gorm.DB, idGen idgen.IDGenerator) *PluginOAuthAuthDAO {
return &PluginOAuthAuthDAO{
idGen: idGen,
query: query.Use(db),
}
}
type pluginOAuthAuthPO model.PluginOauthAuth
func (p pluginOAuthAuthPO) ToDO() *entity.AuthorizationCodeInfo {
if p.RefreshToken != "" {
refreshToken, err := utils.DecryptByAES(p.RefreshToken, utils.OAuthTokenSecretKey)
if err == nil {
p.RefreshToken = string(refreshToken)
}
}
if p.AccessToken != "" {
accessToken, err := utils.DecryptByAES(p.AccessToken, utils.OAuthTokenSecretKey)
if err == nil {
p.AccessToken = string(accessToken)
}
}
return &entity.AuthorizationCodeInfo{
RecordID: p.ID,
Meta: &entity.AuthorizationCodeMeta{
UserID: p.UserID,
PluginID: p.PluginID,
IsDraft: p.IsDraft,
},
Config: p.OauthConfig,
AccessToken: p.AccessToken,
RefreshToken: p.RefreshToken,
TokenExpiredAtMS: p.TokenExpiredAt,
NextTokenRefreshAtMS: &p.NextTokenRefreshAt,
LastActiveAtMS: p.LastActiveAt,
}
}
type PluginOAuthAuthDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
func (p *PluginOAuthAuthDAO) Get(ctx context.Context, meta *entity.AuthorizationCodeMeta) (info *entity.AuthorizationCodeInfo, exist bool, err error) {
table := p.query.PluginOauthAuth
res, err := table.WithContext(ctx).
Where(
table.UserID.Eq(meta.UserID),
table.PluginID.Eq(meta.PluginID),
table.IsDraft.Is(meta.IsDraft),
).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
info = pluginOAuthAuthPO(*res).ToDO()
return info, true, nil
}
func (p *PluginOAuthAuthDAO) Upsert(ctx context.Context, info *entity.AuthorizationCodeInfo) (err error) {
if info.Meta == nil || info.Meta.UserID == "" || info.Meta.PluginID <= 0 {
return fmt.Errorf("meta info is required")
}
meta := info.Meta
var accessToken, refreshToken string
if info.AccessToken != "" {
accessToken, err = utils.EncryptByAES([]byte(info.AccessToken), utils.OAuthTokenSecretKey)
if err != nil {
return err
}
}
if info.RefreshToken != "" {
refreshToken, err = utils.EncryptByAES([]byte(info.RefreshToken), utils.OAuthTokenSecretKey)
if err != nil {
return err
}
}
table := p.query.PluginOauthAuth
_, err = table.WithContext(ctx).
Select(table.ID).
Where(
table.UserID.Eq(meta.UserID),
table.PluginID.Eq(meta.PluginID),
table.IsDraft.Is(meta.IsDraft),
).First()
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
id, err := p.idGen.GenID(ctx)
if err != nil {
return err
}
po := &model.PluginOauthAuth{
ID: id,
UserID: meta.UserID,
PluginID: meta.PluginID,
IsDraft: meta.IsDraft,
AccessToken: accessToken,
RefreshToken: refreshToken,
TokenExpiredAt: info.TokenExpiredAtMS,
NextTokenRefreshAt: info.GetNextTokenRefreshAtMS(),
OauthConfig: info.Config,
LastActiveAt: info.LastActiveAtMS,
}
return table.WithContext(ctx).Create(po)
}
updateMap := map[string]any{}
if accessToken != "" {
updateMap[table.AccessToken.ColumnName().String()] = accessToken
}
if refreshToken != "" {
updateMap[table.RefreshToken.ColumnName().String()] = refreshToken
}
if info.NextTokenRefreshAtMS != nil {
updateMap[table.NextTokenRefreshAt.ColumnName().String()] = *info.NextTokenRefreshAtMS
}
if info.TokenExpiredAtMS > 0 {
updateMap[table.TokenExpiredAt.ColumnName().String()] = info.TokenExpiredAtMS
}
if info.LastActiveAtMS > 0 {
updateMap[table.LastActiveAt.ColumnName().String()] = info.LastActiveAtMS
}
if info.Config != nil {
b, err := json.Marshal(info.Config)
if err != nil {
return err
}
updateMap[table.OauthConfig.ColumnName().String()] = b
}
_, err = table.WithContext(ctx).
Where(
table.UserID.Eq(meta.UserID),
table.PluginID.Eq(meta.PluginID),
table.IsDraft.Is(meta.IsDraft),
).
Updates(updateMap)
return err
}
func (p *PluginOAuthAuthDAO) UpdateLastActiveAt(ctx context.Context, meta *entity.AuthorizationCodeMeta, lastActiveAtMs int64) (err error) {
po := &model.PluginOauthAuth{
LastActiveAt: lastActiveAtMs,
}
table := p.query.PluginOauthAuth
_, err = table.WithContext(ctx).
Where(
table.UserID.Eq(meta.UserID),
table.PluginID.Eq(meta.PluginID),
table.IsDraft.Is(meta.IsDraft),
).
Updates(po)
return err
}
func (p *PluginOAuthAuthDAO) GetRefreshTokenList(ctx context.Context, nextRefreshAt int64, limit int) (infos []*entity.AuthorizationCodeInfo, err error) {
const size = 50
table := p.query.PluginOauthAuth
infos = make([]*entity.AuthorizationCodeInfo, 0, limit)
for limit > 0 {
res, err := table.WithContext(ctx).
Where(
table.NextTokenRefreshAt.Gt(0),
table.NextTokenRefreshAt.Lt(nextRefreshAt),
).
Order(table.NextTokenRefreshAt.Asc()).
Limit(size).
Find()
if err != nil {
return nil, err
}
infos = make([]*entity.AuthorizationCodeInfo, 0, len(res))
for _, v := range res {
infos = append(infos, pluginOAuthAuthPO(*v).ToDO())
}
limit -= size
if len(res) < size {
break
}
}
return infos, nil
}
func (p *PluginOAuthAuthDAO) BatchDeleteByIDs(ctx context.Context, ids []int64) (err error) {
table := p.query.PluginOauthAuth
chunks := slices.Chunks(ids, 20)
for _, chunk := range chunks {
_, err = table.WithContext(ctx).
Where(table.ID.In(chunk...)).
Delete()
if err != nil {
return err
}
}
return nil
}
func (p *PluginOAuthAuthDAO) Delete(ctx context.Context, meta *entity.AuthorizationCodeMeta) (err error) {
table := p.query.PluginOauthAuth
_, err = table.WithContext(ctx).
Where(
table.UserID.Eq(meta.UserID),
table.PluginID.Eq(meta.PluginID),
table.IsDraft.Is(meta.IsDraft),
).
Delete()
return err
}
func (p *PluginOAuthAuthDAO) DeleteExpiredTokens(ctx context.Context, expireAt int64, limit int) (err error) {
const size = 50
table := p.query.PluginOauthAuth
for limit > 0 {
res, err := table.WithContext(ctx).
Where(
table.TokenExpiredAt.Gt(0),
table.TokenExpiredAt.Lt(expireAt),
).
Limit(size).
Delete()
if err != nil {
return err
}
limit -= size
if res.RowsAffected < size {
break
}
}
return nil
}
func (p *PluginOAuthAuthDAO) DeleteInactiveTokens(ctx context.Context, lastActiveAt int64, limit int) (err error) {
const size = 50
table := p.query.PluginOauthAuth
for limit > 0 {
res, err := table.WithContext(ctx).
Where(
table.LastActiveAt.Gt(0),
table.LastActiveAt.Lt(lastActiveAt),
).
Limit(size).
Delete()
if err != nil {
return err
}
limit -= size
if res.RowsAffected < size {
break
}
}
return nil
}

View File

@@ -0,0 +1,210 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"errors"
"fmt"
"gorm.io/gen/field"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewPluginVersionDAO(db *gorm.DB, idGen idgen.IDGenerator) *PluginVersionDAO {
return &PluginVersionDAO{
idGen: idGen,
query: query.Use(db),
}
}
type PluginVersionDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type pluginVersionPO model.PluginVersion
func (p pluginVersionPO) ToDO() *entity.PluginInfo {
return entity.NewPluginInfo(&plugin.PluginInfo{
ID: p.PluginID,
SpaceID: p.SpaceID,
APPID: &p.AppID,
DeveloperID: p.DeveloperID,
PluginType: plugin_develop_common.PluginType(p.PluginType),
IconURI: &p.IconURI,
ServerURL: &p.ServerURL,
CreatedAt: p.CreatedAt,
Version: &p.Version,
VersionDesc: &p.VersionDesc,
Manifest: p.Manifest,
OpenapiDoc: p.OpenapiDoc,
})
}
func (p *PluginVersionDAO) getSelected(opt *PluginSelectedOption) (selected []field.Expr) {
if opt == nil {
return selected
}
table := p.query.PluginVersion
if opt.PluginID {
selected = append(selected, table.PluginID)
}
if opt.OpenapiDoc {
selected = append(selected, table.OpenapiDoc)
}
if opt.Version {
selected = append(selected, table.Version)
}
if opt.Manifest {
selected = append(selected, table.Manifest)
}
if opt.IconURI {
selected = append(selected, table.IconURI)
}
return selected
}
func (p *PluginVersionDAO) Get(ctx context.Context, pluginID int64, version string) (plugin *entity.PluginInfo, exist bool, err error) {
table := p.query.PluginVersion
pl, err := table.WithContext(ctx).
Where(
table.PluginID.Eq(pluginID),
table.Version.Eq(version),
).First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
plugin = pluginVersionPO(*pl).ToDO()
return plugin, true, nil
}
func (p *PluginVersionDAO) MGet(ctx context.Context, vPlugins []entity.VersionPlugin, opt *PluginSelectedOption) (plugins []*entity.PluginInfo, err error) {
plugins = make([]*entity.PluginInfo, 0, len(vPlugins))
table := p.query.PluginVersion
chunks := slices.Chunks(vPlugins, 10)
for _, chunk := range chunks {
q := table.WithContext(ctx).
Select(p.getSelected(opt)...).
Where(
table.Where(
table.PluginID.Eq(chunk[0].PluginID),
table.Version.Eq(chunk[0].Version),
),
)
for i, v := range chunk {
if i == 0 {
continue
}
q = q.Or(
table.PluginID.Eq(v.PluginID),
table.Version.Eq(v.Version),
)
}
pls, err := q.Find()
if err != nil {
return nil, err
}
for _, pl := range pls {
plugins = append(plugins, pluginVersionPO(*pl).ToDO())
}
}
return plugins, nil
}
func (p *PluginVersionDAO) ListVersions(ctx context.Context, pluginID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error) {
table := p.query.PluginVersion
offset := (pageInfo.Page - 1) * pageInfo.Size
pls, total, err := table.WithContext(ctx).
Where(table.PluginID.Eq(pluginID)).
Select(table.CreatedAt, table.Manifest, table.Version, table.VersionDesc).
Order(table.CreatedAt.Desc()).
FindByPage(offset, pageInfo.Size)
if err != nil {
return nil, 0, err
}
plugins = make([]*entity.PluginInfo, 0, len(pls))
for _, pl := range pls {
plugins = append(plugins, pluginVersionPO(*pl).ToDO())
}
return plugins, total, nil
}
func (p *PluginVersionDAO) CreateWithTX(ctx context.Context, tx *query.QueryTx, plugin *entity.PluginInfo) (err error) {
if plugin.GetVersion() == "" {
return fmt.Errorf("invalid plugin version")
}
id, err := p.idGen.GenID(ctx)
if err != nil {
return err
}
table := tx.PluginVersion
err = table.WithContext(ctx).Create(&model.PluginVersion{
ID: id,
SpaceID: plugin.SpaceID,
PluginID: plugin.ID,
DeveloperID: plugin.DeveloperID,
AppID: plugin.GetAPPID(),
PluginType: int32(plugin.PluginType),
IconURI: plugin.GetIconURI(),
ServerURL: plugin.GetServerURL(),
Version: plugin.GetVersion(),
VersionDesc: plugin.GetVersionDesc(),
Manifest: plugin.Manifest,
OpenapiDoc: plugin.OpenapiDoc,
})
if err != nil {
return err
}
return nil
}
func (p *PluginVersionDAO) DeleteWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {
table := tx.PluginVersion
_, err = table.WithContext(ctx).
Where(table.PluginID.Eq(pluginID)).
Delete()
return err
}

View File

@@ -0,0 +1,417 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newAgentToolDraft(db *gorm.DB, opts ...gen.DOOption) agentToolDraft {
_agentToolDraft := agentToolDraft{}
_agentToolDraft.agentToolDraftDo.UseDB(db, opts...)
_agentToolDraft.agentToolDraftDo.UseModel(&model.AgentToolDraft{})
tableName := _agentToolDraft.agentToolDraftDo.TableName()
_agentToolDraft.ALL = field.NewAsterisk(tableName)
_agentToolDraft.ID = field.NewInt64(tableName, "id")
_agentToolDraft.AgentID = field.NewInt64(tableName, "agent_id")
_agentToolDraft.PluginID = field.NewInt64(tableName, "plugin_id")
_agentToolDraft.ToolID = field.NewInt64(tableName, "tool_id")
_agentToolDraft.CreatedAt = field.NewInt64(tableName, "created_at")
_agentToolDraft.SubURL = field.NewString(tableName, "sub_url")
_agentToolDraft.Method = field.NewString(tableName, "method")
_agentToolDraft.ToolName = field.NewString(tableName, "tool_name")
_agentToolDraft.ToolVersion = field.NewString(tableName, "tool_version")
_agentToolDraft.Operation = field.NewField(tableName, "operation")
_agentToolDraft.fillFieldMap()
return _agentToolDraft
}
// agentToolDraft Draft Agent Tool
type agentToolDraft struct {
agentToolDraftDo
ALL field.Asterisk
ID field.Int64 // Primary Key ID
AgentID field.Int64 // Agent ID
PluginID field.Int64 // Plugin ID
ToolID field.Int64 // Tool ID
CreatedAt field.Int64 // Create Time in Milliseconds
SubURL field.String // Sub URL Path
Method field.String // HTTP Request Method
ToolName field.String // Tool Name
ToolVersion field.String // Tool Version, e.g. v1.0.0
Operation field.Field // Tool Openapi Operation Schema
fieldMap map[string]field.Expr
}
func (a agentToolDraft) Table(newTableName string) *agentToolDraft {
a.agentToolDraftDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a agentToolDraft) As(alias string) *agentToolDraft {
a.agentToolDraftDo.DO = *(a.agentToolDraftDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *agentToolDraft) updateTableName(table string) *agentToolDraft {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.AgentID = field.NewInt64(table, "agent_id")
a.PluginID = field.NewInt64(table, "plugin_id")
a.ToolID = field.NewInt64(table, "tool_id")
a.CreatedAt = field.NewInt64(table, "created_at")
a.SubURL = field.NewString(table, "sub_url")
a.Method = field.NewString(table, "method")
a.ToolName = field.NewString(table, "tool_name")
a.ToolVersion = field.NewString(table, "tool_version")
a.Operation = field.NewField(table, "operation")
a.fillFieldMap()
return a
}
func (a *agentToolDraft) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *agentToolDraft) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 10)
a.fieldMap["id"] = a.ID
a.fieldMap["agent_id"] = a.AgentID
a.fieldMap["plugin_id"] = a.PluginID
a.fieldMap["tool_id"] = a.ToolID
a.fieldMap["created_at"] = a.CreatedAt
a.fieldMap["sub_url"] = a.SubURL
a.fieldMap["method"] = a.Method
a.fieldMap["tool_name"] = a.ToolName
a.fieldMap["tool_version"] = a.ToolVersion
a.fieldMap["operation"] = a.Operation
}
func (a agentToolDraft) clone(db *gorm.DB) agentToolDraft {
a.agentToolDraftDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a agentToolDraft) replaceDB(db *gorm.DB) agentToolDraft {
a.agentToolDraftDo.ReplaceDB(db)
return a
}
type agentToolDraftDo struct{ gen.DO }
type IAgentToolDraftDo interface {
gen.SubQuery
Debug() IAgentToolDraftDo
WithContext(ctx context.Context) IAgentToolDraftDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAgentToolDraftDo
WriteDB() IAgentToolDraftDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAgentToolDraftDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAgentToolDraftDo
Not(conds ...gen.Condition) IAgentToolDraftDo
Or(conds ...gen.Condition) IAgentToolDraftDo
Select(conds ...field.Expr) IAgentToolDraftDo
Where(conds ...gen.Condition) IAgentToolDraftDo
Order(conds ...field.Expr) IAgentToolDraftDo
Distinct(cols ...field.Expr) IAgentToolDraftDo
Omit(cols ...field.Expr) IAgentToolDraftDo
Join(table schema.Tabler, on ...field.Expr) IAgentToolDraftDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAgentToolDraftDo
RightJoin(table schema.Tabler, on ...field.Expr) IAgentToolDraftDo
Group(cols ...field.Expr) IAgentToolDraftDo
Having(conds ...gen.Condition) IAgentToolDraftDo
Limit(limit int) IAgentToolDraftDo
Offset(offset int) IAgentToolDraftDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAgentToolDraftDo
Unscoped() IAgentToolDraftDo
Create(values ...*model.AgentToolDraft) error
CreateInBatches(values []*model.AgentToolDraft, batchSize int) error
Save(values ...*model.AgentToolDraft) error
First() (*model.AgentToolDraft, error)
Take() (*model.AgentToolDraft, error)
Last() (*model.AgentToolDraft, error)
Find() ([]*model.AgentToolDraft, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AgentToolDraft, err error)
FindInBatches(result *[]*model.AgentToolDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AgentToolDraft) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAgentToolDraftDo
Assign(attrs ...field.AssignExpr) IAgentToolDraftDo
Joins(fields ...field.RelationField) IAgentToolDraftDo
Preload(fields ...field.RelationField) IAgentToolDraftDo
FirstOrInit() (*model.AgentToolDraft, error)
FirstOrCreate() (*model.AgentToolDraft, error)
FindByPage(offset int, limit int) (result []*model.AgentToolDraft, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAgentToolDraftDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a agentToolDraftDo) Debug() IAgentToolDraftDo {
return a.withDO(a.DO.Debug())
}
func (a agentToolDraftDo) WithContext(ctx context.Context) IAgentToolDraftDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a agentToolDraftDo) ReadDB() IAgentToolDraftDo {
return a.Clauses(dbresolver.Read)
}
func (a agentToolDraftDo) WriteDB() IAgentToolDraftDo {
return a.Clauses(dbresolver.Write)
}
func (a agentToolDraftDo) Session(config *gorm.Session) IAgentToolDraftDo {
return a.withDO(a.DO.Session(config))
}
func (a agentToolDraftDo) Clauses(conds ...clause.Expression) IAgentToolDraftDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a agentToolDraftDo) Returning(value interface{}, columns ...string) IAgentToolDraftDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a agentToolDraftDo) Not(conds ...gen.Condition) IAgentToolDraftDo {
return a.withDO(a.DO.Not(conds...))
}
func (a agentToolDraftDo) Or(conds ...gen.Condition) IAgentToolDraftDo {
return a.withDO(a.DO.Or(conds...))
}
func (a agentToolDraftDo) Select(conds ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.Select(conds...))
}
func (a agentToolDraftDo) Where(conds ...gen.Condition) IAgentToolDraftDo {
return a.withDO(a.DO.Where(conds...))
}
func (a agentToolDraftDo) Order(conds ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.Order(conds...))
}
func (a agentToolDraftDo) Distinct(cols ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a agentToolDraftDo) Omit(cols ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a agentToolDraftDo) Join(table schema.Tabler, on ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a agentToolDraftDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a agentToolDraftDo) RightJoin(table schema.Tabler, on ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a agentToolDraftDo) Group(cols ...field.Expr) IAgentToolDraftDo {
return a.withDO(a.DO.Group(cols...))
}
func (a agentToolDraftDo) Having(conds ...gen.Condition) IAgentToolDraftDo {
return a.withDO(a.DO.Having(conds...))
}
func (a agentToolDraftDo) Limit(limit int) IAgentToolDraftDo {
return a.withDO(a.DO.Limit(limit))
}
func (a agentToolDraftDo) Offset(offset int) IAgentToolDraftDo {
return a.withDO(a.DO.Offset(offset))
}
func (a agentToolDraftDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAgentToolDraftDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a agentToolDraftDo) Unscoped() IAgentToolDraftDo {
return a.withDO(a.DO.Unscoped())
}
func (a agentToolDraftDo) Create(values ...*model.AgentToolDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a agentToolDraftDo) CreateInBatches(values []*model.AgentToolDraft, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a agentToolDraftDo) Save(values ...*model.AgentToolDraft) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a agentToolDraftDo) First() (*model.AgentToolDraft, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolDraft), nil
}
}
func (a agentToolDraftDo) Take() (*model.AgentToolDraft, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolDraft), nil
}
}
func (a agentToolDraftDo) Last() (*model.AgentToolDraft, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolDraft), nil
}
}
func (a agentToolDraftDo) Find() ([]*model.AgentToolDraft, error) {
result, err := a.DO.Find()
return result.([]*model.AgentToolDraft), err
}
func (a agentToolDraftDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AgentToolDraft, err error) {
buf := make([]*model.AgentToolDraft, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a agentToolDraftDo) FindInBatches(result *[]*model.AgentToolDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a agentToolDraftDo) Attrs(attrs ...field.AssignExpr) IAgentToolDraftDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a agentToolDraftDo) Assign(attrs ...field.AssignExpr) IAgentToolDraftDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a agentToolDraftDo) Joins(fields ...field.RelationField) IAgentToolDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a agentToolDraftDo) Preload(fields ...field.RelationField) IAgentToolDraftDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a agentToolDraftDo) FirstOrInit() (*model.AgentToolDraft, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolDraft), nil
}
}
func (a agentToolDraftDo) FirstOrCreate() (*model.AgentToolDraft, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolDraft), nil
}
}
func (a agentToolDraftDo) FindByPage(offset int, limit int) (result []*model.AgentToolDraft, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a agentToolDraftDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a agentToolDraftDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a agentToolDraftDo) Delete(models ...*model.AgentToolDraft) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *agentToolDraftDo) withDO(do gen.Dao) *agentToolDraftDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,421 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newAgentToolVersion(db *gorm.DB, opts ...gen.DOOption) agentToolVersion {
_agentToolVersion := agentToolVersion{}
_agentToolVersion.agentToolVersionDo.UseDB(db, opts...)
_agentToolVersion.agentToolVersionDo.UseModel(&model.AgentToolVersion{})
tableName := _agentToolVersion.agentToolVersionDo.TableName()
_agentToolVersion.ALL = field.NewAsterisk(tableName)
_agentToolVersion.ID = field.NewInt64(tableName, "id")
_agentToolVersion.AgentID = field.NewInt64(tableName, "agent_id")
_agentToolVersion.PluginID = field.NewInt64(tableName, "plugin_id")
_agentToolVersion.ToolID = field.NewInt64(tableName, "tool_id")
_agentToolVersion.AgentVersion = field.NewString(tableName, "agent_version")
_agentToolVersion.ToolName = field.NewString(tableName, "tool_name")
_agentToolVersion.ToolVersion = field.NewString(tableName, "tool_version")
_agentToolVersion.SubURL = field.NewString(tableName, "sub_url")
_agentToolVersion.Method = field.NewString(tableName, "method")
_agentToolVersion.Operation = field.NewField(tableName, "operation")
_agentToolVersion.CreatedAt = field.NewInt64(tableName, "created_at")
_agentToolVersion.fillFieldMap()
return _agentToolVersion
}
// agentToolVersion Agent Tool Version
type agentToolVersion struct {
agentToolVersionDo
ALL field.Asterisk
ID field.Int64 // Primary Key ID
AgentID field.Int64 // Agent ID
PluginID field.Int64 // Plugin ID
ToolID field.Int64 // Tool ID
AgentVersion field.String // Agent Tool Version
ToolName field.String // Tool Name
ToolVersion field.String // Tool Version, e.g. v1.0.0
SubURL field.String // Sub URL Path
Method field.String // HTTP Request Method
Operation field.Field // Tool Openapi Operation Schema
CreatedAt field.Int64 // Create Time in Milliseconds
fieldMap map[string]field.Expr
}
func (a agentToolVersion) Table(newTableName string) *agentToolVersion {
a.agentToolVersionDo.UseTable(newTableName)
return a.updateTableName(newTableName)
}
func (a agentToolVersion) As(alias string) *agentToolVersion {
a.agentToolVersionDo.DO = *(a.agentToolVersionDo.As(alias).(*gen.DO))
return a.updateTableName(alias)
}
func (a *agentToolVersion) updateTableName(table string) *agentToolVersion {
a.ALL = field.NewAsterisk(table)
a.ID = field.NewInt64(table, "id")
a.AgentID = field.NewInt64(table, "agent_id")
a.PluginID = field.NewInt64(table, "plugin_id")
a.ToolID = field.NewInt64(table, "tool_id")
a.AgentVersion = field.NewString(table, "agent_version")
a.ToolName = field.NewString(table, "tool_name")
a.ToolVersion = field.NewString(table, "tool_version")
a.SubURL = field.NewString(table, "sub_url")
a.Method = field.NewString(table, "method")
a.Operation = field.NewField(table, "operation")
a.CreatedAt = field.NewInt64(table, "created_at")
a.fillFieldMap()
return a
}
func (a *agentToolVersion) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := a.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (a *agentToolVersion) fillFieldMap() {
a.fieldMap = make(map[string]field.Expr, 11)
a.fieldMap["id"] = a.ID
a.fieldMap["agent_id"] = a.AgentID
a.fieldMap["plugin_id"] = a.PluginID
a.fieldMap["tool_id"] = a.ToolID
a.fieldMap["agent_version"] = a.AgentVersion
a.fieldMap["tool_name"] = a.ToolName
a.fieldMap["tool_version"] = a.ToolVersion
a.fieldMap["sub_url"] = a.SubURL
a.fieldMap["method"] = a.Method
a.fieldMap["operation"] = a.Operation
a.fieldMap["created_at"] = a.CreatedAt
}
func (a agentToolVersion) clone(db *gorm.DB) agentToolVersion {
a.agentToolVersionDo.ReplaceConnPool(db.Statement.ConnPool)
return a
}
func (a agentToolVersion) replaceDB(db *gorm.DB) agentToolVersion {
a.agentToolVersionDo.ReplaceDB(db)
return a
}
type agentToolVersionDo struct{ gen.DO }
type IAgentToolVersionDo interface {
gen.SubQuery
Debug() IAgentToolVersionDo
WithContext(ctx context.Context) IAgentToolVersionDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IAgentToolVersionDo
WriteDB() IAgentToolVersionDo
As(alias string) gen.Dao
Session(config *gorm.Session) IAgentToolVersionDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IAgentToolVersionDo
Not(conds ...gen.Condition) IAgentToolVersionDo
Or(conds ...gen.Condition) IAgentToolVersionDo
Select(conds ...field.Expr) IAgentToolVersionDo
Where(conds ...gen.Condition) IAgentToolVersionDo
Order(conds ...field.Expr) IAgentToolVersionDo
Distinct(cols ...field.Expr) IAgentToolVersionDo
Omit(cols ...field.Expr) IAgentToolVersionDo
Join(table schema.Tabler, on ...field.Expr) IAgentToolVersionDo
LeftJoin(table schema.Tabler, on ...field.Expr) IAgentToolVersionDo
RightJoin(table schema.Tabler, on ...field.Expr) IAgentToolVersionDo
Group(cols ...field.Expr) IAgentToolVersionDo
Having(conds ...gen.Condition) IAgentToolVersionDo
Limit(limit int) IAgentToolVersionDo
Offset(offset int) IAgentToolVersionDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IAgentToolVersionDo
Unscoped() IAgentToolVersionDo
Create(values ...*model.AgentToolVersion) error
CreateInBatches(values []*model.AgentToolVersion, batchSize int) error
Save(values ...*model.AgentToolVersion) error
First() (*model.AgentToolVersion, error)
Take() (*model.AgentToolVersion, error)
Last() (*model.AgentToolVersion, error)
Find() ([]*model.AgentToolVersion, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AgentToolVersion, err error)
FindInBatches(result *[]*model.AgentToolVersion, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.AgentToolVersion) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IAgentToolVersionDo
Assign(attrs ...field.AssignExpr) IAgentToolVersionDo
Joins(fields ...field.RelationField) IAgentToolVersionDo
Preload(fields ...field.RelationField) IAgentToolVersionDo
FirstOrInit() (*model.AgentToolVersion, error)
FirstOrCreate() (*model.AgentToolVersion, error)
FindByPage(offset int, limit int) (result []*model.AgentToolVersion, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IAgentToolVersionDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (a agentToolVersionDo) Debug() IAgentToolVersionDo {
return a.withDO(a.DO.Debug())
}
func (a agentToolVersionDo) WithContext(ctx context.Context) IAgentToolVersionDo {
return a.withDO(a.DO.WithContext(ctx))
}
func (a agentToolVersionDo) ReadDB() IAgentToolVersionDo {
return a.Clauses(dbresolver.Read)
}
func (a agentToolVersionDo) WriteDB() IAgentToolVersionDo {
return a.Clauses(dbresolver.Write)
}
func (a agentToolVersionDo) Session(config *gorm.Session) IAgentToolVersionDo {
return a.withDO(a.DO.Session(config))
}
func (a agentToolVersionDo) Clauses(conds ...clause.Expression) IAgentToolVersionDo {
return a.withDO(a.DO.Clauses(conds...))
}
func (a agentToolVersionDo) Returning(value interface{}, columns ...string) IAgentToolVersionDo {
return a.withDO(a.DO.Returning(value, columns...))
}
func (a agentToolVersionDo) Not(conds ...gen.Condition) IAgentToolVersionDo {
return a.withDO(a.DO.Not(conds...))
}
func (a agentToolVersionDo) Or(conds ...gen.Condition) IAgentToolVersionDo {
return a.withDO(a.DO.Or(conds...))
}
func (a agentToolVersionDo) Select(conds ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.Select(conds...))
}
func (a agentToolVersionDo) Where(conds ...gen.Condition) IAgentToolVersionDo {
return a.withDO(a.DO.Where(conds...))
}
func (a agentToolVersionDo) Order(conds ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.Order(conds...))
}
func (a agentToolVersionDo) Distinct(cols ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.Distinct(cols...))
}
func (a agentToolVersionDo) Omit(cols ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.Omit(cols...))
}
func (a agentToolVersionDo) Join(table schema.Tabler, on ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.Join(table, on...))
}
func (a agentToolVersionDo) LeftJoin(table schema.Tabler, on ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.LeftJoin(table, on...))
}
func (a agentToolVersionDo) RightJoin(table schema.Tabler, on ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.RightJoin(table, on...))
}
func (a agentToolVersionDo) Group(cols ...field.Expr) IAgentToolVersionDo {
return a.withDO(a.DO.Group(cols...))
}
func (a agentToolVersionDo) Having(conds ...gen.Condition) IAgentToolVersionDo {
return a.withDO(a.DO.Having(conds...))
}
func (a agentToolVersionDo) Limit(limit int) IAgentToolVersionDo {
return a.withDO(a.DO.Limit(limit))
}
func (a agentToolVersionDo) Offset(offset int) IAgentToolVersionDo {
return a.withDO(a.DO.Offset(offset))
}
func (a agentToolVersionDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IAgentToolVersionDo {
return a.withDO(a.DO.Scopes(funcs...))
}
func (a agentToolVersionDo) Unscoped() IAgentToolVersionDo {
return a.withDO(a.DO.Unscoped())
}
func (a agentToolVersionDo) Create(values ...*model.AgentToolVersion) error {
if len(values) == 0 {
return nil
}
return a.DO.Create(values)
}
func (a agentToolVersionDo) CreateInBatches(values []*model.AgentToolVersion, batchSize int) error {
return a.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (a agentToolVersionDo) Save(values ...*model.AgentToolVersion) error {
if len(values) == 0 {
return nil
}
return a.DO.Save(values)
}
func (a agentToolVersionDo) First() (*model.AgentToolVersion, error) {
if result, err := a.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolVersion), nil
}
}
func (a agentToolVersionDo) Take() (*model.AgentToolVersion, error) {
if result, err := a.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolVersion), nil
}
}
func (a agentToolVersionDo) Last() (*model.AgentToolVersion, error) {
if result, err := a.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolVersion), nil
}
}
func (a agentToolVersionDo) Find() ([]*model.AgentToolVersion, error) {
result, err := a.DO.Find()
return result.([]*model.AgentToolVersion), err
}
func (a agentToolVersionDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.AgentToolVersion, err error) {
buf := make([]*model.AgentToolVersion, 0, batchSize)
err = a.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (a agentToolVersionDo) FindInBatches(result *[]*model.AgentToolVersion, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return a.DO.FindInBatches(result, batchSize, fc)
}
func (a agentToolVersionDo) Attrs(attrs ...field.AssignExpr) IAgentToolVersionDo {
return a.withDO(a.DO.Attrs(attrs...))
}
func (a agentToolVersionDo) Assign(attrs ...field.AssignExpr) IAgentToolVersionDo {
return a.withDO(a.DO.Assign(attrs...))
}
func (a agentToolVersionDo) Joins(fields ...field.RelationField) IAgentToolVersionDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Joins(_f))
}
return &a
}
func (a agentToolVersionDo) Preload(fields ...field.RelationField) IAgentToolVersionDo {
for _, _f := range fields {
a = *a.withDO(a.DO.Preload(_f))
}
return &a
}
func (a agentToolVersionDo) FirstOrInit() (*model.AgentToolVersion, error) {
if result, err := a.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolVersion), nil
}
}
func (a agentToolVersionDo) FirstOrCreate() (*model.AgentToolVersion, error) {
if result, err := a.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.AgentToolVersion), nil
}
}
func (a agentToolVersionDo) FindByPage(offset int, limit int) (result []*model.AgentToolVersion, count int64, err error) {
result, err = a.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = a.Offset(-1).Limit(-1).Count()
return
}
func (a agentToolVersionDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = a.Count()
if err != nil {
return
}
err = a.Offset(offset).Limit(limit).Scan(result)
return
}
func (a agentToolVersionDo) Scan(result interface{}) (err error) {
return a.DO.Scan(result)
}
func (a agentToolVersionDo) Delete(models ...*model.AgentToolVersion) (result gen.ResultInfo, err error) {
return a.DO.Delete(models)
}
func (a *agentToolVersionDo) withDO(do gen.Dao) *agentToolVersionDo {
a.DO = *do.(*gen.DO)
return a
}

View File

@@ -0,0 +1,167 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"database/sql"
"gorm.io/gorm"
"gorm.io/gen"
"gorm.io/plugin/dbresolver"
)
var (
Q = new(Query)
AgentToolDraft *agentToolDraft
AgentToolVersion *agentToolVersion
Plugin *plugin
PluginDraft *pluginDraft
PluginOauthAuth *pluginOauthAuth
PluginVersion *pluginVersion
Tool *tool
ToolDraft *toolDraft
ToolVersion *toolVersion
)
func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
*Q = *Use(db, opts...)
AgentToolDraft = &Q.AgentToolDraft
AgentToolVersion = &Q.AgentToolVersion
Plugin = &Q.Plugin
PluginDraft = &Q.PluginDraft
PluginOauthAuth = &Q.PluginOauthAuth
PluginVersion = &Q.PluginVersion
Tool = &Q.Tool
ToolDraft = &Q.ToolDraft
ToolVersion = &Q.ToolVersion
}
func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{
db: db,
AgentToolDraft: newAgentToolDraft(db, opts...),
AgentToolVersion: newAgentToolVersion(db, opts...),
Plugin: newPlugin(db, opts...),
PluginDraft: newPluginDraft(db, opts...),
PluginOauthAuth: newPluginOauthAuth(db, opts...),
PluginVersion: newPluginVersion(db, opts...),
Tool: newTool(db, opts...),
ToolDraft: newToolDraft(db, opts...),
ToolVersion: newToolVersion(db, opts...),
}
}
type Query struct {
db *gorm.DB
AgentToolDraft agentToolDraft
AgentToolVersion agentToolVersion
Plugin plugin
PluginDraft pluginDraft
PluginOauthAuth pluginOauthAuth
PluginVersion pluginVersion
Tool tool
ToolDraft toolDraft
ToolVersion toolVersion
}
func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query {
return &Query{
db: db,
AgentToolDraft: q.AgentToolDraft.clone(db),
AgentToolVersion: q.AgentToolVersion.clone(db),
Plugin: q.Plugin.clone(db),
PluginDraft: q.PluginDraft.clone(db),
PluginOauthAuth: q.PluginOauthAuth.clone(db),
PluginVersion: q.PluginVersion.clone(db),
Tool: q.Tool.clone(db),
ToolDraft: q.ToolDraft.clone(db),
ToolVersion: q.ToolVersion.clone(db),
}
}
func (q *Query) ReadDB() *Query {
return q.ReplaceDB(q.db.Clauses(dbresolver.Read))
}
func (q *Query) WriteDB() *Query {
return q.ReplaceDB(q.db.Clauses(dbresolver.Write))
}
func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{
db: db,
AgentToolDraft: q.AgentToolDraft.replaceDB(db),
AgentToolVersion: q.AgentToolVersion.replaceDB(db),
Plugin: q.Plugin.replaceDB(db),
PluginDraft: q.PluginDraft.replaceDB(db),
PluginOauthAuth: q.PluginOauthAuth.replaceDB(db),
PluginVersion: q.PluginVersion.replaceDB(db),
Tool: q.Tool.replaceDB(db),
ToolDraft: q.ToolDraft.replaceDB(db),
ToolVersion: q.ToolVersion.replaceDB(db),
}
}
type queryCtx struct {
AgentToolDraft IAgentToolDraftDo
AgentToolVersion IAgentToolVersionDo
Plugin IPluginDo
PluginDraft IPluginDraftDo
PluginOauthAuth IPluginOauthAuthDo
PluginVersion IPluginVersionDo
Tool IToolDo
ToolDraft IToolDraftDo
ToolVersion IToolVersionDo
}
func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{
AgentToolDraft: q.AgentToolDraft.WithContext(ctx),
AgentToolVersion: q.AgentToolVersion.WithContext(ctx),
Plugin: q.Plugin.WithContext(ctx),
PluginDraft: q.PluginDraft.WithContext(ctx),
PluginOauthAuth: q.PluginOauthAuth.WithContext(ctx),
PluginVersion: q.PluginVersion.WithContext(ctx),
Tool: q.Tool.WithContext(ctx),
ToolDraft: q.ToolDraft.WithContext(ctx),
ToolVersion: q.ToolVersion.WithContext(ctx),
}
}
func (q *Query) Transaction(fc func(tx *Query) error, opts ...*sql.TxOptions) error {
return q.db.Transaction(func(tx *gorm.DB) error { return fc(q.clone(tx)) }, opts...)
}
func (q *Query) Begin(opts ...*sql.TxOptions) *QueryTx {
tx := q.db.Begin(opts...)
return &QueryTx{Query: q.clone(tx), Error: tx.Error}
}
type QueryTx struct {
*Query
Error error
}
func (q *QueryTx) Commit() error {
return q.db.Commit().Error
}
func (q *QueryTx) Rollback() error {
return q.db.Rollback().Error
}
func (q *QueryTx) SavePoint(name string) error {
return q.db.SavePoint(name).Error
}
func (q *QueryTx) RollbackTo(name string) error {
return q.db.RollbackTo(name).Error
}

View File

@@ -0,0 +1,429 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newPlugin(db *gorm.DB, opts ...gen.DOOption) plugin {
_plugin := plugin{}
_plugin.pluginDo.UseDB(db, opts...)
_plugin.pluginDo.UseModel(&model.Plugin{})
tableName := _plugin.pluginDo.TableName()
_plugin.ALL = field.NewAsterisk(tableName)
_plugin.ID = field.NewInt64(tableName, "id")
_plugin.SpaceID = field.NewInt64(tableName, "space_id")
_plugin.DeveloperID = field.NewInt64(tableName, "developer_id")
_plugin.AppID = field.NewInt64(tableName, "app_id")
_plugin.IconURI = field.NewString(tableName, "icon_uri")
_plugin.ServerURL = field.NewString(tableName, "server_url")
_plugin.PluginType = field.NewInt32(tableName, "plugin_type")
_plugin.CreatedAt = field.NewInt64(tableName, "created_at")
_plugin.UpdatedAt = field.NewInt64(tableName, "updated_at")
_plugin.Version = field.NewString(tableName, "version")
_plugin.VersionDesc = field.NewString(tableName, "version_desc")
_plugin.Manifest = field.NewField(tableName, "manifest")
_plugin.OpenapiDoc = field.NewField(tableName, "openapi_doc")
_plugin.fillFieldMap()
return _plugin
}
// plugin Latest Plugin
type plugin struct {
pluginDo
ALL field.Asterisk
ID field.Int64 // Plugin ID
SpaceID field.Int64 // Space ID
DeveloperID field.Int64 // Developer ID
AppID field.Int64 // Application ID
IconURI field.String // Icon URI
ServerURL field.String // Server URL
PluginType field.Int32 // Plugin Type, 1:http, 6:local
CreatedAt field.Int64 // Create Time in Milliseconds
UpdatedAt field.Int64 // Update Time in Milliseconds
Version field.String // Plugin Version, e.g. v1.0.0
VersionDesc field.String // Plugin Version Description
Manifest field.Field // Plugin Manifest
OpenapiDoc field.Field // OpenAPI Document, only stores the root
fieldMap map[string]field.Expr
}
func (p plugin) Table(newTableName string) *plugin {
p.pluginDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p plugin) As(alias string) *plugin {
p.pluginDo.DO = *(p.pluginDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *plugin) updateTableName(table string) *plugin {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt64(table, "id")
p.SpaceID = field.NewInt64(table, "space_id")
p.DeveloperID = field.NewInt64(table, "developer_id")
p.AppID = field.NewInt64(table, "app_id")
p.IconURI = field.NewString(table, "icon_uri")
p.ServerURL = field.NewString(table, "server_url")
p.PluginType = field.NewInt32(table, "plugin_type")
p.CreatedAt = field.NewInt64(table, "created_at")
p.UpdatedAt = field.NewInt64(table, "updated_at")
p.Version = field.NewString(table, "version")
p.VersionDesc = field.NewString(table, "version_desc")
p.Manifest = field.NewField(table, "manifest")
p.OpenapiDoc = field.NewField(table, "openapi_doc")
p.fillFieldMap()
return p
}
func (p *plugin) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *plugin) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 13)
p.fieldMap["id"] = p.ID
p.fieldMap["space_id"] = p.SpaceID
p.fieldMap["developer_id"] = p.DeveloperID
p.fieldMap["app_id"] = p.AppID
p.fieldMap["icon_uri"] = p.IconURI
p.fieldMap["server_url"] = p.ServerURL
p.fieldMap["plugin_type"] = p.PluginType
p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["updated_at"] = p.UpdatedAt
p.fieldMap["version"] = p.Version
p.fieldMap["version_desc"] = p.VersionDesc
p.fieldMap["manifest"] = p.Manifest
p.fieldMap["openapi_doc"] = p.OpenapiDoc
}
func (p plugin) clone(db *gorm.DB) plugin {
p.pluginDo.ReplaceConnPool(db.Statement.ConnPool)
return p
}
func (p plugin) replaceDB(db *gorm.DB) plugin {
p.pluginDo.ReplaceDB(db)
return p
}
type pluginDo struct{ gen.DO }
type IPluginDo interface {
gen.SubQuery
Debug() IPluginDo
WithContext(ctx context.Context) IPluginDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IPluginDo
WriteDB() IPluginDo
As(alias string) gen.Dao
Session(config *gorm.Session) IPluginDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IPluginDo
Not(conds ...gen.Condition) IPluginDo
Or(conds ...gen.Condition) IPluginDo
Select(conds ...field.Expr) IPluginDo
Where(conds ...gen.Condition) IPluginDo
Order(conds ...field.Expr) IPluginDo
Distinct(cols ...field.Expr) IPluginDo
Omit(cols ...field.Expr) IPluginDo
Join(table schema.Tabler, on ...field.Expr) IPluginDo
LeftJoin(table schema.Tabler, on ...field.Expr) IPluginDo
RightJoin(table schema.Tabler, on ...field.Expr) IPluginDo
Group(cols ...field.Expr) IPluginDo
Having(conds ...gen.Condition) IPluginDo
Limit(limit int) IPluginDo
Offset(offset int) IPluginDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginDo
Unscoped() IPluginDo
Create(values ...*model.Plugin) error
CreateInBatches(values []*model.Plugin, batchSize int) error
Save(values ...*model.Plugin) error
First() (*model.Plugin, error)
Take() (*model.Plugin, error)
Last() (*model.Plugin, error)
Find() ([]*model.Plugin, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Plugin, err error)
FindInBatches(result *[]*model.Plugin, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.Plugin) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IPluginDo
Assign(attrs ...field.AssignExpr) IPluginDo
Joins(fields ...field.RelationField) IPluginDo
Preload(fields ...field.RelationField) IPluginDo
FirstOrInit() (*model.Plugin, error)
FirstOrCreate() (*model.Plugin, error)
FindByPage(offset int, limit int) (result []*model.Plugin, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IPluginDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (p pluginDo) Debug() IPluginDo {
return p.withDO(p.DO.Debug())
}
func (p pluginDo) WithContext(ctx context.Context) IPluginDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p pluginDo) ReadDB() IPluginDo {
return p.Clauses(dbresolver.Read)
}
func (p pluginDo) WriteDB() IPluginDo {
return p.Clauses(dbresolver.Write)
}
func (p pluginDo) Session(config *gorm.Session) IPluginDo {
return p.withDO(p.DO.Session(config))
}
func (p pluginDo) Clauses(conds ...clause.Expression) IPluginDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p pluginDo) Returning(value interface{}, columns ...string) IPluginDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p pluginDo) Not(conds ...gen.Condition) IPluginDo {
return p.withDO(p.DO.Not(conds...))
}
func (p pluginDo) Or(conds ...gen.Condition) IPluginDo {
return p.withDO(p.DO.Or(conds...))
}
func (p pluginDo) Select(conds ...field.Expr) IPluginDo {
return p.withDO(p.DO.Select(conds...))
}
func (p pluginDo) Where(conds ...gen.Condition) IPluginDo {
return p.withDO(p.DO.Where(conds...))
}
func (p pluginDo) Order(conds ...field.Expr) IPluginDo {
return p.withDO(p.DO.Order(conds...))
}
func (p pluginDo) Distinct(cols ...field.Expr) IPluginDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p pluginDo) Omit(cols ...field.Expr) IPluginDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p pluginDo) Join(table schema.Tabler, on ...field.Expr) IPluginDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p pluginDo) LeftJoin(table schema.Tabler, on ...field.Expr) IPluginDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p pluginDo) RightJoin(table schema.Tabler, on ...field.Expr) IPluginDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p pluginDo) Group(cols ...field.Expr) IPluginDo {
return p.withDO(p.DO.Group(cols...))
}
func (p pluginDo) Having(conds ...gen.Condition) IPluginDo {
return p.withDO(p.DO.Having(conds...))
}
func (p pluginDo) Limit(limit int) IPluginDo {
return p.withDO(p.DO.Limit(limit))
}
func (p pluginDo) Offset(offset int) IPluginDo {
return p.withDO(p.DO.Offset(offset))
}
func (p pluginDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p pluginDo) Unscoped() IPluginDo {
return p.withDO(p.DO.Unscoped())
}
func (p pluginDo) Create(values ...*model.Plugin) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p pluginDo) CreateInBatches(values []*model.Plugin, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p pluginDo) Save(values ...*model.Plugin) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p pluginDo) First() (*model.Plugin, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.Plugin), nil
}
}
func (p pluginDo) Take() (*model.Plugin, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.Plugin), nil
}
}
func (p pluginDo) Last() (*model.Plugin, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.Plugin), nil
}
}
func (p pluginDo) Find() ([]*model.Plugin, error) {
result, err := p.DO.Find()
return result.([]*model.Plugin), err
}
func (p pluginDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Plugin, err error) {
buf := make([]*model.Plugin, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p pluginDo) FindInBatches(result *[]*model.Plugin, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p pluginDo) Attrs(attrs ...field.AssignExpr) IPluginDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p pluginDo) Assign(attrs ...field.AssignExpr) IPluginDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p pluginDo) Joins(fields ...field.RelationField) IPluginDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p pluginDo) Preload(fields ...field.RelationField) IPluginDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p pluginDo) FirstOrInit() (*model.Plugin, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.Plugin), nil
}
}
func (p pluginDo) FirstOrCreate() (*model.Plugin, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.Plugin), nil
}
}
func (p pluginDo) FindByPage(offset int, limit int) (result []*model.Plugin, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p pluginDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p pluginDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p pluginDo) Delete(models ...*model.Plugin) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *pluginDo) withDO(do gen.Dao) *pluginDo {
p.DO = *do.(*gen.DO)
return p
}

View File

@@ -0,0 +1,425 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newPluginDraft(db *gorm.DB, opts ...gen.DOOption) pluginDraft {
_pluginDraft := pluginDraft{}
_pluginDraft.pluginDraftDo.UseDB(db, opts...)
_pluginDraft.pluginDraftDo.UseModel(&model.PluginDraft{})
tableName := _pluginDraft.pluginDraftDo.TableName()
_pluginDraft.ALL = field.NewAsterisk(tableName)
_pluginDraft.ID = field.NewInt64(tableName, "id")
_pluginDraft.SpaceID = field.NewInt64(tableName, "space_id")
_pluginDraft.DeveloperID = field.NewInt64(tableName, "developer_id")
_pluginDraft.AppID = field.NewInt64(tableName, "app_id")
_pluginDraft.IconURI = field.NewString(tableName, "icon_uri")
_pluginDraft.ServerURL = field.NewString(tableName, "server_url")
_pluginDraft.PluginType = field.NewInt32(tableName, "plugin_type")
_pluginDraft.CreatedAt = field.NewInt64(tableName, "created_at")
_pluginDraft.UpdatedAt = field.NewInt64(tableName, "updated_at")
_pluginDraft.DeletedAt = field.NewField(tableName, "deleted_at")
_pluginDraft.Manifest = field.NewField(tableName, "manifest")
_pluginDraft.OpenapiDoc = field.NewField(tableName, "openapi_doc")
_pluginDraft.fillFieldMap()
return _pluginDraft
}
// pluginDraft Draft Plugin
type pluginDraft struct {
pluginDraftDo
ALL field.Asterisk
ID field.Int64 // Plugin ID
SpaceID field.Int64 // Space ID
DeveloperID field.Int64 // Developer ID
AppID field.Int64 // Application ID
IconURI field.String // Icon URI
ServerURL field.String // Server URL
PluginType field.Int32 // Plugin Type, 1:http, 6:local
CreatedAt field.Int64 // Create Time in Milliseconds
UpdatedAt field.Int64 // Update Time in Milliseconds
DeletedAt field.Field // Delete Time
Manifest field.Field // Plugin Manifest
OpenapiDoc field.Field // OpenAPI Document, only stores the root
fieldMap map[string]field.Expr
}
func (p pluginDraft) Table(newTableName string) *pluginDraft {
p.pluginDraftDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p pluginDraft) As(alias string) *pluginDraft {
p.pluginDraftDo.DO = *(p.pluginDraftDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *pluginDraft) updateTableName(table string) *pluginDraft {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt64(table, "id")
p.SpaceID = field.NewInt64(table, "space_id")
p.DeveloperID = field.NewInt64(table, "developer_id")
p.AppID = field.NewInt64(table, "app_id")
p.IconURI = field.NewString(table, "icon_uri")
p.ServerURL = field.NewString(table, "server_url")
p.PluginType = field.NewInt32(table, "plugin_type")
p.CreatedAt = field.NewInt64(table, "created_at")
p.UpdatedAt = field.NewInt64(table, "updated_at")
p.DeletedAt = field.NewField(table, "deleted_at")
p.Manifest = field.NewField(table, "manifest")
p.OpenapiDoc = field.NewField(table, "openapi_doc")
p.fillFieldMap()
return p
}
func (p *pluginDraft) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *pluginDraft) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 12)
p.fieldMap["id"] = p.ID
p.fieldMap["space_id"] = p.SpaceID
p.fieldMap["developer_id"] = p.DeveloperID
p.fieldMap["app_id"] = p.AppID
p.fieldMap["icon_uri"] = p.IconURI
p.fieldMap["server_url"] = p.ServerURL
p.fieldMap["plugin_type"] = p.PluginType
p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["updated_at"] = p.UpdatedAt
p.fieldMap["deleted_at"] = p.DeletedAt
p.fieldMap["manifest"] = p.Manifest
p.fieldMap["openapi_doc"] = p.OpenapiDoc
}
func (p pluginDraft) clone(db *gorm.DB) pluginDraft {
p.pluginDraftDo.ReplaceConnPool(db.Statement.ConnPool)
return p
}
func (p pluginDraft) replaceDB(db *gorm.DB) pluginDraft {
p.pluginDraftDo.ReplaceDB(db)
return p
}
type pluginDraftDo struct{ gen.DO }
type IPluginDraftDo interface {
gen.SubQuery
Debug() IPluginDraftDo
WithContext(ctx context.Context) IPluginDraftDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IPluginDraftDo
WriteDB() IPluginDraftDo
As(alias string) gen.Dao
Session(config *gorm.Session) IPluginDraftDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IPluginDraftDo
Not(conds ...gen.Condition) IPluginDraftDo
Or(conds ...gen.Condition) IPluginDraftDo
Select(conds ...field.Expr) IPluginDraftDo
Where(conds ...gen.Condition) IPluginDraftDo
Order(conds ...field.Expr) IPluginDraftDo
Distinct(cols ...field.Expr) IPluginDraftDo
Omit(cols ...field.Expr) IPluginDraftDo
Join(table schema.Tabler, on ...field.Expr) IPluginDraftDo
LeftJoin(table schema.Tabler, on ...field.Expr) IPluginDraftDo
RightJoin(table schema.Tabler, on ...field.Expr) IPluginDraftDo
Group(cols ...field.Expr) IPluginDraftDo
Having(conds ...gen.Condition) IPluginDraftDo
Limit(limit int) IPluginDraftDo
Offset(offset int) IPluginDraftDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginDraftDo
Unscoped() IPluginDraftDo
Create(values ...*model.PluginDraft) error
CreateInBatches(values []*model.PluginDraft, batchSize int) error
Save(values ...*model.PluginDraft) error
First() (*model.PluginDraft, error)
Take() (*model.PluginDraft, error)
Last() (*model.PluginDraft, error)
Find() ([]*model.PluginDraft, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PluginDraft, err error)
FindInBatches(result *[]*model.PluginDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.PluginDraft) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IPluginDraftDo
Assign(attrs ...field.AssignExpr) IPluginDraftDo
Joins(fields ...field.RelationField) IPluginDraftDo
Preload(fields ...field.RelationField) IPluginDraftDo
FirstOrInit() (*model.PluginDraft, error)
FirstOrCreate() (*model.PluginDraft, error)
FindByPage(offset int, limit int) (result []*model.PluginDraft, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IPluginDraftDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (p pluginDraftDo) Debug() IPluginDraftDo {
return p.withDO(p.DO.Debug())
}
func (p pluginDraftDo) WithContext(ctx context.Context) IPluginDraftDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p pluginDraftDo) ReadDB() IPluginDraftDo {
return p.Clauses(dbresolver.Read)
}
func (p pluginDraftDo) WriteDB() IPluginDraftDo {
return p.Clauses(dbresolver.Write)
}
func (p pluginDraftDo) Session(config *gorm.Session) IPluginDraftDo {
return p.withDO(p.DO.Session(config))
}
func (p pluginDraftDo) Clauses(conds ...clause.Expression) IPluginDraftDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p pluginDraftDo) Returning(value interface{}, columns ...string) IPluginDraftDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p pluginDraftDo) Not(conds ...gen.Condition) IPluginDraftDo {
return p.withDO(p.DO.Not(conds...))
}
func (p pluginDraftDo) Or(conds ...gen.Condition) IPluginDraftDo {
return p.withDO(p.DO.Or(conds...))
}
func (p pluginDraftDo) Select(conds ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.Select(conds...))
}
func (p pluginDraftDo) Where(conds ...gen.Condition) IPluginDraftDo {
return p.withDO(p.DO.Where(conds...))
}
func (p pluginDraftDo) Order(conds ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.Order(conds...))
}
func (p pluginDraftDo) Distinct(cols ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p pluginDraftDo) Omit(cols ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p pluginDraftDo) Join(table schema.Tabler, on ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p pluginDraftDo) LeftJoin(table schema.Tabler, on ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p pluginDraftDo) RightJoin(table schema.Tabler, on ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p pluginDraftDo) Group(cols ...field.Expr) IPluginDraftDo {
return p.withDO(p.DO.Group(cols...))
}
func (p pluginDraftDo) Having(conds ...gen.Condition) IPluginDraftDo {
return p.withDO(p.DO.Having(conds...))
}
func (p pluginDraftDo) Limit(limit int) IPluginDraftDo {
return p.withDO(p.DO.Limit(limit))
}
func (p pluginDraftDo) Offset(offset int) IPluginDraftDo {
return p.withDO(p.DO.Offset(offset))
}
func (p pluginDraftDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginDraftDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p pluginDraftDo) Unscoped() IPluginDraftDo {
return p.withDO(p.DO.Unscoped())
}
func (p pluginDraftDo) Create(values ...*model.PluginDraft) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p pluginDraftDo) CreateInBatches(values []*model.PluginDraft, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p pluginDraftDo) Save(values ...*model.PluginDraft) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p pluginDraftDo) First() (*model.PluginDraft, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.PluginDraft), nil
}
}
func (p pluginDraftDo) Take() (*model.PluginDraft, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.PluginDraft), nil
}
}
func (p pluginDraftDo) Last() (*model.PluginDraft, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.PluginDraft), nil
}
}
func (p pluginDraftDo) Find() ([]*model.PluginDraft, error) {
result, err := p.DO.Find()
return result.([]*model.PluginDraft), err
}
func (p pluginDraftDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PluginDraft, err error) {
buf := make([]*model.PluginDraft, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p pluginDraftDo) FindInBatches(result *[]*model.PluginDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p pluginDraftDo) Attrs(attrs ...field.AssignExpr) IPluginDraftDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p pluginDraftDo) Assign(attrs ...field.AssignExpr) IPluginDraftDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p pluginDraftDo) Joins(fields ...field.RelationField) IPluginDraftDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p pluginDraftDo) Preload(fields ...field.RelationField) IPluginDraftDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p pluginDraftDo) FirstOrInit() (*model.PluginDraft, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.PluginDraft), nil
}
}
func (p pluginDraftDo) FirstOrCreate() (*model.PluginDraft, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.PluginDraft), nil
}
}
func (p pluginDraftDo) FindByPage(offset int, limit int) (result []*model.PluginDraft, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p pluginDraftDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p pluginDraftDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p pluginDraftDo) Delete(models ...*model.PluginDraft) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *pluginDraftDo) withDO(do gen.Dao) *pluginDraftDo {
p.DO = *do.(*gen.DO)
return p
}

View File

@@ -0,0 +1,425 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newPluginOauthAuth(db *gorm.DB, opts ...gen.DOOption) pluginOauthAuth {
_pluginOauthAuth := pluginOauthAuth{}
_pluginOauthAuth.pluginOauthAuthDo.UseDB(db, opts...)
_pluginOauthAuth.pluginOauthAuthDo.UseModel(&model.PluginOauthAuth{})
tableName := _pluginOauthAuth.pluginOauthAuthDo.TableName()
_pluginOauthAuth.ALL = field.NewAsterisk(tableName)
_pluginOauthAuth.ID = field.NewInt64(tableName, "id")
_pluginOauthAuth.UserID = field.NewString(tableName, "user_id")
_pluginOauthAuth.PluginID = field.NewInt64(tableName, "plugin_id")
_pluginOauthAuth.IsDraft = field.NewBool(tableName, "is_draft")
_pluginOauthAuth.OauthConfig = field.NewField(tableName, "oauth_config")
_pluginOauthAuth.AccessToken = field.NewString(tableName, "access_token")
_pluginOauthAuth.RefreshToken = field.NewString(tableName, "refresh_token")
_pluginOauthAuth.TokenExpiredAt = field.NewInt64(tableName, "token_expired_at")
_pluginOauthAuth.NextTokenRefreshAt = field.NewInt64(tableName, "next_token_refresh_at")
_pluginOauthAuth.LastActiveAt = field.NewInt64(tableName, "last_active_at")
_pluginOauthAuth.CreatedAt = field.NewInt64(tableName, "created_at")
_pluginOauthAuth.UpdatedAt = field.NewInt64(tableName, "updated_at")
_pluginOauthAuth.fillFieldMap()
return _pluginOauthAuth
}
// pluginOauthAuth Plugin OAuth Authorization Code Info
type pluginOauthAuth struct {
pluginOauthAuthDo
ALL field.Asterisk
ID field.Int64 // Primary Key
UserID field.String // User ID
PluginID field.Int64 // Plugin ID
IsDraft field.Bool // Is Draft Plugin
OauthConfig field.Field // Authorization Code OAuth Config
AccessToken field.String // Access Token
RefreshToken field.String // Refresh Token
TokenExpiredAt field.Int64 // Token Expired in Milliseconds
NextTokenRefreshAt field.Int64 // Next Token Refresh Time in Milliseconds
LastActiveAt field.Int64 // Last active time in Milliseconds
CreatedAt field.Int64 // Create Time in Milliseconds
UpdatedAt field.Int64 // Update Time in Milliseconds
fieldMap map[string]field.Expr
}
func (p pluginOauthAuth) Table(newTableName string) *pluginOauthAuth {
p.pluginOauthAuthDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p pluginOauthAuth) As(alias string) *pluginOauthAuth {
p.pluginOauthAuthDo.DO = *(p.pluginOauthAuthDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *pluginOauthAuth) updateTableName(table string) *pluginOauthAuth {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt64(table, "id")
p.UserID = field.NewString(table, "user_id")
p.PluginID = field.NewInt64(table, "plugin_id")
p.IsDraft = field.NewBool(table, "is_draft")
p.OauthConfig = field.NewField(table, "oauth_config")
p.AccessToken = field.NewString(table, "access_token")
p.RefreshToken = field.NewString(table, "refresh_token")
p.TokenExpiredAt = field.NewInt64(table, "token_expired_at")
p.NextTokenRefreshAt = field.NewInt64(table, "next_token_refresh_at")
p.LastActiveAt = field.NewInt64(table, "last_active_at")
p.CreatedAt = field.NewInt64(table, "created_at")
p.UpdatedAt = field.NewInt64(table, "updated_at")
p.fillFieldMap()
return p
}
func (p *pluginOauthAuth) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *pluginOauthAuth) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 12)
p.fieldMap["id"] = p.ID
p.fieldMap["user_id"] = p.UserID
p.fieldMap["plugin_id"] = p.PluginID
p.fieldMap["is_draft"] = p.IsDraft
p.fieldMap["oauth_config"] = p.OauthConfig
p.fieldMap["access_token"] = p.AccessToken
p.fieldMap["refresh_token"] = p.RefreshToken
p.fieldMap["token_expired_at"] = p.TokenExpiredAt
p.fieldMap["next_token_refresh_at"] = p.NextTokenRefreshAt
p.fieldMap["last_active_at"] = p.LastActiveAt
p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["updated_at"] = p.UpdatedAt
}
func (p pluginOauthAuth) clone(db *gorm.DB) pluginOauthAuth {
p.pluginOauthAuthDo.ReplaceConnPool(db.Statement.ConnPool)
return p
}
func (p pluginOauthAuth) replaceDB(db *gorm.DB) pluginOauthAuth {
p.pluginOauthAuthDo.ReplaceDB(db)
return p
}
type pluginOauthAuthDo struct{ gen.DO }
type IPluginOauthAuthDo interface {
gen.SubQuery
Debug() IPluginOauthAuthDo
WithContext(ctx context.Context) IPluginOauthAuthDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IPluginOauthAuthDo
WriteDB() IPluginOauthAuthDo
As(alias string) gen.Dao
Session(config *gorm.Session) IPluginOauthAuthDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IPluginOauthAuthDo
Not(conds ...gen.Condition) IPluginOauthAuthDo
Or(conds ...gen.Condition) IPluginOauthAuthDo
Select(conds ...field.Expr) IPluginOauthAuthDo
Where(conds ...gen.Condition) IPluginOauthAuthDo
Order(conds ...field.Expr) IPluginOauthAuthDo
Distinct(cols ...field.Expr) IPluginOauthAuthDo
Omit(cols ...field.Expr) IPluginOauthAuthDo
Join(table schema.Tabler, on ...field.Expr) IPluginOauthAuthDo
LeftJoin(table schema.Tabler, on ...field.Expr) IPluginOauthAuthDo
RightJoin(table schema.Tabler, on ...field.Expr) IPluginOauthAuthDo
Group(cols ...field.Expr) IPluginOauthAuthDo
Having(conds ...gen.Condition) IPluginOauthAuthDo
Limit(limit int) IPluginOauthAuthDo
Offset(offset int) IPluginOauthAuthDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginOauthAuthDo
Unscoped() IPluginOauthAuthDo
Create(values ...*model.PluginOauthAuth) error
CreateInBatches(values []*model.PluginOauthAuth, batchSize int) error
Save(values ...*model.PluginOauthAuth) error
First() (*model.PluginOauthAuth, error)
Take() (*model.PluginOauthAuth, error)
Last() (*model.PluginOauthAuth, error)
Find() ([]*model.PluginOauthAuth, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PluginOauthAuth, err error)
FindInBatches(result *[]*model.PluginOauthAuth, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.PluginOauthAuth) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IPluginOauthAuthDo
Assign(attrs ...field.AssignExpr) IPluginOauthAuthDo
Joins(fields ...field.RelationField) IPluginOauthAuthDo
Preload(fields ...field.RelationField) IPluginOauthAuthDo
FirstOrInit() (*model.PluginOauthAuth, error)
FirstOrCreate() (*model.PluginOauthAuth, error)
FindByPage(offset int, limit int) (result []*model.PluginOauthAuth, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IPluginOauthAuthDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (p pluginOauthAuthDo) Debug() IPluginOauthAuthDo {
return p.withDO(p.DO.Debug())
}
func (p pluginOauthAuthDo) WithContext(ctx context.Context) IPluginOauthAuthDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p pluginOauthAuthDo) ReadDB() IPluginOauthAuthDo {
return p.Clauses(dbresolver.Read)
}
func (p pluginOauthAuthDo) WriteDB() IPluginOauthAuthDo {
return p.Clauses(dbresolver.Write)
}
func (p pluginOauthAuthDo) Session(config *gorm.Session) IPluginOauthAuthDo {
return p.withDO(p.DO.Session(config))
}
func (p pluginOauthAuthDo) Clauses(conds ...clause.Expression) IPluginOauthAuthDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p pluginOauthAuthDo) Returning(value interface{}, columns ...string) IPluginOauthAuthDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p pluginOauthAuthDo) Not(conds ...gen.Condition) IPluginOauthAuthDo {
return p.withDO(p.DO.Not(conds...))
}
func (p pluginOauthAuthDo) Or(conds ...gen.Condition) IPluginOauthAuthDo {
return p.withDO(p.DO.Or(conds...))
}
func (p pluginOauthAuthDo) Select(conds ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.Select(conds...))
}
func (p pluginOauthAuthDo) Where(conds ...gen.Condition) IPluginOauthAuthDo {
return p.withDO(p.DO.Where(conds...))
}
func (p pluginOauthAuthDo) Order(conds ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.Order(conds...))
}
func (p pluginOauthAuthDo) Distinct(cols ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p pluginOauthAuthDo) Omit(cols ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p pluginOauthAuthDo) Join(table schema.Tabler, on ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p pluginOauthAuthDo) LeftJoin(table schema.Tabler, on ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p pluginOauthAuthDo) RightJoin(table schema.Tabler, on ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p pluginOauthAuthDo) Group(cols ...field.Expr) IPluginOauthAuthDo {
return p.withDO(p.DO.Group(cols...))
}
func (p pluginOauthAuthDo) Having(conds ...gen.Condition) IPluginOauthAuthDo {
return p.withDO(p.DO.Having(conds...))
}
func (p pluginOauthAuthDo) Limit(limit int) IPluginOauthAuthDo {
return p.withDO(p.DO.Limit(limit))
}
func (p pluginOauthAuthDo) Offset(offset int) IPluginOauthAuthDo {
return p.withDO(p.DO.Offset(offset))
}
func (p pluginOauthAuthDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginOauthAuthDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p pluginOauthAuthDo) Unscoped() IPluginOauthAuthDo {
return p.withDO(p.DO.Unscoped())
}
func (p pluginOauthAuthDo) Create(values ...*model.PluginOauthAuth) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p pluginOauthAuthDo) CreateInBatches(values []*model.PluginOauthAuth, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p pluginOauthAuthDo) Save(values ...*model.PluginOauthAuth) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p pluginOauthAuthDo) First() (*model.PluginOauthAuth, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.PluginOauthAuth), nil
}
}
func (p pluginOauthAuthDo) Take() (*model.PluginOauthAuth, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.PluginOauthAuth), nil
}
}
func (p pluginOauthAuthDo) Last() (*model.PluginOauthAuth, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.PluginOauthAuth), nil
}
}
func (p pluginOauthAuthDo) Find() ([]*model.PluginOauthAuth, error) {
result, err := p.DO.Find()
return result.([]*model.PluginOauthAuth), err
}
func (p pluginOauthAuthDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PluginOauthAuth, err error) {
buf := make([]*model.PluginOauthAuth, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p pluginOauthAuthDo) FindInBatches(result *[]*model.PluginOauthAuth, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p pluginOauthAuthDo) Attrs(attrs ...field.AssignExpr) IPluginOauthAuthDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p pluginOauthAuthDo) Assign(attrs ...field.AssignExpr) IPluginOauthAuthDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p pluginOauthAuthDo) Joins(fields ...field.RelationField) IPluginOauthAuthDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p pluginOauthAuthDo) Preload(fields ...field.RelationField) IPluginOauthAuthDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p pluginOauthAuthDo) FirstOrInit() (*model.PluginOauthAuth, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.PluginOauthAuth), nil
}
}
func (p pluginOauthAuthDo) FirstOrCreate() (*model.PluginOauthAuth, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.PluginOauthAuth), nil
}
}
func (p pluginOauthAuthDo) FindByPage(offset int, limit int) (result []*model.PluginOauthAuth, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p pluginOauthAuthDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p pluginOauthAuthDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p pluginOauthAuthDo) Delete(models ...*model.PluginOauthAuth) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *pluginOauthAuthDo) withDO(do gen.Dao) *pluginOauthAuthDo {
p.DO = *do.(*gen.DO)
return p
}

View File

@@ -0,0 +1,433 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newPluginVersion(db *gorm.DB, opts ...gen.DOOption) pluginVersion {
_pluginVersion := pluginVersion{}
_pluginVersion.pluginVersionDo.UseDB(db, opts...)
_pluginVersion.pluginVersionDo.UseModel(&model.PluginVersion{})
tableName := _pluginVersion.pluginVersionDo.TableName()
_pluginVersion.ALL = field.NewAsterisk(tableName)
_pluginVersion.ID = field.NewInt64(tableName, "id")
_pluginVersion.SpaceID = field.NewInt64(tableName, "space_id")
_pluginVersion.DeveloperID = field.NewInt64(tableName, "developer_id")
_pluginVersion.PluginID = field.NewInt64(tableName, "plugin_id")
_pluginVersion.AppID = field.NewInt64(tableName, "app_id")
_pluginVersion.IconURI = field.NewString(tableName, "icon_uri")
_pluginVersion.ServerURL = field.NewString(tableName, "server_url")
_pluginVersion.PluginType = field.NewInt32(tableName, "plugin_type")
_pluginVersion.Version = field.NewString(tableName, "version")
_pluginVersion.VersionDesc = field.NewString(tableName, "version_desc")
_pluginVersion.Manifest = field.NewField(tableName, "manifest")
_pluginVersion.OpenapiDoc = field.NewField(tableName, "openapi_doc")
_pluginVersion.CreatedAt = field.NewInt64(tableName, "created_at")
_pluginVersion.DeletedAt = field.NewField(tableName, "deleted_at")
_pluginVersion.fillFieldMap()
return _pluginVersion
}
// pluginVersion Plugin Version
type pluginVersion struct {
pluginVersionDo
ALL field.Asterisk
ID field.Int64 // Primary Key ID
SpaceID field.Int64 // Space ID
DeveloperID field.Int64 // Developer ID
PluginID field.Int64 // Plugin ID
AppID field.Int64 // Application ID
IconURI field.String // Icon URI
ServerURL field.String // Server URL
PluginType field.Int32 // Plugin Type, 1:http, 6:local
Version field.String // Plugin Version, e.g. v1.0.0
VersionDesc field.String // Plugin Version Description
Manifest field.Field // Plugin Manifest
OpenapiDoc field.Field // OpenAPI Document, only stores the root
CreatedAt field.Int64 // Create Time in Milliseconds
DeletedAt field.Field // Delete Time
fieldMap map[string]field.Expr
}
func (p pluginVersion) Table(newTableName string) *pluginVersion {
p.pluginVersionDo.UseTable(newTableName)
return p.updateTableName(newTableName)
}
func (p pluginVersion) As(alias string) *pluginVersion {
p.pluginVersionDo.DO = *(p.pluginVersionDo.As(alias).(*gen.DO))
return p.updateTableName(alias)
}
func (p *pluginVersion) updateTableName(table string) *pluginVersion {
p.ALL = field.NewAsterisk(table)
p.ID = field.NewInt64(table, "id")
p.SpaceID = field.NewInt64(table, "space_id")
p.DeveloperID = field.NewInt64(table, "developer_id")
p.PluginID = field.NewInt64(table, "plugin_id")
p.AppID = field.NewInt64(table, "app_id")
p.IconURI = field.NewString(table, "icon_uri")
p.ServerURL = field.NewString(table, "server_url")
p.PluginType = field.NewInt32(table, "plugin_type")
p.Version = field.NewString(table, "version")
p.VersionDesc = field.NewString(table, "version_desc")
p.Manifest = field.NewField(table, "manifest")
p.OpenapiDoc = field.NewField(table, "openapi_doc")
p.CreatedAt = field.NewInt64(table, "created_at")
p.DeletedAt = field.NewField(table, "deleted_at")
p.fillFieldMap()
return p
}
func (p *pluginVersion) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := p.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (p *pluginVersion) fillFieldMap() {
p.fieldMap = make(map[string]field.Expr, 14)
p.fieldMap["id"] = p.ID
p.fieldMap["space_id"] = p.SpaceID
p.fieldMap["developer_id"] = p.DeveloperID
p.fieldMap["plugin_id"] = p.PluginID
p.fieldMap["app_id"] = p.AppID
p.fieldMap["icon_uri"] = p.IconURI
p.fieldMap["server_url"] = p.ServerURL
p.fieldMap["plugin_type"] = p.PluginType
p.fieldMap["version"] = p.Version
p.fieldMap["version_desc"] = p.VersionDesc
p.fieldMap["manifest"] = p.Manifest
p.fieldMap["openapi_doc"] = p.OpenapiDoc
p.fieldMap["created_at"] = p.CreatedAt
p.fieldMap["deleted_at"] = p.DeletedAt
}
func (p pluginVersion) clone(db *gorm.DB) pluginVersion {
p.pluginVersionDo.ReplaceConnPool(db.Statement.ConnPool)
return p
}
func (p pluginVersion) replaceDB(db *gorm.DB) pluginVersion {
p.pluginVersionDo.ReplaceDB(db)
return p
}
type pluginVersionDo struct{ gen.DO }
type IPluginVersionDo interface {
gen.SubQuery
Debug() IPluginVersionDo
WithContext(ctx context.Context) IPluginVersionDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IPluginVersionDo
WriteDB() IPluginVersionDo
As(alias string) gen.Dao
Session(config *gorm.Session) IPluginVersionDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IPluginVersionDo
Not(conds ...gen.Condition) IPluginVersionDo
Or(conds ...gen.Condition) IPluginVersionDo
Select(conds ...field.Expr) IPluginVersionDo
Where(conds ...gen.Condition) IPluginVersionDo
Order(conds ...field.Expr) IPluginVersionDo
Distinct(cols ...field.Expr) IPluginVersionDo
Omit(cols ...field.Expr) IPluginVersionDo
Join(table schema.Tabler, on ...field.Expr) IPluginVersionDo
LeftJoin(table schema.Tabler, on ...field.Expr) IPluginVersionDo
RightJoin(table schema.Tabler, on ...field.Expr) IPluginVersionDo
Group(cols ...field.Expr) IPluginVersionDo
Having(conds ...gen.Condition) IPluginVersionDo
Limit(limit int) IPluginVersionDo
Offset(offset int) IPluginVersionDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginVersionDo
Unscoped() IPluginVersionDo
Create(values ...*model.PluginVersion) error
CreateInBatches(values []*model.PluginVersion, batchSize int) error
Save(values ...*model.PluginVersion) error
First() (*model.PluginVersion, error)
Take() (*model.PluginVersion, error)
Last() (*model.PluginVersion, error)
Find() ([]*model.PluginVersion, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PluginVersion, err error)
FindInBatches(result *[]*model.PluginVersion, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.PluginVersion) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IPluginVersionDo
Assign(attrs ...field.AssignExpr) IPluginVersionDo
Joins(fields ...field.RelationField) IPluginVersionDo
Preload(fields ...field.RelationField) IPluginVersionDo
FirstOrInit() (*model.PluginVersion, error)
FirstOrCreate() (*model.PluginVersion, error)
FindByPage(offset int, limit int) (result []*model.PluginVersion, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IPluginVersionDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (p pluginVersionDo) Debug() IPluginVersionDo {
return p.withDO(p.DO.Debug())
}
func (p pluginVersionDo) WithContext(ctx context.Context) IPluginVersionDo {
return p.withDO(p.DO.WithContext(ctx))
}
func (p pluginVersionDo) ReadDB() IPluginVersionDo {
return p.Clauses(dbresolver.Read)
}
func (p pluginVersionDo) WriteDB() IPluginVersionDo {
return p.Clauses(dbresolver.Write)
}
func (p pluginVersionDo) Session(config *gorm.Session) IPluginVersionDo {
return p.withDO(p.DO.Session(config))
}
func (p pluginVersionDo) Clauses(conds ...clause.Expression) IPluginVersionDo {
return p.withDO(p.DO.Clauses(conds...))
}
func (p pluginVersionDo) Returning(value interface{}, columns ...string) IPluginVersionDo {
return p.withDO(p.DO.Returning(value, columns...))
}
func (p pluginVersionDo) Not(conds ...gen.Condition) IPluginVersionDo {
return p.withDO(p.DO.Not(conds...))
}
func (p pluginVersionDo) Or(conds ...gen.Condition) IPluginVersionDo {
return p.withDO(p.DO.Or(conds...))
}
func (p pluginVersionDo) Select(conds ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.Select(conds...))
}
func (p pluginVersionDo) Where(conds ...gen.Condition) IPluginVersionDo {
return p.withDO(p.DO.Where(conds...))
}
func (p pluginVersionDo) Order(conds ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.Order(conds...))
}
func (p pluginVersionDo) Distinct(cols ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.Distinct(cols...))
}
func (p pluginVersionDo) Omit(cols ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.Omit(cols...))
}
func (p pluginVersionDo) Join(table schema.Tabler, on ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.Join(table, on...))
}
func (p pluginVersionDo) LeftJoin(table schema.Tabler, on ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.LeftJoin(table, on...))
}
func (p pluginVersionDo) RightJoin(table schema.Tabler, on ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.RightJoin(table, on...))
}
func (p pluginVersionDo) Group(cols ...field.Expr) IPluginVersionDo {
return p.withDO(p.DO.Group(cols...))
}
func (p pluginVersionDo) Having(conds ...gen.Condition) IPluginVersionDo {
return p.withDO(p.DO.Having(conds...))
}
func (p pluginVersionDo) Limit(limit int) IPluginVersionDo {
return p.withDO(p.DO.Limit(limit))
}
func (p pluginVersionDo) Offset(offset int) IPluginVersionDo {
return p.withDO(p.DO.Offset(offset))
}
func (p pluginVersionDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IPluginVersionDo {
return p.withDO(p.DO.Scopes(funcs...))
}
func (p pluginVersionDo) Unscoped() IPluginVersionDo {
return p.withDO(p.DO.Unscoped())
}
func (p pluginVersionDo) Create(values ...*model.PluginVersion) error {
if len(values) == 0 {
return nil
}
return p.DO.Create(values)
}
func (p pluginVersionDo) CreateInBatches(values []*model.PluginVersion, batchSize int) error {
return p.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (p pluginVersionDo) Save(values ...*model.PluginVersion) error {
if len(values) == 0 {
return nil
}
return p.DO.Save(values)
}
func (p pluginVersionDo) First() (*model.PluginVersion, error) {
if result, err := p.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.PluginVersion), nil
}
}
func (p pluginVersionDo) Take() (*model.PluginVersion, error) {
if result, err := p.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.PluginVersion), nil
}
}
func (p pluginVersionDo) Last() (*model.PluginVersion, error) {
if result, err := p.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.PluginVersion), nil
}
}
func (p pluginVersionDo) Find() ([]*model.PluginVersion, error) {
result, err := p.DO.Find()
return result.([]*model.PluginVersion), err
}
func (p pluginVersionDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.PluginVersion, err error) {
buf := make([]*model.PluginVersion, 0, batchSize)
err = p.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (p pluginVersionDo) FindInBatches(result *[]*model.PluginVersion, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return p.DO.FindInBatches(result, batchSize, fc)
}
func (p pluginVersionDo) Attrs(attrs ...field.AssignExpr) IPluginVersionDo {
return p.withDO(p.DO.Attrs(attrs...))
}
func (p pluginVersionDo) Assign(attrs ...field.AssignExpr) IPluginVersionDo {
return p.withDO(p.DO.Assign(attrs...))
}
func (p pluginVersionDo) Joins(fields ...field.RelationField) IPluginVersionDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Joins(_f))
}
return &p
}
func (p pluginVersionDo) Preload(fields ...field.RelationField) IPluginVersionDo {
for _, _f := range fields {
p = *p.withDO(p.DO.Preload(_f))
}
return &p
}
func (p pluginVersionDo) FirstOrInit() (*model.PluginVersion, error) {
if result, err := p.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.PluginVersion), nil
}
}
func (p pluginVersionDo) FirstOrCreate() (*model.PluginVersion, error) {
if result, err := p.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.PluginVersion), nil
}
}
func (p pluginVersionDo) FindByPage(offset int, limit int) (result []*model.PluginVersion, count int64, err error) {
result, err = p.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = p.Offset(-1).Limit(-1).Count()
return
}
func (p pluginVersionDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = p.Count()
if err != nil {
return
}
err = p.Offset(offset).Limit(limit).Scan(result)
return
}
func (p pluginVersionDo) Scan(result interface{}) (err error) {
return p.DO.Scan(result)
}
func (p pluginVersionDo) Delete(models ...*model.PluginVersion) (result gen.ResultInfo, err error) {
return p.DO.Delete(models)
}
func (p *pluginVersionDo) withDO(do gen.Dao) *pluginVersionDo {
p.DO = *do.(*gen.DO)
return p
}

View File

@@ -0,0 +1,413 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newTool(db *gorm.DB, opts ...gen.DOOption) tool {
_tool := tool{}
_tool.toolDo.UseDB(db, opts...)
_tool.toolDo.UseModel(&model.Tool{})
tableName := _tool.toolDo.TableName()
_tool.ALL = field.NewAsterisk(tableName)
_tool.ID = field.NewInt64(tableName, "id")
_tool.PluginID = field.NewInt64(tableName, "plugin_id")
_tool.CreatedAt = field.NewInt64(tableName, "created_at")
_tool.UpdatedAt = field.NewInt64(tableName, "updated_at")
_tool.Version = field.NewString(tableName, "version")
_tool.SubURL = field.NewString(tableName, "sub_url")
_tool.Method = field.NewString(tableName, "method")
_tool.Operation = field.NewField(tableName, "operation")
_tool.ActivatedStatus = field.NewInt32(tableName, "activated_status")
_tool.fillFieldMap()
return _tool
}
// tool Latest Tool
type tool struct {
toolDo
ALL field.Asterisk
ID field.Int64 // Tool ID
PluginID field.Int64 // Plugin ID
CreatedAt field.Int64 // Create Time in Milliseconds
UpdatedAt field.Int64 // Update Time in Milliseconds
Version field.String // Tool Version, e.g. v1.0.0
SubURL field.String // Sub URL Path
Method field.String // HTTP Request Method
Operation field.Field // Tool Openapi Operation Schema
ActivatedStatus field.Int32 // 0:activated; 1:deactivated
fieldMap map[string]field.Expr
}
func (t tool) Table(newTableName string) *tool {
t.toolDo.UseTable(newTableName)
return t.updateTableName(newTableName)
}
func (t tool) As(alias string) *tool {
t.toolDo.DO = *(t.toolDo.As(alias).(*gen.DO))
return t.updateTableName(alias)
}
func (t *tool) updateTableName(table string) *tool {
t.ALL = field.NewAsterisk(table)
t.ID = field.NewInt64(table, "id")
t.PluginID = field.NewInt64(table, "plugin_id")
t.CreatedAt = field.NewInt64(table, "created_at")
t.UpdatedAt = field.NewInt64(table, "updated_at")
t.Version = field.NewString(table, "version")
t.SubURL = field.NewString(table, "sub_url")
t.Method = field.NewString(table, "method")
t.Operation = field.NewField(table, "operation")
t.ActivatedStatus = field.NewInt32(table, "activated_status")
t.fillFieldMap()
return t
}
func (t *tool) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := t.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (t *tool) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 9)
t.fieldMap["id"] = t.ID
t.fieldMap["plugin_id"] = t.PluginID
t.fieldMap["created_at"] = t.CreatedAt
t.fieldMap["updated_at"] = t.UpdatedAt
t.fieldMap["version"] = t.Version
t.fieldMap["sub_url"] = t.SubURL
t.fieldMap["method"] = t.Method
t.fieldMap["operation"] = t.Operation
t.fieldMap["activated_status"] = t.ActivatedStatus
}
func (t tool) clone(db *gorm.DB) tool {
t.toolDo.ReplaceConnPool(db.Statement.ConnPool)
return t
}
func (t tool) replaceDB(db *gorm.DB) tool {
t.toolDo.ReplaceDB(db)
return t
}
type toolDo struct{ gen.DO }
type IToolDo interface {
gen.SubQuery
Debug() IToolDo
WithContext(ctx context.Context) IToolDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IToolDo
WriteDB() IToolDo
As(alias string) gen.Dao
Session(config *gorm.Session) IToolDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IToolDo
Not(conds ...gen.Condition) IToolDo
Or(conds ...gen.Condition) IToolDo
Select(conds ...field.Expr) IToolDo
Where(conds ...gen.Condition) IToolDo
Order(conds ...field.Expr) IToolDo
Distinct(cols ...field.Expr) IToolDo
Omit(cols ...field.Expr) IToolDo
Join(table schema.Tabler, on ...field.Expr) IToolDo
LeftJoin(table schema.Tabler, on ...field.Expr) IToolDo
RightJoin(table schema.Tabler, on ...field.Expr) IToolDo
Group(cols ...field.Expr) IToolDo
Having(conds ...gen.Condition) IToolDo
Limit(limit int) IToolDo
Offset(offset int) IToolDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IToolDo
Unscoped() IToolDo
Create(values ...*model.Tool) error
CreateInBatches(values []*model.Tool, batchSize int) error
Save(values ...*model.Tool) error
First() (*model.Tool, error)
Take() (*model.Tool, error)
Last() (*model.Tool, error)
Find() ([]*model.Tool, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Tool, err error)
FindInBatches(result *[]*model.Tool, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.Tool) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IToolDo
Assign(attrs ...field.AssignExpr) IToolDo
Joins(fields ...field.RelationField) IToolDo
Preload(fields ...field.RelationField) IToolDo
FirstOrInit() (*model.Tool, error)
FirstOrCreate() (*model.Tool, error)
FindByPage(offset int, limit int) (result []*model.Tool, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IToolDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (t toolDo) Debug() IToolDo {
return t.withDO(t.DO.Debug())
}
func (t toolDo) WithContext(ctx context.Context) IToolDo {
return t.withDO(t.DO.WithContext(ctx))
}
func (t toolDo) ReadDB() IToolDo {
return t.Clauses(dbresolver.Read)
}
func (t toolDo) WriteDB() IToolDo {
return t.Clauses(dbresolver.Write)
}
func (t toolDo) Session(config *gorm.Session) IToolDo {
return t.withDO(t.DO.Session(config))
}
func (t toolDo) Clauses(conds ...clause.Expression) IToolDo {
return t.withDO(t.DO.Clauses(conds...))
}
func (t toolDo) Returning(value interface{}, columns ...string) IToolDo {
return t.withDO(t.DO.Returning(value, columns...))
}
func (t toolDo) Not(conds ...gen.Condition) IToolDo {
return t.withDO(t.DO.Not(conds...))
}
func (t toolDo) Or(conds ...gen.Condition) IToolDo {
return t.withDO(t.DO.Or(conds...))
}
func (t toolDo) Select(conds ...field.Expr) IToolDo {
return t.withDO(t.DO.Select(conds...))
}
func (t toolDo) Where(conds ...gen.Condition) IToolDo {
return t.withDO(t.DO.Where(conds...))
}
func (t toolDo) Order(conds ...field.Expr) IToolDo {
return t.withDO(t.DO.Order(conds...))
}
func (t toolDo) Distinct(cols ...field.Expr) IToolDo {
return t.withDO(t.DO.Distinct(cols...))
}
func (t toolDo) Omit(cols ...field.Expr) IToolDo {
return t.withDO(t.DO.Omit(cols...))
}
func (t toolDo) Join(table schema.Tabler, on ...field.Expr) IToolDo {
return t.withDO(t.DO.Join(table, on...))
}
func (t toolDo) LeftJoin(table schema.Tabler, on ...field.Expr) IToolDo {
return t.withDO(t.DO.LeftJoin(table, on...))
}
func (t toolDo) RightJoin(table schema.Tabler, on ...field.Expr) IToolDo {
return t.withDO(t.DO.RightJoin(table, on...))
}
func (t toolDo) Group(cols ...field.Expr) IToolDo {
return t.withDO(t.DO.Group(cols...))
}
func (t toolDo) Having(conds ...gen.Condition) IToolDo {
return t.withDO(t.DO.Having(conds...))
}
func (t toolDo) Limit(limit int) IToolDo {
return t.withDO(t.DO.Limit(limit))
}
func (t toolDo) Offset(offset int) IToolDo {
return t.withDO(t.DO.Offset(offset))
}
func (t toolDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IToolDo {
return t.withDO(t.DO.Scopes(funcs...))
}
func (t toolDo) Unscoped() IToolDo {
return t.withDO(t.DO.Unscoped())
}
func (t toolDo) Create(values ...*model.Tool) error {
if len(values) == 0 {
return nil
}
return t.DO.Create(values)
}
func (t toolDo) CreateInBatches(values []*model.Tool, batchSize int) error {
return t.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (t toolDo) Save(values ...*model.Tool) error {
if len(values) == 0 {
return nil
}
return t.DO.Save(values)
}
func (t toolDo) First() (*model.Tool, error) {
if result, err := t.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.Tool), nil
}
}
func (t toolDo) Take() (*model.Tool, error) {
if result, err := t.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.Tool), nil
}
}
func (t toolDo) Last() (*model.Tool, error) {
if result, err := t.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.Tool), nil
}
}
func (t toolDo) Find() ([]*model.Tool, error) {
result, err := t.DO.Find()
return result.([]*model.Tool), err
}
func (t toolDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.Tool, err error) {
buf := make([]*model.Tool, 0, batchSize)
err = t.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (t toolDo) FindInBatches(result *[]*model.Tool, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return t.DO.FindInBatches(result, batchSize, fc)
}
func (t toolDo) Attrs(attrs ...field.AssignExpr) IToolDo {
return t.withDO(t.DO.Attrs(attrs...))
}
func (t toolDo) Assign(attrs ...field.AssignExpr) IToolDo {
return t.withDO(t.DO.Assign(attrs...))
}
func (t toolDo) Joins(fields ...field.RelationField) IToolDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Joins(_f))
}
return &t
}
func (t toolDo) Preload(fields ...field.RelationField) IToolDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Preload(_f))
}
return &t
}
func (t toolDo) FirstOrInit() (*model.Tool, error) {
if result, err := t.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.Tool), nil
}
}
func (t toolDo) FirstOrCreate() (*model.Tool, error) {
if result, err := t.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.Tool), nil
}
}
func (t toolDo) FindByPage(offset int, limit int) (result []*model.Tool, count int64, err error) {
result, err = t.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = t.Offset(-1).Limit(-1).Count()
return
}
func (t toolDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = t.Count()
if err != nil {
return
}
err = t.Offset(offset).Limit(limit).Scan(result)
return
}
func (t toolDo) Scan(result interface{}) (err error) {
return t.DO.Scan(result)
}
func (t toolDo) Delete(models ...*model.Tool) (result gen.ResultInfo, err error) {
return t.DO.Delete(models)
}
func (t *toolDo) withDO(do gen.Dao) *toolDo {
t.DO = *do.(*gen.DO)
return t
}

View File

@@ -0,0 +1,413 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newToolDraft(db *gorm.DB, opts ...gen.DOOption) toolDraft {
_toolDraft := toolDraft{}
_toolDraft.toolDraftDo.UseDB(db, opts...)
_toolDraft.toolDraftDo.UseModel(&model.ToolDraft{})
tableName := _toolDraft.toolDraftDo.TableName()
_toolDraft.ALL = field.NewAsterisk(tableName)
_toolDraft.ID = field.NewInt64(tableName, "id")
_toolDraft.PluginID = field.NewInt64(tableName, "plugin_id")
_toolDraft.CreatedAt = field.NewInt64(tableName, "created_at")
_toolDraft.UpdatedAt = field.NewInt64(tableName, "updated_at")
_toolDraft.SubURL = field.NewString(tableName, "sub_url")
_toolDraft.Method = field.NewString(tableName, "method")
_toolDraft.Operation = field.NewField(tableName, "operation")
_toolDraft.DebugStatus = field.NewInt32(tableName, "debug_status")
_toolDraft.ActivatedStatus = field.NewInt32(tableName, "activated_status")
_toolDraft.fillFieldMap()
return _toolDraft
}
// toolDraft Draft Tool
type toolDraft struct {
toolDraftDo
ALL field.Asterisk
ID field.Int64 // Tool ID
PluginID field.Int64 // Plugin ID
CreatedAt field.Int64 // Create Time in Milliseconds
UpdatedAt field.Int64 // Update Time in Milliseconds
SubURL field.String // Sub URL Path
Method field.String // HTTP Request Method
Operation field.Field // Tool Openapi Operation Schema
DebugStatus field.Int32 // 0:not pass; 1:pass
ActivatedStatus field.Int32 // 0:activated; 1:deactivated
fieldMap map[string]field.Expr
}
func (t toolDraft) Table(newTableName string) *toolDraft {
t.toolDraftDo.UseTable(newTableName)
return t.updateTableName(newTableName)
}
func (t toolDraft) As(alias string) *toolDraft {
t.toolDraftDo.DO = *(t.toolDraftDo.As(alias).(*gen.DO))
return t.updateTableName(alias)
}
func (t *toolDraft) updateTableName(table string) *toolDraft {
t.ALL = field.NewAsterisk(table)
t.ID = field.NewInt64(table, "id")
t.PluginID = field.NewInt64(table, "plugin_id")
t.CreatedAt = field.NewInt64(table, "created_at")
t.UpdatedAt = field.NewInt64(table, "updated_at")
t.SubURL = field.NewString(table, "sub_url")
t.Method = field.NewString(table, "method")
t.Operation = field.NewField(table, "operation")
t.DebugStatus = field.NewInt32(table, "debug_status")
t.ActivatedStatus = field.NewInt32(table, "activated_status")
t.fillFieldMap()
return t
}
func (t *toolDraft) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := t.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (t *toolDraft) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 9)
t.fieldMap["id"] = t.ID
t.fieldMap["plugin_id"] = t.PluginID
t.fieldMap["created_at"] = t.CreatedAt
t.fieldMap["updated_at"] = t.UpdatedAt
t.fieldMap["sub_url"] = t.SubURL
t.fieldMap["method"] = t.Method
t.fieldMap["operation"] = t.Operation
t.fieldMap["debug_status"] = t.DebugStatus
t.fieldMap["activated_status"] = t.ActivatedStatus
}
func (t toolDraft) clone(db *gorm.DB) toolDraft {
t.toolDraftDo.ReplaceConnPool(db.Statement.ConnPool)
return t
}
func (t toolDraft) replaceDB(db *gorm.DB) toolDraft {
t.toolDraftDo.ReplaceDB(db)
return t
}
type toolDraftDo struct{ gen.DO }
type IToolDraftDo interface {
gen.SubQuery
Debug() IToolDraftDo
WithContext(ctx context.Context) IToolDraftDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IToolDraftDo
WriteDB() IToolDraftDo
As(alias string) gen.Dao
Session(config *gorm.Session) IToolDraftDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IToolDraftDo
Not(conds ...gen.Condition) IToolDraftDo
Or(conds ...gen.Condition) IToolDraftDo
Select(conds ...field.Expr) IToolDraftDo
Where(conds ...gen.Condition) IToolDraftDo
Order(conds ...field.Expr) IToolDraftDo
Distinct(cols ...field.Expr) IToolDraftDo
Omit(cols ...field.Expr) IToolDraftDo
Join(table schema.Tabler, on ...field.Expr) IToolDraftDo
LeftJoin(table schema.Tabler, on ...field.Expr) IToolDraftDo
RightJoin(table schema.Tabler, on ...field.Expr) IToolDraftDo
Group(cols ...field.Expr) IToolDraftDo
Having(conds ...gen.Condition) IToolDraftDo
Limit(limit int) IToolDraftDo
Offset(offset int) IToolDraftDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IToolDraftDo
Unscoped() IToolDraftDo
Create(values ...*model.ToolDraft) error
CreateInBatches(values []*model.ToolDraft, batchSize int) error
Save(values ...*model.ToolDraft) error
First() (*model.ToolDraft, error)
Take() (*model.ToolDraft, error)
Last() (*model.ToolDraft, error)
Find() ([]*model.ToolDraft, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ToolDraft, err error)
FindInBatches(result *[]*model.ToolDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.ToolDraft) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IToolDraftDo
Assign(attrs ...field.AssignExpr) IToolDraftDo
Joins(fields ...field.RelationField) IToolDraftDo
Preload(fields ...field.RelationField) IToolDraftDo
FirstOrInit() (*model.ToolDraft, error)
FirstOrCreate() (*model.ToolDraft, error)
FindByPage(offset int, limit int) (result []*model.ToolDraft, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IToolDraftDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (t toolDraftDo) Debug() IToolDraftDo {
return t.withDO(t.DO.Debug())
}
func (t toolDraftDo) WithContext(ctx context.Context) IToolDraftDo {
return t.withDO(t.DO.WithContext(ctx))
}
func (t toolDraftDo) ReadDB() IToolDraftDo {
return t.Clauses(dbresolver.Read)
}
func (t toolDraftDo) WriteDB() IToolDraftDo {
return t.Clauses(dbresolver.Write)
}
func (t toolDraftDo) Session(config *gorm.Session) IToolDraftDo {
return t.withDO(t.DO.Session(config))
}
func (t toolDraftDo) Clauses(conds ...clause.Expression) IToolDraftDo {
return t.withDO(t.DO.Clauses(conds...))
}
func (t toolDraftDo) Returning(value interface{}, columns ...string) IToolDraftDo {
return t.withDO(t.DO.Returning(value, columns...))
}
func (t toolDraftDo) Not(conds ...gen.Condition) IToolDraftDo {
return t.withDO(t.DO.Not(conds...))
}
func (t toolDraftDo) Or(conds ...gen.Condition) IToolDraftDo {
return t.withDO(t.DO.Or(conds...))
}
func (t toolDraftDo) Select(conds ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.Select(conds...))
}
func (t toolDraftDo) Where(conds ...gen.Condition) IToolDraftDo {
return t.withDO(t.DO.Where(conds...))
}
func (t toolDraftDo) Order(conds ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.Order(conds...))
}
func (t toolDraftDo) Distinct(cols ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.Distinct(cols...))
}
func (t toolDraftDo) Omit(cols ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.Omit(cols...))
}
func (t toolDraftDo) Join(table schema.Tabler, on ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.Join(table, on...))
}
func (t toolDraftDo) LeftJoin(table schema.Tabler, on ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.LeftJoin(table, on...))
}
func (t toolDraftDo) RightJoin(table schema.Tabler, on ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.RightJoin(table, on...))
}
func (t toolDraftDo) Group(cols ...field.Expr) IToolDraftDo {
return t.withDO(t.DO.Group(cols...))
}
func (t toolDraftDo) Having(conds ...gen.Condition) IToolDraftDo {
return t.withDO(t.DO.Having(conds...))
}
func (t toolDraftDo) Limit(limit int) IToolDraftDo {
return t.withDO(t.DO.Limit(limit))
}
func (t toolDraftDo) Offset(offset int) IToolDraftDo {
return t.withDO(t.DO.Offset(offset))
}
func (t toolDraftDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IToolDraftDo {
return t.withDO(t.DO.Scopes(funcs...))
}
func (t toolDraftDo) Unscoped() IToolDraftDo {
return t.withDO(t.DO.Unscoped())
}
func (t toolDraftDo) Create(values ...*model.ToolDraft) error {
if len(values) == 0 {
return nil
}
return t.DO.Create(values)
}
func (t toolDraftDo) CreateInBatches(values []*model.ToolDraft, batchSize int) error {
return t.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (t toolDraftDo) Save(values ...*model.ToolDraft) error {
if len(values) == 0 {
return nil
}
return t.DO.Save(values)
}
func (t toolDraftDo) First() (*model.ToolDraft, error) {
if result, err := t.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.ToolDraft), nil
}
}
func (t toolDraftDo) Take() (*model.ToolDraft, error) {
if result, err := t.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.ToolDraft), nil
}
}
func (t toolDraftDo) Last() (*model.ToolDraft, error) {
if result, err := t.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.ToolDraft), nil
}
}
func (t toolDraftDo) Find() ([]*model.ToolDraft, error) {
result, err := t.DO.Find()
return result.([]*model.ToolDraft), err
}
func (t toolDraftDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ToolDraft, err error) {
buf := make([]*model.ToolDraft, 0, batchSize)
err = t.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (t toolDraftDo) FindInBatches(result *[]*model.ToolDraft, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return t.DO.FindInBatches(result, batchSize, fc)
}
func (t toolDraftDo) Attrs(attrs ...field.AssignExpr) IToolDraftDo {
return t.withDO(t.DO.Attrs(attrs...))
}
func (t toolDraftDo) Assign(attrs ...field.AssignExpr) IToolDraftDo {
return t.withDO(t.DO.Assign(attrs...))
}
func (t toolDraftDo) Joins(fields ...field.RelationField) IToolDraftDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Joins(_f))
}
return &t
}
func (t toolDraftDo) Preload(fields ...field.RelationField) IToolDraftDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Preload(_f))
}
return &t
}
func (t toolDraftDo) FirstOrInit() (*model.ToolDraft, error) {
if result, err := t.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.ToolDraft), nil
}
}
func (t toolDraftDo) FirstOrCreate() (*model.ToolDraft, error) {
if result, err := t.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.ToolDraft), nil
}
}
func (t toolDraftDo) FindByPage(offset int, limit int) (result []*model.ToolDraft, count int64, err error) {
result, err = t.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = t.Offset(-1).Limit(-1).Count()
return
}
func (t toolDraftDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = t.Count()
if err != nil {
return
}
err = t.Offset(offset).Limit(limit).Scan(result)
return
}
func (t toolDraftDo) Scan(result interface{}) (err error) {
return t.DO.Scan(result)
}
func (t toolDraftDo) Delete(models ...*model.ToolDraft) (result gen.ResultInfo, err error) {
return t.DO.Delete(models)
}
func (t *toolDraftDo) withDO(do gen.Dao) *toolDraftDo {
t.DO = *do.(*gen.DO)
return t
}

View File

@@ -0,0 +1,413 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
)
func newToolVersion(db *gorm.DB, opts ...gen.DOOption) toolVersion {
_toolVersion := toolVersion{}
_toolVersion.toolVersionDo.UseDB(db, opts...)
_toolVersion.toolVersionDo.UseModel(&model.ToolVersion{})
tableName := _toolVersion.toolVersionDo.TableName()
_toolVersion.ALL = field.NewAsterisk(tableName)
_toolVersion.ID = field.NewInt64(tableName, "id")
_toolVersion.ToolID = field.NewInt64(tableName, "tool_id")
_toolVersion.PluginID = field.NewInt64(tableName, "plugin_id")
_toolVersion.Version = field.NewString(tableName, "version")
_toolVersion.SubURL = field.NewString(tableName, "sub_url")
_toolVersion.Method = field.NewString(tableName, "method")
_toolVersion.Operation = field.NewField(tableName, "operation")
_toolVersion.CreatedAt = field.NewInt64(tableName, "created_at")
_toolVersion.DeletedAt = field.NewField(tableName, "deleted_at")
_toolVersion.fillFieldMap()
return _toolVersion
}
// toolVersion Tool Version
type toolVersion struct {
toolVersionDo
ALL field.Asterisk
ID field.Int64 // Primary Key ID
ToolID field.Int64 // Tool ID
PluginID field.Int64 // Plugin ID
Version field.String // Tool Version, e.g. v1.0.0
SubURL field.String // Sub URL Path
Method field.String // HTTP Request Method
Operation field.Field // Tool Openapi Operation Schema
CreatedAt field.Int64 // Create Time in Milliseconds
DeletedAt field.Field // Delete Time
fieldMap map[string]field.Expr
}
func (t toolVersion) Table(newTableName string) *toolVersion {
t.toolVersionDo.UseTable(newTableName)
return t.updateTableName(newTableName)
}
func (t toolVersion) As(alias string) *toolVersion {
t.toolVersionDo.DO = *(t.toolVersionDo.As(alias).(*gen.DO))
return t.updateTableName(alias)
}
func (t *toolVersion) updateTableName(table string) *toolVersion {
t.ALL = field.NewAsterisk(table)
t.ID = field.NewInt64(table, "id")
t.ToolID = field.NewInt64(table, "tool_id")
t.PluginID = field.NewInt64(table, "plugin_id")
t.Version = field.NewString(table, "version")
t.SubURL = field.NewString(table, "sub_url")
t.Method = field.NewString(table, "method")
t.Operation = field.NewField(table, "operation")
t.CreatedAt = field.NewInt64(table, "created_at")
t.DeletedAt = field.NewField(table, "deleted_at")
t.fillFieldMap()
return t
}
func (t *toolVersion) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := t.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (t *toolVersion) fillFieldMap() {
t.fieldMap = make(map[string]field.Expr, 9)
t.fieldMap["id"] = t.ID
t.fieldMap["tool_id"] = t.ToolID
t.fieldMap["plugin_id"] = t.PluginID
t.fieldMap["version"] = t.Version
t.fieldMap["sub_url"] = t.SubURL
t.fieldMap["method"] = t.Method
t.fieldMap["operation"] = t.Operation
t.fieldMap["created_at"] = t.CreatedAt
t.fieldMap["deleted_at"] = t.DeletedAt
}
func (t toolVersion) clone(db *gorm.DB) toolVersion {
t.toolVersionDo.ReplaceConnPool(db.Statement.ConnPool)
return t
}
func (t toolVersion) replaceDB(db *gorm.DB) toolVersion {
t.toolVersionDo.ReplaceDB(db)
return t
}
type toolVersionDo struct{ gen.DO }
type IToolVersionDo interface {
gen.SubQuery
Debug() IToolVersionDo
WithContext(ctx context.Context) IToolVersionDo
WithResult(fc func(tx gen.Dao)) gen.ResultInfo
ReplaceDB(db *gorm.DB)
ReadDB() IToolVersionDo
WriteDB() IToolVersionDo
As(alias string) gen.Dao
Session(config *gorm.Session) IToolVersionDo
Columns(cols ...field.Expr) gen.Columns
Clauses(conds ...clause.Expression) IToolVersionDo
Not(conds ...gen.Condition) IToolVersionDo
Or(conds ...gen.Condition) IToolVersionDo
Select(conds ...field.Expr) IToolVersionDo
Where(conds ...gen.Condition) IToolVersionDo
Order(conds ...field.Expr) IToolVersionDo
Distinct(cols ...field.Expr) IToolVersionDo
Omit(cols ...field.Expr) IToolVersionDo
Join(table schema.Tabler, on ...field.Expr) IToolVersionDo
LeftJoin(table schema.Tabler, on ...field.Expr) IToolVersionDo
RightJoin(table schema.Tabler, on ...field.Expr) IToolVersionDo
Group(cols ...field.Expr) IToolVersionDo
Having(conds ...gen.Condition) IToolVersionDo
Limit(limit int) IToolVersionDo
Offset(offset int) IToolVersionDo
Count() (count int64, err error)
Scopes(funcs ...func(gen.Dao) gen.Dao) IToolVersionDo
Unscoped() IToolVersionDo
Create(values ...*model.ToolVersion) error
CreateInBatches(values []*model.ToolVersion, batchSize int) error
Save(values ...*model.ToolVersion) error
First() (*model.ToolVersion, error)
Take() (*model.ToolVersion, error)
Last() (*model.ToolVersion, error)
Find() ([]*model.ToolVersion, error)
FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ToolVersion, err error)
FindInBatches(result *[]*model.ToolVersion, batchSize int, fc func(tx gen.Dao, batch int) error) error
Pluck(column field.Expr, dest interface{}) error
Delete(...*model.ToolVersion) (info gen.ResultInfo, err error)
Update(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
Updates(value interface{}) (info gen.ResultInfo, err error)
UpdateColumn(column field.Expr, value interface{}) (info gen.ResultInfo, err error)
UpdateColumnSimple(columns ...field.AssignExpr) (info gen.ResultInfo, err error)
UpdateColumns(value interface{}) (info gen.ResultInfo, err error)
UpdateFrom(q gen.SubQuery) gen.Dao
Attrs(attrs ...field.AssignExpr) IToolVersionDo
Assign(attrs ...field.AssignExpr) IToolVersionDo
Joins(fields ...field.RelationField) IToolVersionDo
Preload(fields ...field.RelationField) IToolVersionDo
FirstOrInit() (*model.ToolVersion, error)
FirstOrCreate() (*model.ToolVersion, error)
FindByPage(offset int, limit int) (result []*model.ToolVersion, count int64, err error)
ScanByPage(result interface{}, offset int, limit int) (count int64, err error)
Scan(result interface{}) (err error)
Returning(value interface{}, columns ...string) IToolVersionDo
UnderlyingDB() *gorm.DB
schema.Tabler
}
func (t toolVersionDo) Debug() IToolVersionDo {
return t.withDO(t.DO.Debug())
}
func (t toolVersionDo) WithContext(ctx context.Context) IToolVersionDo {
return t.withDO(t.DO.WithContext(ctx))
}
func (t toolVersionDo) ReadDB() IToolVersionDo {
return t.Clauses(dbresolver.Read)
}
func (t toolVersionDo) WriteDB() IToolVersionDo {
return t.Clauses(dbresolver.Write)
}
func (t toolVersionDo) Session(config *gorm.Session) IToolVersionDo {
return t.withDO(t.DO.Session(config))
}
func (t toolVersionDo) Clauses(conds ...clause.Expression) IToolVersionDo {
return t.withDO(t.DO.Clauses(conds...))
}
func (t toolVersionDo) Returning(value interface{}, columns ...string) IToolVersionDo {
return t.withDO(t.DO.Returning(value, columns...))
}
func (t toolVersionDo) Not(conds ...gen.Condition) IToolVersionDo {
return t.withDO(t.DO.Not(conds...))
}
func (t toolVersionDo) Or(conds ...gen.Condition) IToolVersionDo {
return t.withDO(t.DO.Or(conds...))
}
func (t toolVersionDo) Select(conds ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.Select(conds...))
}
func (t toolVersionDo) Where(conds ...gen.Condition) IToolVersionDo {
return t.withDO(t.DO.Where(conds...))
}
func (t toolVersionDo) Order(conds ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.Order(conds...))
}
func (t toolVersionDo) Distinct(cols ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.Distinct(cols...))
}
func (t toolVersionDo) Omit(cols ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.Omit(cols...))
}
func (t toolVersionDo) Join(table schema.Tabler, on ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.Join(table, on...))
}
func (t toolVersionDo) LeftJoin(table schema.Tabler, on ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.LeftJoin(table, on...))
}
func (t toolVersionDo) RightJoin(table schema.Tabler, on ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.RightJoin(table, on...))
}
func (t toolVersionDo) Group(cols ...field.Expr) IToolVersionDo {
return t.withDO(t.DO.Group(cols...))
}
func (t toolVersionDo) Having(conds ...gen.Condition) IToolVersionDo {
return t.withDO(t.DO.Having(conds...))
}
func (t toolVersionDo) Limit(limit int) IToolVersionDo {
return t.withDO(t.DO.Limit(limit))
}
func (t toolVersionDo) Offset(offset int) IToolVersionDo {
return t.withDO(t.DO.Offset(offset))
}
func (t toolVersionDo) Scopes(funcs ...func(gen.Dao) gen.Dao) IToolVersionDo {
return t.withDO(t.DO.Scopes(funcs...))
}
func (t toolVersionDo) Unscoped() IToolVersionDo {
return t.withDO(t.DO.Unscoped())
}
func (t toolVersionDo) Create(values ...*model.ToolVersion) error {
if len(values) == 0 {
return nil
}
return t.DO.Create(values)
}
func (t toolVersionDo) CreateInBatches(values []*model.ToolVersion, batchSize int) error {
return t.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (t toolVersionDo) Save(values ...*model.ToolVersion) error {
if len(values) == 0 {
return nil
}
return t.DO.Save(values)
}
func (t toolVersionDo) First() (*model.ToolVersion, error) {
if result, err := t.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.ToolVersion), nil
}
}
func (t toolVersionDo) Take() (*model.ToolVersion, error) {
if result, err := t.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.ToolVersion), nil
}
}
func (t toolVersionDo) Last() (*model.ToolVersion, error) {
if result, err := t.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.ToolVersion), nil
}
}
func (t toolVersionDo) Find() ([]*model.ToolVersion, error) {
result, err := t.DO.Find()
return result.([]*model.ToolVersion), err
}
func (t toolVersionDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.ToolVersion, err error) {
buf := make([]*model.ToolVersion, 0, batchSize)
err = t.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (t toolVersionDo) FindInBatches(result *[]*model.ToolVersion, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return t.DO.FindInBatches(result, batchSize, fc)
}
func (t toolVersionDo) Attrs(attrs ...field.AssignExpr) IToolVersionDo {
return t.withDO(t.DO.Attrs(attrs...))
}
func (t toolVersionDo) Assign(attrs ...field.AssignExpr) IToolVersionDo {
return t.withDO(t.DO.Assign(attrs...))
}
func (t toolVersionDo) Joins(fields ...field.RelationField) IToolVersionDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Joins(_f))
}
return &t
}
func (t toolVersionDo) Preload(fields ...field.RelationField) IToolVersionDo {
for _, _f := range fields {
t = *t.withDO(t.DO.Preload(_f))
}
return &t
}
func (t toolVersionDo) FirstOrInit() (*model.ToolVersion, error) {
if result, err := t.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.ToolVersion), nil
}
}
func (t toolVersionDo) FirstOrCreate() (*model.ToolVersion, error) {
if result, err := t.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.ToolVersion), nil
}
}
func (t toolVersionDo) FindByPage(offset int, limit int) (result []*model.ToolVersion, count int64, err error) {
result, err = t.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = t.Offset(-1).Limit(-1).Count()
return
}
func (t toolVersionDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = t.Count()
if err != nil {
return
}
err = t.Offset(offset).Limit(limit).Scan(result)
return
}
func (t toolVersionDo) Scan(result interface{}) (err error) {
return t.DO.Scan(result)
}
func (t toolVersionDo) Delete(models ...*model.ToolVersion) (result gen.ResultInfo, err error) {
return t.DO.Delete(models)
}
func (t *toolVersionDo) withDO(do gen.Dao) *toolVersionDo {
t.DO = *do.(*gen.DO)
return t
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"errors"
"fmt"
"gorm.io/gen/field"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewToolDAO(db *gorm.DB, idGen idgen.IDGenerator) *ToolDAO {
return &ToolDAO{
idGen: idGen,
query: query.Use(db),
}
}
type ToolDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type toolPO model.Tool
func (t toolPO) ToDO() *entity.ToolInfo {
return &entity.ToolInfo{
ID: t.ID,
PluginID: t.PluginID,
CreatedAt: t.CreatedAt,
UpdatedAt: t.UpdatedAt,
Version: &t.Version,
SubURL: &t.SubURL,
Method: ptr.Of(t.Method),
Operation: t.Operation,
ActivatedStatus: ptr.Of(plugin.ActivatedStatus(t.ActivatedStatus)),
}
}
func (t *ToolDAO) getSelected(opt *ToolSelectedOption) (selected []field.Expr) {
if opt == nil {
return selected
}
table := t.query.Tool
if opt.ToolID {
selected = append(selected, table.ID)
}
if opt.ActivatedStatus {
selected = append(selected, table.ActivatedStatus)
}
if opt.ToolMethod {
selected = append(selected, table.Method)
}
if opt.ToolSubURL {
selected = append(selected, table.SubURL)
}
return selected
}
func (t *ToolDAO) Get(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
table := t.query.Tool
tl, err := table.WithContext(ctx).
Where(table.ID.Eq(toolID)).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
tool = toolPO(*tl).ToDO()
return tool, true, nil
}
func (t *ToolDAO) MGet(ctx context.Context, toolIDs []int64, opt *ToolSelectedOption) (tools []*entity.ToolInfo, err error) {
tools = make([]*entity.ToolInfo, 0, len(toolIDs))
table := t.query.Tool
chunks := slices.Chunks(toolIDs, 20)
for _, chunk := range chunks {
tls, err := table.WithContext(ctx).
Select(t.getSelected(opt)...).
Where(table.ID.In(chunk...)).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, toolPO(*tl).ToDO())
}
}
return tools, nil
}
func (t *ToolDAO) GetAll(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error) {
const limit = 20
table := t.query.Tool
cursor := int64(0)
for {
tls, err := table.WithContext(ctx).
Where(
table.PluginID.Eq(pluginID),
table.ID.Gt(cursor),
).
Order(table.ID.Asc()).
Limit(limit).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, toolPO(*tl).ToDO())
}
if len(tls) < limit {
break
}
cursor = tls[len(tls)-1].ID
}
return tools, nil
}
func (t *ToolDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx, tools []*entity.ToolInfo) (err error) {
tls := make([]*model.Tool, 0, len(tools))
for _, tool := range tools {
if tool.GetVersion() == "" {
return fmt.Errorf("invalid tool version")
}
tls = append(tls, &model.Tool{
ID: tool.ID,
PluginID: tool.PluginID,
Version: tool.GetVersion(),
SubURL: tool.GetSubURL(),
Method: tool.GetMethod(),
ActivatedStatus: int32(tool.GetActivatedStatus()),
Operation: tool.Operation,
})
}
err = tx.Tool.WithContext(ctx).CreateInBatches(tls, 10)
if err != nil {
return err
}
return nil
}
func (t *ToolDAO) DeleteAllWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {
const limit = 20
table := tx.Tool
for {
info, err := table.WithContext(ctx).
Where(table.PluginID.Eq(pluginID)).
Limit(limit).
Delete()
if err != nil {
return err
}
if info.RowsAffected < limit {
break
}
}
return nil
}

View File

@@ -0,0 +1,466 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"encoding/json"
"errors"
"fmt"
"gorm.io/gen/field"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewToolDraftDAO(db *gorm.DB, idGen idgen.IDGenerator) *ToolDraftDAO {
return &ToolDraftDAO{
idGen: idGen,
query: query.Use(db),
}
}
type ToolDraftDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type toolDraftPO model.ToolDraft
func (t toolDraftPO) ToDO() *entity.ToolInfo {
return &entity.ToolInfo{
ID: t.ID,
PluginID: t.PluginID,
CreatedAt: t.CreatedAt,
UpdatedAt: t.UpdatedAt,
SubURL: &t.SubURL,
Method: ptr.Of(t.Method),
Operation: t.Operation,
DebugStatus: ptr.Of(common.APIDebugStatus(t.DebugStatus)),
ActivatedStatus: ptr.Of(plugin.ActivatedStatus(t.ActivatedStatus)),
}
}
func (t *ToolDraftDAO) getSelected(opt *ToolSelectedOption) (selected []field.Expr) {
if opt == nil {
return selected
}
table := t.query.ToolDraft
if opt.ToolID {
selected = append(selected, table.ID)
}
if opt.ActivatedStatus {
selected = append(selected, table.ActivatedStatus)
}
if opt.DebugStatus {
selected = append(selected, table.DebugStatus)
}
if opt.ToolMethod {
selected = append(selected, table.Method)
}
if opt.ToolSubURL {
selected = append(selected, table.SubURL)
}
return selected
}
func (t *ToolDraftDAO) Create(ctx context.Context, tool *entity.ToolInfo) (toolID int64, err error) {
id, err := t.idGen.GenID(ctx)
if err != nil {
return 0, err
}
err = t.query.ToolDraft.WithContext(ctx).Create(&model.ToolDraft{
ID: id,
PluginID: tool.PluginID,
SubURL: tool.GetSubURL(),
Method: tool.GetMethod(),
ActivatedStatus: int32(tool.GetActivatedStatus()),
DebugStatus: int32(tool.GetDebugStatus()),
Operation: tool.Operation,
})
if err != nil {
return 0, err
}
return id, nil
}
func (t *ToolDraftDAO) Get(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
table := t.query.ToolDraft
tl, err := table.WithContext(ctx).
Where(table.ID.Eq(toolID)).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
tool = toolDraftPO(*tl).ToDO()
return tool, true, nil
}
func (t *ToolDraftDAO) MGet(ctx context.Context, toolIDs []int64, opt *ToolSelectedOption) (tools []*entity.ToolInfo, err error) {
tools = make([]*entity.ToolInfo, 0, len(toolIDs))
table := t.query.ToolDraft
chunks := slices.Chunks(toolIDs, 10)
for _, chunk := range chunks {
tls, err := table.WithContext(ctx).
Select(t.getSelected(opt)...).
Where(table.ID.In(chunk...)).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, toolDraftPO(*tl).ToDO())
}
}
return tools, nil
}
func (t *ToolDraftDAO) GetWithAPI(ctx context.Context, pluginID int64, api entity.UniqueToolAPI) (tool *entity.ToolInfo, exist bool, err error) {
table := t.query.ToolDraft
tl, err := table.WithContext(ctx).
Where(
table.PluginID.Eq(pluginID),
table.SubURL.Eq(api.SubURL),
table.Method.Eq(api.Method),
).
First()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
}
return nil, false, err
}
tool = toolDraftPO(*tl).ToDO()
return tool, true, nil
}
func (t *ToolDraftDAO) MGetWithAPIs(ctx context.Context, pluginID int64, apis []entity.UniqueToolAPI, opt *ToolSelectedOption) (tools map[entity.UniqueToolAPI]*entity.ToolInfo, err error) {
tools = make(map[entity.UniqueToolAPI]*entity.ToolInfo, len(apis))
table := t.query.ToolDraft
chunks := slices.Chunks(apis, 10)
for _, chunk := range chunks {
sq := table.Where(
table.Where(
table.SubURL.Eq(chunk[0].SubURL),
table.Method.Eq(chunk[0].Method),
),
)
for i, api := range chunk {
if i == 0 {
continue
}
sq = sq.Or(
table.SubURL.Eq(api.SubURL),
table.Method.Eq(api.Method),
)
}
tls, err := table.WithContext(ctx).
Select(t.getSelected(opt)...).
Where(table.PluginID.Eq(pluginID)).
Where(sq).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
api := entity.UniqueToolAPI{
SubURL: tl.SubURL,
Method: tl.Method,
}
tools[api] = toolDraftPO(*tl).ToDO()
}
}
return tools, nil
}
func (t *ToolDraftDAO) GetAll(ctx context.Context, pluginID int64, opt *ToolSelectedOption) (tools []*entity.ToolInfo, err error) {
const limit = 20
table := t.query.ToolDraft
cursor := int64(0)
for {
tls, err := table.WithContext(ctx).
Select(t.getSelected(opt)...).
Where(
table.PluginID.Eq(pluginID),
table.ID.Gt(cursor),
).
Order(table.ID.Asc()).
Limit(limit).
Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, toolDraftPO(*tl).ToDO())
}
if len(tls) < limit {
break
}
cursor = tls[len(tls)-1].ID
}
return tools, nil
}
func (t *ToolDraftDAO) Delete(ctx context.Context, toolID int64) (err error) {
table := t.query.ToolDraft
_, err = table.WithContext(ctx).
Where(table.ID.Eq(toolID)).
Delete()
if err != nil {
return err
}
return nil
}
func (t *ToolDraftDAO) Update(ctx context.Context, tool *entity.ToolInfo) (err error) {
m, err := t.getToolDraftUpdateMap(tool)
if err != nil {
return err
}
table := t.query.ToolDraft
_, err = table.WithContext(ctx).
Where(table.ID.Eq(tool.ID)).
Updates(m)
if err != nil {
return err
}
return nil
}
func (t *ToolDraftDAO) List(ctx context.Context, pluginID int64, pageInfo entity.PageInfo) (tools []*entity.ToolInfo, total int64, err error) {
if pageInfo.SortBy == nil || pageInfo.OrderByACS == nil {
return nil, 0, fmt.Errorf("sortBy or orderByACS is empty")
}
if *pageInfo.SortBy != entity.SortByCreatedAt {
return nil, 0, fmt.Errorf("invalid sortBy '%v'", *pageInfo.SortBy)
}
table := t.query.ToolDraft
var orderExpr field.Expr
if *pageInfo.OrderByACS {
orderExpr = table.CreatedAt.Asc()
} else {
orderExpr = table.CreatedAt.Desc()
}
offset := (pageInfo.Page - 1) * pageInfo.Size
tls, total, err := table.WithContext(ctx).
Where(table.PluginID.Eq(pluginID)).
Order(orderExpr).
FindByPage(offset, pageInfo.Size)
if err != nil {
return nil, 0, err
}
tools = make([]*entity.ToolInfo, 0, len(tls))
for _, tl := range tls {
tools = append(tools, toolDraftPO(*tl).ToDO())
}
return tools, total, nil
}
func (t *ToolDraftDAO) DeleteAllWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {
const limit = 20
table := tx.ToolDraft
for {
info, err := table.WithContext(ctx).
Where(table.PluginID.Eq(pluginID)).
Limit(limit).
Delete()
if err != nil {
return err
}
if info.RowsAffected < limit {
break
}
}
return nil
}
func (t *ToolDraftDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx, tools []*entity.ToolInfo) (toolIDs []int64, err error) {
toolIDs = make([]int64, 0, len(tools))
tls := make([]*model.ToolDraft, 0, len(tools))
for _, tool := range tools {
id, err := t.idGen.GenID(ctx)
if err != nil {
return nil, err
}
toolIDs = append(toolIDs, id)
tls = append(tls, &model.ToolDraft{
ID: id,
PluginID: tool.PluginID,
SubURL: tool.GetSubURL(),
Method: tool.GetMethod(),
ActivatedStatus: int32(tool.GetActivatedStatus()),
DebugStatus: int32(tool.GetDebugStatus()),
Operation: tool.Operation,
})
}
table := tx.ToolDraft
err = table.CreateInBatches(tls, 10)
if err != nil {
return nil, err
}
return toolIDs, nil
}
func (t *ToolDraftDAO) BatchUpdateWithTX(ctx context.Context, tx *query.QueryTx, tools []*entity.ToolInfo) (err error) {
for _, tool := range tools {
m, err := t.getToolDraftUpdateMap(tool)
if err != nil {
return err
}
table := tx.ToolDraft
_, err = table.WithContext(ctx).
Where(table.ID.Eq(tool.ID)).
Updates(m)
if err != nil {
return err
}
}
return nil
}
func (t *ToolDraftDAO) UpdateWithTX(ctx context.Context, tx *query.QueryTx, tool *entity.ToolInfo) (err error) {
m, err := t.getToolDraftUpdateMap(tool)
if err != nil {
return err
}
table := tx.ToolDraft
_, err = table.Debug().WithContext(ctx).
Where(table.ID.Eq(tool.ID)).
Updates(m)
if err != nil {
return err
}
return nil
}
func (t *ToolDraftDAO) ResetAllDebugStatusWithTX(ctx context.Context, tx *query.QueryTx, pluginID int64) (err error) {
const limit = 50
table := tx.ToolDraft
lastID := int64(0)
for {
var toolIDs []int64
err = table.WithContext(ctx).
Where(table.PluginID.Eq(pluginID)).
Where(table.ID.Gt(lastID)).
Order(table.ID.Asc()).
Limit(limit).
Pluck(table.ID, &toolIDs)
if err != nil {
return err
}
if len(toolIDs) == 0 {
break
}
_, err = table.WithContext(ctx).
Where(table.ID.In(toolIDs...)).
Updates(map[string]any{
table.DebugStatus.ColumnName().String(): int32(common.APIDebugStatus_DebugWaiting),
})
if err != nil {
return err
}
lastID = toolIDs[len(toolIDs)-1]
if len(toolIDs) < limit {
break
}
}
return nil
}
func (t *ToolDraftDAO) getToolDraftUpdateMap(tool *entity.ToolInfo) (map[string]any, error) {
table := t.query.ToolDraft
updateMap := map[string]any{}
if tool.Operation != nil {
b, err := json.Marshal(tool.Operation)
if err != nil {
return nil, err
}
updateMap[table.Operation.ColumnName().String()] = b
}
if tool.SubURL != nil {
updateMap[table.SubURL.ColumnName().String()] = *tool.SubURL
}
if tool.Method != nil {
updateMap[table.Method.ColumnName().String()] = *tool.Method
}
if tool.ActivatedStatus != nil {
updateMap[table.ActivatedStatus.ColumnName().String()] = int32(*tool.ActivatedStatus)
}
if tool.DebugStatus != nil {
updateMap[table.DebugStatus.ColumnName().String()] = int32(*tool.DebugStatus)
}
return updateMap, nil
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dal
import (
"context"
"fmt"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/model"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
)
func NewToolVersionDAO(db *gorm.DB, idGen idgen.IDGenerator) *ToolVersionDAO {
return &ToolVersionDAO{
idGen: idGen,
query: query.Use(db),
}
}
type ToolVersionDAO struct {
idGen idgen.IDGenerator
query *query.Query
}
type toolVersionPO model.ToolVersion
func (t toolVersionPO) ToDO() *entity.ToolInfo {
return &entity.ToolInfo{
ID: t.ToolID,
PluginID: t.PluginID,
CreatedAt: t.CreatedAt,
Version: &t.Version,
SubURL: &t.SubURL,
Method: ptr.Of(t.Method),
Operation: t.Operation,
}
}
func (t *ToolVersionDAO) Get(ctx context.Context, vTool entity.VersionTool) (tool *entity.ToolInfo, exist bool, err error) {
table := t.query.ToolVersion
if vTool.Version == "" {
return nil, false, fmt.Errorf("invalid tool version")
}
tl, err := table.WithContext(ctx).
Where(
table.ToolID.Eq(vTool.ToolID),
table.Version.Eq(vTool.Version),
).
First()
if err != nil {
return nil, false, err
}
tool = toolVersionPO(*tl).ToDO()
return tool, true, nil
}
func (t *ToolVersionDAO) MGet(ctx context.Context, vTools []entity.VersionTool) (tools []*entity.ToolInfo, err error) {
tools = make([]*entity.ToolInfo, 0, len(vTools))
table := t.query.ToolVersion
chunks := slices.Chunks(vTools, 10)
for _, chunk := range chunks {
q := table.WithContext(ctx).
Where(
table.Where(
table.ToolID.Eq(chunk[0].ToolID),
table.Version.Eq(chunk[0].Version),
),
)
for i, v := range chunk {
if i == 0 {
continue
}
q = q.Or(
table.ToolID.Eq(v.ToolID),
table.Version.Eq(v.Version),
)
}
tls, err := q.Find()
if err != nil {
return nil, err
}
for _, tl := range tls {
tools = append(tools, toolVersionPO(*tl).ToDO())
}
}
return tools, nil
}
func (t *ToolVersionDAO) BatchCreateWithTX(ctx context.Context, tx *query.QueryTx, tools []*entity.ToolInfo) (err error) {
tls := make([]*model.ToolVersion, 0, len(tools))
for _, tool := range tools {
if tool.GetVersion() == "" {
return fmt.Errorf("invalid tool version")
}
id, err := t.idGen.GenID(ctx)
if err != nil {
return err
}
tls = append(tls, &model.ToolVersion{
ID: id,
ToolID: tool.ID,
PluginID: tool.PluginID,
Version: tool.GetVersion(),
SubURL: tool.GetSubURL(),
Method: tool.GetMethod(),
Operation: tool.Operation,
})
}
err = tx.ToolVersion.WithContext(ctx).CreateInBatches(tls, 10)
if err != nil {
return err
}
return nil
}
func (t *ToolVersionDAO) DeleteWithTX(ctx context.Context, tx *query.QueryTx, toolID int64) (err error) {
table := tx.ToolVersion
_, err = table.WithContext(ctx).
Where(table.ToolID.Eq(toolID)).
Delete()
return err
}

View File

@@ -0,0 +1,379 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package encoder
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"github.com/bytedance/sonic"
"github.com/getkin/kin-openapi/openapi3"
"github.com/shopspring/decimal"
"gopkg.in/yaml.v3"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
)
func EncodeBodyWithContentType(contentType string, body map[string]any) ([]byte, error) {
switch contentType {
case plugin.MediaTypeJson, plugin.MediaTypeProblemJson:
return jsonBodyEncoder(body)
case plugin.MediaTypeFormURLEncoded:
return urlencodedBodyEncoder(body)
case plugin.MediaTypeYaml, plugin.MediaTypeXYaml:
return yamlBodyEncoder(body)
default:
return nil, fmt.Errorf("[EncodeBodyWithContentType] unsupported contentType=%s", contentType)
}
}
func jsonBodyEncoder(body map[string]any) ([]byte, error) {
b, err := sonic.Marshal(body)
if err != nil {
return nil, fmt.Errorf("[jsonBodyEncoder] failed to marshal body, err=%v", err)
}
return b, nil
}
func yamlBodyEncoder(body map[string]any) ([]byte, error) {
b, err := yaml.Marshal(body)
if err != nil {
return nil, fmt.Errorf("[yamlBodyEncoder] failed to marshal body, err=%v", err)
}
return b, nil
}
func urlencodedBodyEncoder(body map[string]any) ([]byte, error) {
objectStr := ""
res := url.Values{}
sm := &openapi3.SerializationMethod{
Style: openapi3.SerializationForm,
Explode: true,
}
for k, value := range body {
switch val := value.(type) {
case map[string]any:
vStr, err := encodeObjectParam(sm, k, val)
if err != nil {
return nil, err
}
if len(objectStr) > 0 {
vStr = "&" + vStr
}
objectStr += vStr
case []any:
vStr, err := encodeArrayParam(sm, k, val)
if err != nil {
return nil, err
}
if len(objectStr) > 0 {
vStr = "&" + vStr
}
objectStr += vStr
case string:
res.Add(k, val)
default:
res.Add(k, MustString(val))
}
}
if len(objectStr) > 0 {
return []byte(res.Encode() + "&" + url.QueryEscape(objectStr)), nil
}
return []byte(res.Encode()), nil
}
func EncodeParameter(param *openapi3.Parameter, value any) (string, error) {
sm, err := param.SerializationMethod()
if err != nil {
return "", err
}
switch v := value.(type) {
case map[string]any:
return encodeObjectParam(sm, param.Name, v)
case []any:
return encodeArrayParam(sm, param.Name, v)
default:
return encodePrimitiveParam(sm, param.Name, v)
}
}
func encodePrimitiveParam(sm *openapi3.SerializationMethod, paramName string, val any) (string, error) {
var prefix string
switch sm.Style {
case openapi3.SerializationSimple:
// A prefix is empty for style "simple".
case openapi3.SerializationLabel:
prefix = "."
case openapi3.SerializationMatrix:
prefix = ";" + url.QueryEscape(paramName) + "="
case openapi3.SerializationForm:
result := url.QueryEscape(paramName) + "=" + url.QueryEscape(MustString(val))
return result, nil
default:
return "", fmt.Errorf("invalid serialization method: style=%q, explode=%v", sm.Style, sm.Explode)
}
raw := MustString(val)
return prefix + raw, nil
}
func encodeArrayParam(sm *openapi3.SerializationMethod, paramName string, arrVal []any) (string, error) {
var prefix, delim string
switch {
case sm.Style == openapi3.SerializationMatrix && !sm.Explode:
prefix = ";" + paramName + "="
delim = ","
case sm.Style == openapi3.SerializationMatrix && sm.Explode:
prefix = ";" + paramName + "="
delim = ";" + paramName + "="
case sm.Style == openapi3.SerializationLabel && !sm.Explode:
prefix = "."
delim = ","
case sm.Style == openapi3.SerializationLabel && sm.Explode:
prefix = "."
delim = "."
case sm.Style == openapi3.SerializationForm && sm.Explode:
prefix = paramName + "="
delim = "&" + paramName + "="
case sm.Style == openapi3.SerializationForm && !sm.Explode:
prefix = paramName + "="
delim = ","
case sm.Style == openapi3.SerializationSimple:
delim = ","
case sm.Style == openapi3.SerializationSpaceDelimited && !sm.Explode:
delim = ","
case sm.Style == openapi3.SerializationPipeDelimited && !sm.Explode:
delim = "|"
default:
return "", fmt.Errorf("invalid serialization method: style=%q, explode=%v", sm.Style, sm.Explode)
}
res := prefix
for i, val := range arrVal {
vStr := MustString(val)
res += vStr
if i != len(arrVal)-1 {
res += delim
}
}
return res, nil
}
func encodeObjectParam(sm *openapi3.SerializationMethod, paramName string, mapVal map[string]any) (string, error) {
var prefix, propsDelim, valueDelim string
switch {
case sm.Style == openapi3.SerializationSimple && !sm.Explode:
propsDelim = ","
valueDelim = ","
case sm.Style == openapi3.SerializationSimple && sm.Explode:
propsDelim = ","
valueDelim = "="
case sm.Style == openapi3.SerializationLabel && !sm.Explode:
prefix = "."
propsDelim = "."
valueDelim = "."
case sm.Style == openapi3.SerializationLabel && sm.Explode:
prefix = "."
propsDelim = "."
valueDelim = "="
case sm.Style == openapi3.SerializationMatrix && !sm.Explode:
prefix = ";" + paramName + "="
propsDelim = ","
valueDelim = ","
case sm.Style == openapi3.SerializationMatrix && sm.Explode:
prefix = ";"
propsDelim = ";"
valueDelim = "="
case sm.Style == openapi3.SerializationForm && !sm.Explode:
prefix = paramName + "="
propsDelim = ","
valueDelim = ","
case sm.Style == openapi3.SerializationForm && sm.Explode:
propsDelim = "&"
valueDelim = "="
case sm.Style == openapi3.SerializationSpaceDelimited && !sm.Explode:
propsDelim = " "
valueDelim = " "
case sm.Style == openapi3.SerializationPipeDelimited && !sm.Explode:
propsDelim = "|"
valueDelim = "|"
case sm.Style == openapi3.SerializationDeepObject && sm.Explode:
prefix = paramName + "["
propsDelim = "&color["
valueDelim = "]="
default:
return "", fmt.Errorf("invalid serialization method: style=%s, explode=%t", sm.Style, sm.Explode)
}
res := prefix
for k, val := range mapVal {
vStr := MustString(val)
res += k + valueDelim + vStr + propsDelim
}
if len(mapVal) > 0 && len(res) > 0 {
res = res[:len(res)-1]
}
return res, nil
}
func MustString(value any) string {
if value == nil {
return ""
}
switch val := value.(type) {
case string:
return val
default:
b, _ := json.Marshal(val)
return string(b)
}
}
func TryFixValueType(paramName string, schemaRef *openapi3.SchemaRef, value any) (any, error) {
if value == nil {
return "", fmt.Errorf("value of '%s' is nil", paramName)
}
switch schemaRef.Value.Type {
case openapi3.TypeString:
return tryString(value)
case openapi3.TypeNumber:
return tryFloat64(value)
case openapi3.TypeInteger:
return tryInt64(value)
case openapi3.TypeBoolean:
return tryBool(value)
case openapi3.TypeArray:
arrVal, ok := value.([]any)
if !ok {
return nil, fmt.Errorf("[TryFixValueType] value '%s' is not array", paramName)
}
for i, v := range arrVal {
_v, err := TryFixValueType(paramName, schemaRef.Value.Items, v)
if err != nil {
return nil, err
}
arrVal[i] = _v
}
return arrVal, nil
case openapi3.TypeObject:
mapVal, ok := value.(map[string]any)
if !ok {
return nil, fmt.Errorf("[TryFixValueType] value '%s' is not object", paramName)
}
for k, v := range mapVal {
p, ok := schemaRef.Value.Properties[k]
if !ok {
continue
}
_v, err := TryFixValueType(k, p, v)
if err != nil {
return nil, err
}
mapVal[k] = _v
}
return mapVal, nil
default:
return nil, fmt.Errorf("[TryFixValueType] unsupported schema type '%s'", schemaRef.Value.Type)
}
}
func tryString(value any) (string, error) {
switch val := value.(type) {
case string:
return val, nil
case int64:
return strconv.FormatInt(val, 10), nil
case float64:
d := decimal.NewFromFloat(val)
return d.String(), nil
case json.Number:
return val.String(), nil
default:
return "", fmt.Errorf("cannot convert type from '%T' to string", val)
}
}
func tryInt64(value any) (int64, error) {
switch val := value.(type) {
case string:
vi64, _ := strconv.ParseInt(val, 10, 64)
return vi64, nil
case int64:
return val, nil
case float64:
return int64(val), nil
case json.Number:
vi64, _ := strconv.ParseInt(val.String(), 10, 64)
return vi64, nil
default:
return 0, fmt.Errorf("cannot convert type from '%T' to int64", val)
}
}
func tryBool(value any) (bool, error) {
switch val := value.(type) {
case string:
return strconv.ParseBool(val)
case bool:
return val, nil
default:
return false, fmt.Errorf("cannot convert type from '%T' to bool", val)
}
}
func tryFloat64(value any) (float64, error) {
switch val := value.(type) {
case string:
return strconv.ParseFloat(val, 64)
case float64:
return val, nil
case int64:
return float64(val), nil
case json.Number:
return strconv.ParseFloat(val.String(), 64)
default:
return 0, fmt.Errorf("cannot convert type from '%T' to float64", val)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"context"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
)
type OAuthRepoComponents struct {
IDGen idgen.IDGenerator
DB *gorm.DB
}
func NewOAuthRepo(components *OAuthRepoComponents) OAuthRepository {
return &oauthRepoImpl{
oauthAuth: dal.NewPluginOAuthAuthDAO(components.DB, components.IDGen),
}
}
type oauthRepoImpl struct {
oauthAuth *dal.PluginOAuthAuthDAO
}
func (o *oauthRepoImpl) GetAuthorizationCode(ctx context.Context, meta *entity.AuthorizationCodeMeta) (info *entity.AuthorizationCodeInfo, exist bool, err error) {
return o.oauthAuth.Get(ctx, meta)
}
func (o *oauthRepoImpl) UpsertAuthorizationCode(ctx context.Context, info *entity.AuthorizationCodeInfo) (err error) {
return o.oauthAuth.Upsert(ctx, info)
}
func (o *oauthRepoImpl) UpdateAuthorizationCodeLastActiveAt(ctx context.Context, meta *entity.AuthorizationCodeMeta, lastActiveAtMs int64) (err error) {
return o.oauthAuth.UpdateLastActiveAt(ctx, meta, lastActiveAtMs)
}
func (o *oauthRepoImpl) BatchDeleteAuthorizationCodeByIDs(ctx context.Context, ids []int64) (err error) {
return o.oauthAuth.BatchDeleteByIDs(ctx, ids)
}
func (o *oauthRepoImpl) DeleteAuthorizationCode(ctx context.Context, meta *entity.AuthorizationCodeMeta) (err error) {
return o.oauthAuth.Delete(ctx, meta)
}
func (o *oauthRepoImpl) GetAuthorizationCodeRefreshTokens(ctx context.Context, nextRefreshAt int64, limit int) (infos []*entity.AuthorizationCodeInfo, err error) {
return o.oauthAuth.GetRefreshTokenList(ctx, nextRefreshAt, limit)
}
func (o *oauthRepoImpl) DeleteExpiredAuthorizationCodeTokens(ctx context.Context, expireAt int64, limit int) (err error) {
return o.oauthAuth.DeleteExpiredTokens(ctx, expireAt, limit)
}
func (o *oauthRepoImpl) DeleteInactiveAuthorizationCodeTokens(ctx context.Context, lastActiveAt int64, limit int) (err error) {
return o.oauthAuth.DeleteInactiveTokens(ctx, lastActiveAt, limit)
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"context"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
)
type OAuthRepository interface {
GetAuthorizationCode(ctx context.Context, meta *entity.AuthorizationCodeMeta) (info *entity.AuthorizationCodeInfo, exist bool, err error)
UpsertAuthorizationCode(ctx context.Context, info *entity.AuthorizationCodeInfo) (err error)
UpdateAuthorizationCodeLastActiveAt(ctx context.Context, meta *entity.AuthorizationCodeMeta, lastActiveAtMs int64) (err error)
BatchDeleteAuthorizationCodeByIDs(ctx context.Context, ids []int64) (err error)
DeleteAuthorizationCode(ctx context.Context, meta *entity.AuthorizationCodeMeta) (err error)
GetAuthorizationCodeRefreshTokens(ctx context.Context, nextRefreshAt int64, limit int) (infos []*entity.AuthorizationCodeInfo, err error)
DeleteExpiredAuthorizationCodeTokens(ctx context.Context, expireAt int64, limit int) (err error)
DeleteInactiveAuthorizationCodeTokens(ctx context.Context, lastActiveAt int64, limit int) (err error)
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal"
)
type PluginSelectedOptions func(*dal.PluginSelectedOption)
func WithPluginID() PluginSelectedOptions {
return func(opts *dal.PluginSelectedOption) {
opts.PluginID = true
}
}
func WithPluginOpenapiDoc() PluginSelectedOptions {
return func(opts *dal.PluginSelectedOption) {
opts.OpenapiDoc = true
}
}
func WithPluginManifest() PluginSelectedOptions {
return func(opts *dal.PluginSelectedOption) {
opts.Manifest = true
}
}
func WithPluginIconURI() PluginSelectedOptions {
return func(opts *dal.PluginSelectedOption) {
opts.IconURI = true
}
}
func WithPluginVersion() PluginSelectedOptions {
return func(opts *dal.PluginSelectedOption) {
opts.Version = true
}
}
type ToolSelectedOptions func(option *dal.ToolSelectedOption)
func WithToolID() ToolSelectedOptions {
return func(opts *dal.ToolSelectedOption) {
opts.ToolID = true
}
}
func WithToolMethod() ToolSelectedOptions {
return func(opts *dal.ToolSelectedOption) {
opts.ToolMethod = true
}
}
func WithToolSubURL() ToolSelectedOptions {
return func(opts *dal.ToolSelectedOption) {
opts.ToolSubURL = true
}
}
func WithToolActivatedStatus() ToolSelectedOptions {
return func(opts *dal.ToolSelectedOption) {
opts.ActivatedStatus = true
}
}
func WithToolDebugStatus() ToolSelectedOptions {
return func(opts *dal.ToolSelectedOption) {
opts.DebugStatus = true
}
}

View File

@@ -0,0 +1,855 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"context"
"fmt"
"runtime/debug"
"github.com/getkin/kin-openapi/openapi3"
"github.com/jinzhu/copier"
"gorm.io/gorm"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
type pluginRepoImpl struct {
query *query.Query
pluginDraftDAO *dal.PluginDraftDAO
pluginDAO *dal.PluginDAO
pluginVersionDAO *dal.PluginVersionDAO
toolDraftDAO *dal.ToolDraftDAO
toolDAO *dal.ToolDAO
toolVersionDAO *dal.ToolVersionDAO
}
type PluginRepoComponents struct {
IDGen idgen.IDGenerator
DB *gorm.DB
}
func NewPluginRepo(components *PluginRepoComponents) PluginRepository {
return &pluginRepoImpl{
query: query.Use(components.DB),
pluginDraftDAO: dal.NewPluginDraftDAO(components.DB, components.IDGen),
pluginDAO: dal.NewPluginDAO(components.DB, components.IDGen),
pluginVersionDAO: dal.NewPluginVersionDAO(components.DB, components.IDGen),
toolDraftDAO: dal.NewToolDraftDAO(components.DB, components.IDGen),
toolDAO: dal.NewToolDAO(components.DB, components.IDGen),
toolVersionDAO: dal.NewToolVersionDAO(components.DB, components.IDGen),
}
}
func (p *pluginRepoImpl) CreateDraftPlugin(ctx context.Context, plugin *entity.PluginInfo) (pluginID int64, err error) {
pluginID, err = p.pluginDraftDAO.Create(ctx, plugin)
if err != nil {
return 0, err
}
return pluginID, nil
}
func (p *pluginRepoImpl) GetDraftPlugin(ctx context.Context, pluginID int64, opts ...PluginSelectedOptions) (plugin *entity.PluginInfo, exist bool, err error) {
var opt *dal.PluginSelectedOption
if len(opts) > 0 {
opt = &dal.PluginSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return p.pluginDraftDAO.Get(ctx, pluginID, opt)
}
func (p *pluginRepoImpl) MGetDraftPlugins(ctx context.Context, pluginIDs []int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error) {
var opt *dal.PluginSelectedOption
if len(opts) > 0 {
opt = &dal.PluginSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return p.pluginDraftDAO.MGet(ctx, pluginIDs, opt)
}
func (p *pluginRepoImpl) GetAPPAllDraftPlugins(ctx context.Context, appID int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error) {
var opt *dal.PluginSelectedOption
if len(opts) > 0 {
opt = &dal.PluginSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return p.pluginDraftDAO.GetAPPAllPlugins(ctx, appID, opt)
}
func (p *pluginRepoImpl) ListDraftPlugins(ctx context.Context, req *ListDraftPluginsRequest) (resp *ListDraftPluginsResponse, err error) {
plugins, total, err := p.pluginDraftDAO.List(ctx, req.SpaceID, req.APPID, req.PageInfo)
if err != nil {
return nil, err
}
resp = &ListDraftPluginsResponse{
Plugins: plugins,
Total: total,
}
return resp, nil
}
func (p *pluginRepoImpl) UpdateDraftPlugin(ctx context.Context, plugin *entity.PluginInfo) (err error) {
tx := p.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = p.pluginDraftDAO.UpdateWithTX(ctx, tx, plugin)
if err != nil {
return err
}
err = p.toolDraftDAO.ResetAllDebugStatusWithTX(ctx, tx, plugin.ID)
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func (p *pluginRepoImpl) UpdateDraftPluginWithoutURLChanged(ctx context.Context, plugin *entity.PluginInfo) (err error) {
return p.pluginDraftDAO.Update(ctx, plugin)
}
func (p *pluginRepoImpl) GetOnlinePlugin(ctx context.Context, pluginID int64, opts ...PluginSelectedOptions) (plugin *entity.PluginInfo, exist bool, err error) {
pi, exist := pluginConf.GetPluginProduct(pluginID)
if exist {
return entity.NewPluginInfo(pi.Info), true, nil
}
var opt *dal.PluginSelectedOption
if len(opts) > 0 {
opt = &dal.PluginSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return p.pluginDAO.Get(ctx, pluginID, opt)
}
func (p *pluginRepoImpl) MGetOnlinePlugins(ctx context.Context, pluginIDs []int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error) {
pluginProducts := pluginConf.MGetPluginProducts(pluginIDs)
plugins = slices.Transform(pluginProducts, func(pl *pluginConf.PluginInfo) *entity.PluginInfo {
return entity.NewPluginInfo(pl.Info)
})
productPluginIDs := slices.ToMap(pluginProducts, func(plugin *pluginConf.PluginInfo) (int64, bool) {
return plugin.Info.ID, true
})
customPluginIDs := make([]int64, 0, len(pluginIDs))
for _, id := range pluginIDs {
_, ok := productPluginIDs[id]
if ok {
continue
}
customPluginIDs = append(customPluginIDs, id)
}
var opt *dal.PluginSelectedOption
if len(opts) > 0 {
opt = &dal.PluginSelectedOption{}
for _, o := range opts {
o(opt)
}
}
customPlugins, err := p.pluginDAO.MGet(ctx, customPluginIDs, opt)
if err != nil {
return nil, err
}
plugins = append(plugins, customPlugins...)
return plugins, nil
}
func (p *pluginRepoImpl) ListCustomOnlinePlugins(ctx context.Context, spaceID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error) {
return p.pluginDAO.List(ctx, spaceID, pageInfo)
}
func (p *pluginRepoImpl) GetVersionPlugin(ctx context.Context, vPlugin entity.VersionPlugin) (plugin *entity.PluginInfo, exist bool, err error) {
pi, exist := pluginConf.GetPluginProduct(vPlugin.PluginID)
if exist {
return entity.NewPluginInfo(pi.Info), true, nil
}
return p.pluginVersionDAO.Get(ctx, vPlugin.PluginID, vPlugin.Version)
}
func (p *pluginRepoImpl) MGetVersionPlugins(ctx context.Context, vPlugins []entity.VersionPlugin, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error) {
pluginIDs := make([]int64, 0, len(vPlugins))
for _, vPlugin := range vPlugins {
pluginIDs = append(pluginIDs, vPlugin.PluginID)
}
pluginProducts := pluginConf.MGetPluginProducts(pluginIDs)
plugins = slices.Transform(pluginProducts, func(pl *pluginConf.PluginInfo) *entity.PluginInfo {
return entity.NewPluginInfo(pl.Info)
})
productPluginIDs := slices.ToMap(pluginProducts, func(plugin *pluginConf.PluginInfo) (int64, bool) {
return plugin.Info.ID, true
})
vCustomPlugins := make([]entity.VersionPlugin, 0, len(pluginIDs))
for _, v := range vPlugins {
_, ok := productPluginIDs[v.PluginID]
if ok {
continue
}
vCustomPlugins = append(vCustomPlugins, v)
}
var opt *dal.PluginSelectedOption
if len(opts) > 0 {
opt = &dal.PluginSelectedOption{}
for _, o := range opts {
o(opt)
}
}
customPlugins, err := p.pluginVersionDAO.MGet(ctx, vCustomPlugins, opt)
if err != nil {
return nil, err
}
plugins = append(plugins, customPlugins...)
return plugins, nil
}
func (p *pluginRepoImpl) PublishPlugin(ctx context.Context, draftPlugin *entity.PluginInfo) (err error) {
draftTools, err := p.toolDraftDAO.GetAll(ctx, draftPlugin.ID, nil)
if err != nil {
return err
}
activatedTools := make([]*entity.ToolInfo, 0, len(draftTools))
for _, tool := range draftTools {
if tool.GetActivatedStatus() == model.DeactivateTool {
continue
}
tool.Version = draftPlugin.Version
activatedTools = append(activatedTools, tool)
}
if len(activatedTools) == 0 {
return errorx.New(errno.ErrPluginToolsCheckFailed, errorx.KVf(errno.PluginMsgKey,
"at least one activated tool is required in plugin '%s'", draftPlugin.GetName()))
}
tx := p.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = p.pluginDAO.UpsertWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.pluginVersionDAO.CreateWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.toolDAO.DeleteAllWithTX(ctx, tx, draftPlugin.ID)
if err != nil {
return err
}
err = p.toolDAO.BatchCreateWithTX(ctx, tx, activatedTools)
if err != nil {
return err
}
err = p.toolVersionDAO.BatchCreateWithTX(ctx, tx, activatedTools)
if err != nil {
return err
}
return tx.Commit()
}
func (p *pluginRepoImpl) PublishPlugins(ctx context.Context, draftPlugins []*entity.PluginInfo) (err error) {
draftPluginMap := slices.ToMap(draftPlugins, func(plugin *entity.PluginInfo) (int64, *entity.PluginInfo) {
return plugin.ID, plugin
})
pluginTools := make(map[int64][]*entity.ToolInfo, len(draftPlugins))
for _, draftPlugin := range draftPlugins {
draftTools, err := p.toolDraftDAO.GetAll(ctx, draftPlugin.ID, nil)
if err != nil {
return err
}
activatedTools := make([]*entity.ToolInfo, 0, len(draftTools))
for _, tool := range draftTools {
if tool.GetActivatedStatus() == model.DeactivateTool {
continue
}
if tool.DebugStatus == nil ||
*tool.DebugStatus == common.APIDebugStatus_DebugWaiting {
return errorx.New(errno.ErrPluginToolsCheckFailed, errorx.KVf(errno.PluginMsgKey,
"tool '%s' in plugin '%s' has not debugged yet", tool.GetName(), draftPlugin.GetName()))
}
tool.Version = draftPlugin.Version
activatedTools = append(activatedTools, tool)
}
if len(activatedTools) == 0 {
return errorx.New(errno.ErrPluginToolsCheckFailed, errorx.KVf(errno.PluginMsgKey,
"at least one activated tool is required in plugin '%s'", draftPlugin.GetName()))
}
pluginTools[draftPlugin.ID] = activatedTools
}
tx := p.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
for pluginID, tools := range pluginTools {
draftPlugin := draftPluginMap[pluginID]
err = p.pluginDAO.UpsertWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.pluginVersionDAO.CreateWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.toolDAO.DeleteAllWithTX(ctx, tx, draftPlugin.ID)
if err != nil {
return err
}
err = p.toolDAO.BatchCreateWithTX(ctx, tx, tools)
if err != nil {
return err
}
err = p.toolVersionDAO.BatchCreateWithTX(ctx, tx, tools)
if err != nil {
return err
}
}
return tx.Commit()
}
func (p *pluginRepoImpl) DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error) {
tx := p.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = p.pluginDraftDAO.DeleteWithTX(ctx, tx, pluginID)
if err != nil {
return err
}
err = p.pluginDAO.DeleteWithTX(ctx, tx, pluginID)
if err != nil {
return err
}
err = p.pluginVersionDAO.DeleteWithTX(ctx, tx, pluginID)
if err != nil {
return err
}
err = p.toolDraftDAO.DeleteAllWithTX(ctx, tx, pluginID)
if err != nil {
return err
}
err = p.toolDAO.DeleteAllWithTX(ctx, tx, pluginID)
if err != nil {
return err
}
err = p.toolVersionDAO.DeleteWithTX(ctx, tx, pluginID)
if err != nil {
return err
}
return tx.Commit()
}
func (p *pluginRepoImpl) DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error) {
opt := &dal.PluginSelectedOption{
PluginID: true,
}
plugins, err := p.pluginDraftDAO.GetAPPAllPlugins(ctx, appID, opt)
if err != nil {
return nil, err
}
pluginIDs = slices.Transform(plugins, func(plugin *entity.PluginInfo) int64 {
return plugin.ID
})
tx := p.query.Begin()
if tx.Error != nil {
return nil, tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
for _, id := range pluginIDs {
err = p.pluginDraftDAO.DeleteWithTX(ctx, tx, id)
if err != nil {
return nil, err
}
err = p.pluginDAO.DeleteWithTX(ctx, tx, id)
if err != nil {
return nil, err
}
err = p.pluginVersionDAO.DeleteWithTX(ctx, tx, id)
if err != nil {
return nil, err
}
err = p.toolDraftDAO.DeleteAllWithTX(ctx, tx, id)
if err != nil {
return nil, err
}
err = p.toolDAO.DeleteAllWithTX(ctx, tx, id)
if err != nil {
return nil, err
}
err = p.toolVersionDAO.DeleteWithTX(ctx, tx, id)
if err != nil {
return nil, err
}
}
err = tx.Commit()
if err != nil {
return nil, err
}
return pluginIDs, nil
}
func (p *pluginRepoImpl) UpdateDraftPluginWithCode(ctx context.Context, req *UpdatePluginDraftWithCode) (err error) {
tx := p.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
newDoc := &model.Openapi3T{}
err = copier.CopyWithOption(newDoc, req.OpenapiDoc, copier.Option{DeepCopy: true, IgnoreEmpty: true})
if err != nil {
return err
}
newDoc.Paths = openapi3.Paths{} // reset paths
updatedPlugin := entity.NewPluginInfo(&model.PluginInfo{
ID: req.PluginID,
ServerURL: ptr.Of(req.OpenapiDoc.Servers[0].URL),
Manifest: req.Manifest,
OpenapiDoc: req.OpenapiDoc,
})
err = p.pluginDraftDAO.UpdateWithTX(ctx, tx, updatedPlugin)
if err != nil {
return err
}
for _, tool := range req.UpdatedTools {
err = p.toolDraftDAO.UpdateWithTX(ctx, tx, tool)
if err != nil {
return err
}
}
if len(req.NewDraftTools) > 0 {
_, err = p.toolDraftDAO.BatchCreateWithTX(ctx, tx, req.NewDraftTools)
if err != nil {
return err
}
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}
func (p *pluginRepoImpl) CreateDraftPluginWithCode(ctx context.Context, req *CreateDraftPluginWithCodeRequest) (resp *CreateDraftPluginWithCodeResponse, err error) {
doc := req.OpenapiDoc
mf := req.Manifest
pluginType, _ := model.ToThriftPluginType(mf.API.Type)
pl := entity.NewPluginInfo(&model.PluginInfo{
PluginType: pluginType,
SpaceID: req.SpaceID,
DeveloperID: req.DeveloperID,
APPID: req.ProjectID,
IconURI: ptr.Of(mf.LogoURL),
ServerURL: ptr.Of(doc.Servers[0].URL),
Manifest: mf,
OpenapiDoc: doc,
})
tools := make([]*entity.ToolInfo, 0, len(doc.Paths))
for subURL, pathItem := range doc.Paths {
for method, op := range pathItem.Operations() {
tools = append(tools, &entity.ToolInfo{
ActivatedStatus: ptr.Of(model.ActivateTool),
DebugStatus: ptr.Of(common.APIDebugStatus_DebugWaiting),
SubURL: ptr.Of(subURL),
Method: ptr.Of(method),
Operation: model.NewOpenapi3Operation(op),
})
}
}
tx := p.query.Begin()
if tx.Error != nil {
return nil, tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
pluginID, err := p.pluginDraftDAO.CreateWithTX(ctx, tx, pl)
if err != nil {
return nil, err
}
pl.ID = pluginID
for _, tool := range tools {
tool.PluginID = pluginID
}
_, err = p.toolDraftDAO.BatchCreateWithTX(ctx, tx, tools)
if err != nil {
return nil, err
}
err = tx.Commit()
if err != nil {
return nil, err
}
return &CreateDraftPluginWithCodeResponse{
Plugin: pl,
Tools: tools,
}, nil
}
func (p *pluginRepoImpl) CopyPlugin(ctx context.Context, req *CopyPluginRequest) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
tx := p.query.Begin()
if tx.Error != nil {
return nil, nil, tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
plugin, tools = req.Plugin, req.Tools
newPluginID, err := p.pluginDraftDAO.CreateWithTX(ctx, tx, plugin)
if err != nil {
return nil, nil, err
}
plugin.ID = newPluginID
for _, tool := range tools {
tool.PluginID = newPluginID
}
toolIDs, err := p.toolDraftDAO.BatchCreateWithTX(ctx, tx, tools)
if err != nil {
return nil, nil, err
}
for i, tool := range tools {
tool.ID = toolIDs[i]
}
if plugin.GetVersion() == "" {
err = tx.Commit()
if err != nil {
return nil, nil, err
}
return plugin, tools, nil
}
// publish plugin
filteredTools := make([]*entity.ToolInfo, 0, len(tools))
for _, tool := range tools {
if tool.GetActivatedStatus() == model.DeactivateTool ||
tool.GetDebugStatus() == common.APIDebugStatus_DebugWaiting {
continue
}
filteredTools = append(filteredTools, tool)
}
if len(filteredTools) == 0 {
return nil, nil, fmt.Errorf("at least one activated tool is required in plugin '%d'", plugin.ID)
}
err = p.pluginDAO.UpsertWithTX(ctx, tx, plugin)
if err != nil {
return nil, nil, err
}
err = p.pluginVersionDAO.CreateWithTX(ctx, tx, plugin)
if err != nil {
return nil, nil, err
}
err = p.toolDAO.BatchCreateWithTX(ctx, tx, filteredTools)
if err != nil {
return nil, nil, err
}
err = p.toolVersionDAO.BatchCreateWithTX(ctx, tx, filteredTools)
if err != nil {
return nil, nil, err
}
err = tx.Commit()
if err != nil {
return nil, nil, err
}
return req.Plugin, req.Tools, nil
}
func (p *pluginRepoImpl) MoveAPPPluginToLibrary(ctx context.Context, draftPlugin *entity.PluginInfo,
draftTools []*entity.ToolInfo) (err error) {
tx := p.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = p.pluginDraftDAO.UpdateWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.pluginDAO.DeleteWithTX(ctx, tx, draftPlugin.ID)
if err != nil {
return err
}
err = p.pluginVersionDAO.DeleteWithTX(ctx, tx, draftPlugin.ID)
if err != nil {
return err
}
err = p.toolDAO.DeleteAllWithTX(ctx, tx, draftPlugin.ID)
if err != nil {
return err
}
err = p.toolVersionDAO.DeleteWithTX(ctx, tx, draftPlugin.ID)
if err != nil {
return err
}
// publish plugin
err = p.pluginDAO.UpsertWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.pluginVersionDAO.CreateWithTX(ctx, tx, draftPlugin)
if err != nil {
return err
}
err = p.toolDAO.BatchCreateWithTX(ctx, tx, draftTools)
if err != nil {
return err
}
err = p.toolVersionDAO.BatchCreateWithTX(ctx, tx, draftTools)
if err != nil {
return err
}
err = tx.Commit()
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"context"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
)
type PluginRepository interface {
CreateDraftPlugin(ctx context.Context, plugin *entity.PluginInfo) (pluginID int64, err error)
CreateDraftPluginWithCode(ctx context.Context, req *CreateDraftPluginWithCodeRequest) (resp *CreateDraftPluginWithCodeResponse, err error)
GetDraftPlugin(ctx context.Context, pluginID int64, opts ...PluginSelectedOptions) (plugin *entity.PluginInfo, exist bool, err error)
MGetDraftPlugins(ctx context.Context, pluginIDs []int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error)
GetAPPAllDraftPlugins(ctx context.Context, appID int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error)
ListDraftPlugins(ctx context.Context, req *ListDraftPluginsRequest) (resp *ListDraftPluginsResponse, err error)
UpdateDraftPlugin(ctx context.Context, plugin *entity.PluginInfo) (err error)
UpdateDraftPluginWithoutURLChanged(ctx context.Context, plugin *entity.PluginInfo) (err error)
UpdateDraftPluginWithCode(ctx context.Context, req *UpdatePluginDraftWithCode) (err error)
DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error)
DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error)
GetOnlinePlugin(ctx context.Context, pluginID int64, opts ...PluginSelectedOptions) (plugin *entity.PluginInfo, exist bool, err error)
MGetOnlinePlugins(ctx context.Context, pluginIDs []int64, opts ...PluginSelectedOptions) (plugins []*entity.PluginInfo, err error)
ListCustomOnlinePlugins(ctx context.Context, spaceID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error)
GetVersionPlugin(ctx context.Context, vPlugin entity.VersionPlugin) (plugin *entity.PluginInfo, exist bool, err error)
MGetVersionPlugins(ctx context.Context, vPlugins []entity.VersionPlugin, opts ...PluginSelectedOptions) (plugin []*entity.PluginInfo, err error)
PublishPlugin(ctx context.Context, draftPlugin *entity.PluginInfo) (err error)
PublishPlugins(ctx context.Context, draftPlugins []*entity.PluginInfo) (err error)
CopyPlugin(ctx context.Context, req *CopyPluginRequest) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error)
MoveAPPPluginToLibrary(ctx context.Context, draftPlugin *entity.PluginInfo, draftTools []*entity.ToolInfo) (err error)
}
type UpdatePluginDraftWithCode struct {
PluginID int64
OpenapiDoc *plugin.Openapi3T
Manifest *entity.PluginManifest
UpdatedTools []*entity.ToolInfo
NewDraftTools []*entity.ToolInfo
}
type CreateDraftPluginWithCodeRequest struct {
SpaceID int64
DeveloperID int64
ProjectID *int64
Manifest *entity.PluginManifest
OpenapiDoc *plugin.Openapi3T
}
type CreateDraftPluginWithCodeResponse struct {
Plugin *entity.PluginInfo
Tools []*entity.ToolInfo
}
type ListDraftPluginsRequest struct {
SpaceID int64
APPID int64
PageInfo entity.PageInfo
}
type ListDraftPluginsResponse struct {
Plugins []*entity.PluginInfo
Total int64
}
type CopyPluginRequest struct {
Plugin *entity.PluginInfo
Tools []*entity.ToolInfo
}

View File

@@ -0,0 +1,429 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"context"
"fmt"
"runtime/debug"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/dal/query"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
)
type toolRepoImpl struct {
query *query.Query
pluginDraftDAO *dal.PluginDraftDAO
toolDraftDAO *dal.ToolDraftDAO
toolDAO *dal.ToolDAO
toolVersionDAO *dal.ToolVersionDAO
agentToolDraftDAO *dal.AgentToolDraftDAO
agentToolVersionDAO *dal.AgentToolVersionDAO
}
type ToolRepoComponents struct {
IDGen idgen.IDGenerator
DB *gorm.DB
}
func NewToolRepo(components *ToolRepoComponents) ToolRepository {
return &toolRepoImpl{
query: query.Use(components.DB),
pluginDraftDAO: dal.NewPluginDraftDAO(components.DB, components.IDGen),
toolDraftDAO: dal.NewToolDraftDAO(components.DB, components.IDGen),
toolDAO: dal.NewToolDAO(components.DB, components.IDGen),
toolVersionDAO: dal.NewToolVersionDAO(components.DB, components.IDGen),
agentToolDraftDAO: dal.NewAgentToolDraftDAO(components.DB, components.IDGen),
agentToolVersionDAO: dal.NewAgentToolVersionDAO(components.DB, components.IDGen),
}
}
func (t *toolRepoImpl) CreateDraftTool(ctx context.Context, tool *entity.ToolInfo) (toolID int64, err error) {
return t.toolDraftDAO.Create(ctx, tool)
}
func (t *toolRepoImpl) UpsertDraftTools(ctx context.Context, pluginID int64, tools []*entity.ToolInfo) (err error) {
apis := slices.Transform(tools, func(tool *entity.ToolInfo) entity.UniqueToolAPI {
return entity.UniqueToolAPI{
SubURL: tool.GetSubURL(),
Method: tool.GetMethod(),
}
})
existTools, err := t.toolDraftDAO.MGetWithAPIs(ctx, pluginID, apis, nil)
if err != nil {
return err
}
tx := t.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
createdTools := make([]*entity.ToolInfo, 0, len(tools))
updatedTools := make([]*entity.ToolInfo, 0, len(existTools))
for _, tool := range tools {
existTool, exist := existTools[entity.UniqueToolAPI{
SubURL: tool.GetSubURL(),
Method: tool.GetMethod(),
}]
if !exist {
createdTools = append(createdTools, tool)
continue
}
tool.ID = existTool.ID
updatedTools = append(updatedTools, tool)
}
if len(createdTools) > 0 {
_, err = t.toolDraftDAO.BatchCreateWithTX(ctx, tx, createdTools)
if err != nil {
return err
}
}
if len(updatedTools) > 0 {
err = t.toolDraftDAO.BatchUpdateWithTX(ctx, tx, updatedTools)
if err != nil {
return err
}
}
return tx.Commit()
}
func (t *toolRepoImpl) UpdateDraftTool(ctx context.Context, tool *entity.ToolInfo) (err error) {
return t.toolDraftDAO.Update(ctx, tool)
}
func (t *toolRepoImpl) GetDraftTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
return t.toolDraftDAO.Get(ctx, toolID)
}
func (t *toolRepoImpl) MGetDraftTools(ctx context.Context, toolIDs []int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error) {
var opt *dal.ToolSelectedOption
if len(opts) > 0 {
opt = &dal.ToolSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return t.toolDraftDAO.MGet(ctx, toolIDs, opt)
}
func (t *toolRepoImpl) GetPluginAllDraftTools(ctx context.Context, pluginID int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error) {
var opt *dal.ToolSelectedOption
if len(opts) > 0 {
opt = &dal.ToolSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return t.toolDraftDAO.GetAll(ctx, pluginID, opt)
}
func (t *toolRepoImpl) GetPluginAllOnlineTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error) {
pi, exist := pluginConf.GetPluginProduct(pluginID)
if exist {
tis := pi.GetPluginAllTools()
tools = slices.Transform(tis, func(ti *pluginConf.ToolInfo) *entity.ToolInfo {
return ti.Info
})
return tools, nil
}
tools, err = t.toolDAO.GetAll(ctx, pluginID)
if err != nil {
return nil, err
}
return tools, nil
}
func (t *toolRepoImpl) ListPluginDraftTools(ctx context.Context, pluginID int64, pageInfo entity.PageInfo) (tools []*entity.ToolInfo, total int64, err error) {
return t.toolDraftDAO.List(ctx, pluginID, pageInfo)
}
func (t *toolRepoImpl) GetDraftToolWithAPI(ctx context.Context, pluginID int64, api entity.UniqueToolAPI) (tool *entity.ToolInfo, exist bool, err error) {
return t.toolDraftDAO.GetWithAPI(ctx, pluginID, api)
}
func (t *toolRepoImpl) MGetDraftToolWithAPI(ctx context.Context, pluginID int64, apis []entity.UniqueToolAPI, opts ...ToolSelectedOptions) (tools map[entity.UniqueToolAPI]*entity.ToolInfo, err error) {
var opt *dal.ToolSelectedOption
if len(opts) > 0 {
opt = &dal.ToolSelectedOption{}
for _, o := range opts {
o(opt)
}
}
return t.toolDraftDAO.MGetWithAPIs(ctx, pluginID, apis, opt)
}
func (t *toolRepoImpl) DeleteDraftTool(ctx context.Context, toolID int64) (err error) {
return t.toolDraftDAO.Delete(ctx, toolID)
}
func (t *toolRepoImpl) GetOnlineTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
ti, exist := pluginConf.GetToolProduct(toolID)
if exist {
return ti.Info, true, nil
}
return t.toolDAO.Get(ctx, toolID)
}
func (t *toolRepoImpl) MGetOnlineTools(ctx context.Context, toolIDs []int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error) {
toolProducts := pluginConf.MGetToolProducts(toolIDs)
tools = slices.Transform(toolProducts, func(tool *pluginConf.ToolInfo) *entity.ToolInfo {
return tool.Info
})
productToolIDs := slices.ToMap(toolProducts, func(tool *pluginConf.ToolInfo) (int64, bool) {
return tool.Info.ID, true
})
customToolIDs := make([]int64, 0, len(toolIDs))
for _, id := range toolIDs {
_, ok := productToolIDs[id]
if ok {
continue
}
customToolIDs = append(customToolIDs, id)
}
var opt *dal.ToolSelectedOption
if len(opts) > 0 {
opt = &dal.ToolSelectedOption{}
for _, o := range opts {
o(opt)
}
}
customTools, err := t.toolDAO.MGet(ctx, customToolIDs, opt)
if err != nil {
return nil, err
}
tools = append(tools, customTools...)
return tools, nil
}
func (t *toolRepoImpl) GetVersionTool(ctx context.Context, vTool entity.VersionTool) (tool *entity.ToolInfo, exist bool, err error) {
ti, exist := pluginConf.GetToolProduct(vTool.ToolID)
if exist {
return ti.Info, true, nil
}
return t.toolVersionDAO.Get(ctx, vTool)
}
func (t *toolRepoImpl) MGetVersionTools(ctx context.Context, versionTools []entity.VersionTool) (tools []*entity.ToolInfo, err error) {
tools, err = t.toolVersionDAO.MGet(ctx, versionTools)
if err != nil {
return nil, err
}
return tools, nil
}
func (t *toolRepoImpl) BindDraftAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error) {
onlineTools, err := t.MGetOnlineTools(ctx, toolIDs)
if err != nil {
return err
}
if len(onlineTools) == 0 {
return t.agentToolDraftDAO.DeleteAll(ctx, agentID)
}
tx := t.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = t.agentToolDraftDAO.DeleteAllWithTX(ctx, tx, agentID)
if err != nil {
return err
}
err = t.agentToolDraftDAO.BatchCreateWithTX(ctx, tx, agentID, onlineTools)
if err != nil {
return err
}
return tx.Commit()
}
func (t *toolRepoImpl) GetAgentPluginIDs(ctx context.Context, agentID int64) (pluginIDs []int64, err error) {
return t.agentToolDraftDAO.GetAllPluginIDs(ctx, agentID)
}
func (t *toolRepoImpl) DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error) {
tools, err := t.agentToolDraftDAO.GetAll(ctx, fromAgentID)
if err != nil {
return err
}
if len(tools) == 0 {
return nil
}
tx := t.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = t.agentToolDraftDAO.BatchCreateWithTX(ctx, tx, toAgentID, tools)
if err != nil {
return err
}
return tx.Commit()
}
func (t *toolRepoImpl) GetDraftAgentTool(ctx context.Context, agentID, toolID int64) (tool *entity.ToolInfo, exist bool, err error) {
return t.agentToolDraftDAO.Get(ctx, agentID, toolID)
}
func (t *toolRepoImpl) GetDraftAgentToolWithToolName(ctx context.Context, agentID int64, toolName string) (tool *entity.ToolInfo, exist bool, err error) {
return t.agentToolDraftDAO.GetWithToolName(ctx, agentID, toolName)
}
func (t *toolRepoImpl) MGetDraftAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (tools []*entity.ToolInfo, err error) {
return t.agentToolDraftDAO.MGet(ctx, agentID, toolIDs)
}
func (t *toolRepoImpl) UpdateDraftAgentTool(ctx context.Context, req *UpdateDraftAgentToolRequest) (err error) {
return t.agentToolDraftDAO.UpdateWithToolName(ctx, req.AgentID, req.ToolName, req.Tool)
}
func (t *toolRepoImpl) GetSpaceAllDraftAgentTools(ctx context.Context, agentID int64) (tools []*entity.ToolInfo, err error) {
return t.agentToolDraftDAO.GetAll(ctx, agentID)
}
func (t *toolRepoImpl) GetVersionAgentTool(ctx context.Context, agentID int64, vAgentTool entity.VersionAgentTool) (tool *entity.ToolInfo, exist bool, err error) {
return t.agentToolVersionDAO.Get(ctx, agentID, vAgentTool)
}
func (t *toolRepoImpl) GetVersionAgentToolWithToolName(ctx context.Context, req *GetVersionAgentToolWithToolNameRequest) (tool *entity.ToolInfo, exist bool, err error) {
return t.agentToolVersionDAO.GetWithToolName(ctx, req.AgentID, req.ToolName, req.AgentVersion)
}
func (t *toolRepoImpl) MGetVersionAgentTool(ctx context.Context, agentID int64, vAgentTools []entity.VersionAgentTool) (tools []*entity.ToolInfo, err error) {
return t.agentToolVersionDAO.MGet(ctx, agentID, vAgentTools)
}
func (t *toolRepoImpl) BatchCreateVersionAgentTools(ctx context.Context, agentID int64, agentVersion string, tools []*entity.ToolInfo) (err error) {
return t.agentToolVersionDAO.BatchCreate(ctx, agentID, agentVersion, tools)
}
func (t *toolRepoImpl) UpdateDraftToolAndDebugExample(ctx context.Context, pluginID int64, doc *plugin.Openapi3T, updatedTool *entity.ToolInfo) (err error) {
tx := t.query.Begin()
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
err = fmt.Errorf("catch panic: %v\nstack=%s", r, string(debug.Stack()))
return
}
if err != nil {
if e := tx.Rollback(); e != nil {
logs.CtxErrorf(ctx, "rollback failed, err=%v", e)
}
}
}()
err = t.toolDraftDAO.UpdateWithTX(ctx, tx, updatedTool)
if err != nil {
return err
}
updatedPlugin := entity.NewPluginInfo(&plugin.PluginInfo{
ID: pluginID,
OpenapiDoc: doc,
})
err = t.pluginDraftDAO.UpdateWithTX(ctx, tx, updatedPlugin)
if err != nil {
return err
}
return tx.Commit()
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package repository
import (
"context"
"github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
)
type ToolRepository interface {
CreateDraftTool(ctx context.Context, tool *entity.ToolInfo) (toolID int64, err error)
UpsertDraftTools(ctx context.Context, pluginID int64, tools []*entity.ToolInfo) (err error)
UpdateDraftTool(ctx context.Context, tool *entity.ToolInfo) (err error)
GetDraftTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error)
MGetDraftTools(ctx context.Context, toolIDs []int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error)
GetDraftToolWithAPI(ctx context.Context, pluginID int64, api entity.UniqueToolAPI) (tool *entity.ToolInfo, exist bool, err error)
MGetDraftToolWithAPI(ctx context.Context, pluginID int64, apis []entity.UniqueToolAPI, opts ...ToolSelectedOptions) (tools map[entity.UniqueToolAPI]*entity.ToolInfo, err error)
DeleteDraftTool(ctx context.Context, toolID int64) (err error)
GetOnlineTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, exist bool, err error)
MGetOnlineTools(ctx context.Context, toolIDs []int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error)
GetVersionTool(ctx context.Context, vTool entity.VersionTool) (tool *entity.ToolInfo, exist bool, err error)
MGetVersionTools(ctx context.Context, vTools []entity.VersionTool) (tools []*entity.ToolInfo, err error)
BindDraftAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error)
DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error)
GetDraftAgentTool(ctx context.Context, agentID, toolID int64) (tool *entity.ToolInfo, exist bool, err error)
GetDraftAgentToolWithToolName(ctx context.Context, agentID int64, toolName string) (tool *entity.ToolInfo, exist bool, err error)
MGetDraftAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (tools []*entity.ToolInfo, err error)
UpdateDraftAgentTool(ctx context.Context, req *UpdateDraftAgentToolRequest) (err error)
GetSpaceAllDraftAgentTools(ctx context.Context, agentID int64) (tools []*entity.ToolInfo, err error)
GetAgentPluginIDs(ctx context.Context, agentID int64) (pluginIDs []int64, err error)
GetVersionAgentTool(ctx context.Context, agentID int64, vAgentTool entity.VersionAgentTool) (tool *entity.ToolInfo, exist bool, err error)
GetVersionAgentToolWithToolName(ctx context.Context, req *GetVersionAgentToolWithToolNameRequest) (tool *entity.ToolInfo, exist bool, err error)
MGetVersionAgentTool(ctx context.Context, agentID int64, vAgentTools []entity.VersionAgentTool) (tools []*entity.ToolInfo, err error)
BatchCreateVersionAgentTools(ctx context.Context, agentID int64, agentVersion string, tools []*entity.ToolInfo) (err error)
UpdateDraftToolAndDebugExample(ctx context.Context, pluginID int64, doc *plugin.Openapi3T, updatedTool *entity.ToolInfo) (err error)
GetPluginAllDraftTools(ctx context.Context, pluginID int64, opts ...ToolSelectedOptions) (tools []*entity.ToolInfo, err error)
GetPluginAllOnlineTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error)
ListPluginDraftTools(ctx context.Context, pluginID int64, pageInfo entity.PageInfo) (tools []*entity.ToolInfo, total int64, err error)
}
type GetVersionAgentToolWithToolNameRequest struct {
AgentID int64
ToolName string
AgentVersion *string
}
type UpdateDraftAgentToolRequest struct {
AgentID int64
ToolName string
Tool *entity.ToolInfo
}

View File

@@ -0,0 +1,387 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"fmt"
"net/http"
"strconv"
"github.com/getkin/kin-openapi/openapi3"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
func (p *pluginServiceImpl) BindAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error) {
return p.toolRepo.BindDraftAgentTools(ctx, agentID, toolIDs)
}
func (p *pluginServiceImpl) DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error) {
return p.toolRepo.DuplicateDraftAgentTools(ctx, fromAgentID, toAgentID)
}
func (p *pluginServiceImpl) GetDraftAgentToolByName(ctx context.Context, agentID int64, toolName string) (tool *entity.ToolInfo, err error) {
draftAgentTool, exist, err := p.toolRepo.GetDraftAgentToolWithToolName(ctx, agentID, toolName)
if err != nil {
return nil, errorx.Wrapf(err, "GetDraftAgentToolWithToolName failed, agentID=%d, toolName=%s", agentID, toolName)
}
if !exist {
return nil, errorx.New(errno.ErrPluginRecordNotFound)
}
tool, exist, err = p.toolRepo.GetOnlineTool(ctx, draftAgentTool.ID)
if err != nil {
return nil, errorx.Wrapf(err, "GetOnlineTool failed, id=%d", draftAgentTool.ID)
}
if !exist {
return nil, errorx.New(errno.ErrPluginRecordNotFound)
}
draftAgentTool, err = mergeAgentToolInfo(ctx, tool, draftAgentTool)
if err != nil {
return nil, errorx.Wrapf(err, "mergeAgentToolInfo failed")
}
return draftAgentTool, nil
}
func (p *pluginServiceImpl) MGetAgentTools(ctx context.Context, req *MGetAgentToolsRequest) (tools []*entity.ToolInfo, err error) {
toolIDs := make([]int64, 0, len(req.VersionAgentTools))
for _, v := range req.VersionAgentTools {
toolIDs = append(toolIDs, v.ToolID)
}
existTools, err := p.toolRepo.MGetOnlineTools(ctx, toolIDs, repository.WithToolID())
if err != nil {
return nil, errorx.Wrapf(err, "MGetOnlineTools failed, toolIDs=%v", toolIDs)
}
if len(existTools) == 0 {
return nil, nil
}
existMap := make(map[int64]bool, len(existTools))
for _, tool := range existTools {
existMap[tool.ID] = true
}
if req.IsDraft {
existToolIDs := make([]int64, 0, len(existMap))
for _, v := range req.VersionAgentTools {
if existMap[v.ToolID] {
existToolIDs = append(existToolIDs, v.ToolID)
}
}
tools, err = p.toolRepo.MGetDraftAgentTools(ctx, req.AgentID, existToolIDs)
if err != nil {
return nil, errorx.Wrapf(err, "MGetDraftAgentTools failed, agentID=%d, toolIDs=%v", req.AgentID, existToolIDs)
}
return tools, nil
}
vTools := make([]entity.VersionAgentTool, 0, len(existMap))
for _, v := range req.VersionAgentTools {
if existMap[v.ToolID] {
vTools = append(vTools, v)
}
}
tools, err = p.toolRepo.MGetVersionAgentTool(ctx, req.AgentID, vTools)
if err != nil {
return nil, errorx.Wrapf(err, "MGetVersionAgentTool failed, agentID=%d, vTools=%v", req.AgentID, vTools)
}
return tools, nil
}
func (p *pluginServiceImpl) PublishAgentTools(ctx context.Context, agentID int64, agentVersion string) (err error) {
tools, err := p.toolRepo.GetSpaceAllDraftAgentTools(ctx, agentID)
if err != nil {
return errorx.Wrapf(err, "GetSpaceAllDraftAgentTools failed, agentID=%d", agentID)
}
err = p.toolRepo.BatchCreateVersionAgentTools(ctx, agentID, agentVersion, tools)
if err != nil {
return errorx.Wrapf(err, "BatchCreateVersionAgentTools failed, agentID=%d, agentVersion=%s", agentID, agentVersion)
}
return nil
}
func (p *pluginServiceImpl) UpdateBotDefaultParams(ctx context.Context, req *UpdateBotDefaultParamsRequest) (err error) {
_, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, req.PluginID, repository.WithPluginID())
if err != nil {
return errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", req.PluginID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
draftAgentTool, exist, err := p.toolRepo.GetDraftAgentToolWithToolName(ctx, req.AgentID, req.ToolName)
if err != nil {
return errorx.Wrapf(err, "GetDraftAgentToolWithToolName failed, agentID=%d, toolName=%s", req.AgentID, req.ToolName)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
onlineTool, exist, err := p.toolRepo.GetOnlineTool(ctx, draftAgentTool.ID)
if err != nil {
return errorx.Wrapf(err, "GetOnlineTool failed, id=%d", draftAgentTool.ID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
op := onlineTool.Operation
if req.Parameters != nil {
op.Parameters = req.Parameters
}
if req.RequestBody != nil {
mType, ok := req.RequestBody.Value.Content[model.MediaTypeJson]
if !ok {
return fmt.Errorf("the '%s' media type is not defined in request body", model.MediaTypeJson)
}
if op.RequestBody.Value.Content == nil {
op.RequestBody.Value.Content = map[string]*openapi3.MediaType{}
}
op.RequestBody.Value.Content[model.MediaTypeJson] = mType
}
if req.Responses != nil {
newRespRef, ok := req.Responses[strconv.Itoa(http.StatusOK)]
if !ok {
return fmt.Errorf("the '%d' status code is not defined in responses", http.StatusOK)
}
newMIMEType, ok := newRespRef.Value.Content[model.MediaTypeJson]
if !ok {
return fmt.Errorf("the '%s' media type is not defined in responses", model.MediaTypeJson)
}
if op.Responses == nil {
op.Responses = map[string]*openapi3.ResponseRef{}
}
oldRespRef, ok := op.Responses[strconv.Itoa(http.StatusOK)]
if !ok {
oldRespRef = &openapi3.ResponseRef{
Value: &openapi3.Response{
Content: map[string]*openapi3.MediaType{},
},
}
op.Responses[strconv.Itoa(http.StatusOK)] = oldRespRef
}
if oldRespRef.Value.Content == nil {
oldRespRef.Value.Content = map[string]*openapi3.MediaType{}
}
oldRespRef.Value.Content[model.MediaTypeJson] = newMIMEType
}
updatedTool := &entity.ToolInfo{
Version: onlineTool.Version,
Method: onlineTool.Method,
SubURL: onlineTool.SubURL,
Operation: op,
}
err = p.toolRepo.UpdateDraftAgentTool(ctx, &repository.UpdateDraftAgentToolRequest{
AgentID: req.AgentID,
ToolName: req.ToolName,
Tool: updatedTool,
})
if err != nil {
return errorx.Wrapf(err, "UpdateDraftAgentTool failed, agentID=%d, toolName=%s", req.AgentID, req.ToolName)
}
return nil
}
func mergeAgentToolInfo(ctx context.Context, dest, src *entity.ToolInfo) (*entity.ToolInfo, error) {
dest.Version = src.Version
dest.Method = src.Method
dest.SubURL = src.SubURL
newParameters, err := mergeParameters(ctx, dest.Operation.Parameters, src.Operation.Parameters)
if err != nil {
return nil, errorx.Wrapf(err, "mergeParameters failed")
}
dest.Operation.Parameters = newParameters
newReqBody, err := mergeRequestBody(ctx, dest.Operation.RequestBody, src.Operation.RequestBody)
if err != nil {
return nil, errorx.Wrapf(err, "mergeRequestBody failed")
}
dest.Operation.RequestBody = newReqBody
newRespBody, err := mergeResponseBody(ctx, dest.Operation.Responses, src.Operation.Responses)
if err != nil {
return nil, errorx.Wrapf(err, "mergeResponseBody failed")
}
dest.Operation.Responses = newRespBody
return dest, nil
}
func mergeParameters(ctx context.Context, dest, src openapi3.Parameters) (openapi3.Parameters, error) {
if len(dest) == 0 || len(src) == 0 {
return src, nil
}
srcMap := make(map[string]*openapi3.ParameterRef, len(src))
for _, p := range src {
srcMap[p.Value.Name] = p
}
for _, dp := range dest {
sp, ok := srcMap[dp.Value.Name]
if !ok {
continue
}
dv := dp.Value.Schema.Value
sv := sp.Value.Schema.Value
if dv.Extensions == nil {
dv.Extensions = make(map[string]any)
}
if v, ok := sv.Extensions[model.APISchemaExtendLocalDisable]; ok {
dv.Extensions[model.APISchemaExtendLocalDisable] = v
}
if v, ok := sv.Extensions[model.APISchemaExtendVariableRef]; ok {
dv.Extensions[model.APISchemaExtendVariableRef] = v
}
dv.Default = sv.Default
}
return dest, nil
}
func mergeRequestBody(ctx context.Context, dest, src *openapi3.RequestBodyRef) (*openapi3.RequestBodyRef, error) {
if dest == nil || src == nil {
return src, nil
}
for ct, dm := range dest.Value.Content {
sm, ok := src.Value.Content[ct]
if !ok {
continue
}
nv, err := mergeMediaSchema(ctx, dm.Schema.Value, sm.Schema.Value)
if err != nil {
return nil, err
}
dm.Schema.Value = nv
}
return dest, nil
}
func mergeMediaSchema(ctx context.Context, dest, src *openapi3.Schema) (*openapi3.Schema, error) {
if dest.Extensions == nil {
dest.Extensions = map[string]any{}
}
if v, ok := src.Extensions[model.APISchemaExtendLocalDisable]; ok {
dest.Extensions[model.APISchemaExtendLocalDisable] = v
}
if v, ok := src.Extensions[model.APISchemaExtendVariableRef]; ok {
dest.Extensions[model.APISchemaExtendVariableRef] = v
}
dest.Default = src.Default
switch dest.Type {
case openapi3.TypeObject:
for k, dv := range dest.Properties {
sv, ok := src.Properties[k]
if !ok {
continue
}
nv, err := mergeMediaSchema(ctx, dv.Value, sv.Value)
if err != nil {
return nil, err
}
dv.Value = nv
}
return dest, nil
case openapi3.TypeArray:
nv, err := mergeMediaSchema(ctx, dest.Items.Value, src.Items.Value)
if err != nil {
return nil, err
}
dest.Items.Value = nv
return dest, nil
default:
return dest, nil
}
}
func mergeResponseBody(ctx context.Context, dest, src openapi3.Responses) (openapi3.Responses, error) {
if len(dest) == 0 || len(src) == 0 {
return src, nil
}
for code, dr := range dest {
sr := src[code]
if dr == nil || sr == nil {
continue
}
if len(dr.Value.Content) == 0 || len(sr.Value.Content) == 0 {
continue
}
for ct, dm := range dr.Value.Content {
sm, ok := sr.Value.Content[ct]
if !ok {
continue
}
nv, err := mergeMediaSchema(ctx, dm.Schema.Value, sm.Schema.Value)
if err != nil {
return nil, err
}
dm.Schema.Value = nv
}
}
return dest, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,903 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/bytedance/sonic"
"github.com/getkin/kin-openapi/openapi3"
"gopkg.in/yaml.v3"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
searchModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/search"
"github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
resCommon "github.com/coze-dev/coze-studio/backend/api/model/resource/common"
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crosssearch"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/internal/openapi"
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
func (p *pluginServiceImpl) CreateDraftPlugin(ctx context.Context, req *CreateDraftPluginRequest) (pluginID int64, err error) {
mf := entity.NewDefaultPluginManifest()
mf.NameForHuman = req.Name
mf.NameForModel = req.Name
mf.DescriptionForHuman = req.Desc
mf.DescriptionForModel = req.Desc
mf.API.Type, _ = model.ToPluginType(req.PluginType)
mf.LogoURL = req.IconURI
authV2, err := req.AuthInfo.toAuthV2()
if err != nil {
return 0, err
}
mf.Auth = authV2
for loc, params := range req.CommonParams {
location, ok := model.ToHTTPParamLocation(loc)
if !ok {
return 0, fmt.Errorf("invalid location '%s'", loc.String())
}
for _, param := range params {
mParams := mf.CommonParams[location]
mParams = append(mParams, &plugin_develop_common.CommonParamSchema{
Name: param.Name,
Value: param.Value,
})
}
}
doc := entity.NewDefaultOpenapiDoc()
doc.Servers = append(doc.Servers, &openapi3.Server{
URL: req.ServerURL,
})
doc.Info.Title = req.Name
doc.Info.Description = req.Desc
err = doc.Validate(ctx)
if err != nil {
return 0, err
}
err = mf.Validate(false)
if err != nil {
return 0, err
}
pl := entity.NewPluginInfo(&model.PluginInfo{
IconURI: ptr.Of(req.IconURI),
SpaceID: req.SpaceID,
ServerURL: ptr.Of(req.ServerURL),
DeveloperID: req.DeveloperID,
APPID: req.ProjectID,
PluginType: req.PluginType,
Manifest: mf,
OpenapiDoc: doc,
})
pluginID, err = p.pluginRepo.CreateDraftPlugin(ctx, pl)
if err != nil {
return 0, errorx.Wrapf(err, "CreateDraftPlugin failed")
}
return pluginID, nil
}
func (p *pluginServiceImpl) GetDraftPlugin(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, err error) {
pl, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pluginID)
if err != nil {
return nil, errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", pluginID)
}
if !exist {
return nil, errorx.New(errno.ErrPluginRecordNotFound)
}
return pl, nil
}
func (p *pluginServiceImpl) MGetDraftPlugins(ctx context.Context, pluginIDs []int64) (plugins []*entity.PluginInfo, err error) {
plugins, err = p.pluginRepo.MGetDraftPlugins(ctx, pluginIDs)
if err != nil {
return nil, err
}
return plugins, nil
}
func (p *pluginServiceImpl) ListDraftPlugins(ctx context.Context, req *ListDraftPluginsRequest) (resp *ListDraftPluginsResponse, err error) {
if req.PageInfo.Name == nil || *req.PageInfo.Name == "" {
res, err := p.pluginRepo.ListDraftPlugins(ctx, &repository.ListDraftPluginsRequest{
SpaceID: req.SpaceID,
APPID: req.APPID,
PageInfo: req.PageInfo,
})
if err != nil {
return nil, errorx.Wrapf(err, "ListDraftPlugins failed, spaceID=%d, appID=%d", req.SpaceID, req.APPID)
}
return &ListDraftPluginsResponse{
Plugins: res.Plugins,
Total: res.Total,
}, nil
}
res, err := crosssearch.DefaultSVC().SearchResources(ctx, &searchModel.SearchResourcesRequest{
SpaceID: req.SpaceID,
APPID: req.APPID,
Name: *req.PageInfo.Name,
OrderAsc: false,
ResTypeFilter: []resCommon.ResType{
resCommon.ResType_Plugin,
},
OrderFiledName: func() string {
if req.PageInfo.SortBy == nil || *req.PageInfo.SortBy != entity.SortByCreatedAt {
return searchModel.FieldOfUpdateTime
}
return searchModel.FieldOfCreateTime
}(),
Page: ptr.Of(int32(req.PageInfo.Page)),
Limit: int32(req.PageInfo.Size),
})
if err != nil {
return nil, errorx.Wrapf(err, "SearchResources failed, spaceID=%d, appID=%d", req.SpaceID, req.APPID)
}
plugins := make([]*entity.PluginInfo, 0, len(res.Data))
for _, pl := range res.Data {
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pl.ResID)
if err != nil {
return nil, errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", pl.ResID)
}
if !exist {
logs.CtxWarnf(ctx, "draft plugin not exist, pluginID=%d", pl.ResID)
continue
}
plugins = append(plugins, draftPlugin)
}
total := int64(0)
if res.TotalHits != nil {
total = *res.TotalHits
}
return &ListDraftPluginsResponse{
Plugins: plugins,
Total: total,
}, nil
}
func (p *pluginServiceImpl) CreateDraftPluginWithCode(ctx context.Context, req *CreateDraftPluginWithCodeRequest) (resp *CreateDraftPluginWithCodeResponse, err error) {
err = req.OpenapiDoc.Validate(ctx)
if err != nil {
return nil, err
}
err = req.Manifest.Validate(false)
if err != nil {
return nil, err
}
res, err := p.pluginRepo.CreateDraftPluginWithCode(ctx, &repository.CreateDraftPluginWithCodeRequest{
SpaceID: req.SpaceID,
DeveloperID: req.DeveloperID,
ProjectID: req.ProjectID,
Manifest: req.Manifest,
OpenapiDoc: req.OpenapiDoc,
})
if err != nil {
return nil, errorx.Wrapf(err, "CreateDraftPluginWithCode failed")
}
resp = &CreateDraftPluginWithCodeResponse{
Plugin: res.Plugin,
Tools: res.Tools,
}
return resp, nil
}
func (p *pluginServiceImpl) UpdateDraftPluginWithCode(ctx context.Context, req *UpdateDraftPluginWithCodeRequest) (err error) {
doc := req.OpenapiDoc
mf := req.Manifest
err = doc.Validate(ctx)
if err != nil {
return err
}
err = mf.Validate(false)
if err != nil {
return err
}
apiSchemas := make(map[entity.UniqueToolAPI]*model.Openapi3Operation, len(doc.Paths))
apis := make([]entity.UniqueToolAPI, 0, len(doc.Paths))
for subURL, pathItem := range doc.Paths {
for method, op := range pathItem.Operations() {
api := entity.UniqueToolAPI{
SubURL: subURL,
Method: method,
}
apiSchemas[api] = model.NewOpenapi3Operation(op)
apis = append(apis, api)
}
}
oldDraftTools, err := p.toolRepo.GetPluginAllDraftTools(ctx, req.PluginID)
if err != nil {
return errorx.Wrapf(err, "GetPluginAllDraftTools failed, pluginID=%d", req.PluginID)
}
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, req.PluginID)
if err != nil {
return errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", req.PluginID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
if draftPlugin.GetServerURL() != doc.Servers[0].URL {
for _, draftTool := range oldDraftTools {
draftTool.DebugStatus = ptr.Of(common.APIDebugStatus_DebugWaiting)
}
}
oldDraftToolsMap := slices.ToMap(oldDraftTools, func(e *entity.ToolInfo) (entity.UniqueToolAPI, *entity.ToolInfo) {
return entity.UniqueToolAPI{
SubURL: e.GetSubURL(),
Method: e.GetMethod(),
}, e
})
// 1. 删除 tool -> 关闭启用
for api, oldTool := range oldDraftToolsMap {
_, ok := apiSchemas[api]
if !ok {
oldTool.DebugStatus = ptr.Of(common.APIDebugStatus_DebugWaiting)
oldTool.ActivatedStatus = ptr.Of(model.DeactivateTool)
}
}
newDraftTools := make([]*entity.ToolInfo, 0, len(apis))
for api, newOp := range apiSchemas {
oldTool, ok := oldDraftToolsMap[api]
if ok { // 2. 更新 tool -> 覆盖
oldTool.ActivatedStatus = ptr.Of(model.ActivateTool)
oldTool.Operation = newOp
if needResetDebugStatusTool(ctx, newOp, oldTool.Operation) {
oldTool.DebugStatus = ptr.Of(common.APIDebugStatus_DebugWaiting)
}
continue
}
// 3. 新增 tool
newDraftTools = append(newDraftTools, &entity.ToolInfo{
PluginID: req.PluginID,
ActivatedStatus: ptr.Of(model.ActivateTool),
DebugStatus: ptr.Of(common.APIDebugStatus_DebugWaiting),
SubURL: ptr.Of(api.SubURL),
Method: ptr.Of(api.Method),
Operation: newOp,
})
}
err = p.pluginRepo.UpdateDraftPluginWithCode(ctx, &repository.UpdatePluginDraftWithCode{
PluginID: req.PluginID,
OpenapiDoc: doc,
Manifest: mf,
UpdatedTools: oldDraftTools,
NewDraftTools: newDraftTools,
})
if err != nil {
return errorx.Wrapf(err, "UpdateDraftPluginWithCode failed, pluginID=%d", req.PluginID)
}
return nil
}
func needResetDebugStatusTool(_ context.Context, nt, ot *model.Openapi3Operation) bool {
if len(ot.Parameters) != len(ot.Parameters) {
return true
}
otParams := make(map[string]*openapi3.Parameter, len(ot.Parameters))
cnt := make(map[string]int, len(nt.Parameters))
for _, p := range nt.Parameters {
cnt[p.Value.Name]++
}
for _, p := range ot.Parameters {
cnt[p.Value.Name]--
otParams[p.Value.Name] = p.Value
}
for _, v := range cnt {
if v != 0 {
return true
}
}
for _, p := range nt.Parameters {
np, op := p.Value, otParams[p.Value.Name]
if np.In != op.In {
return true
}
if np.Required != op.Required {
return true
}
if !isJsonSchemaEqual(op.Schema.Value, np.Schema.Value) {
return true
}
}
nReqBody, oReqBody := nt.RequestBody.Value, ot.RequestBody.Value
if len(nReqBody.Content) != len(oReqBody.Content) {
return true
}
cnt = make(map[string]int, len(nReqBody.Content))
for ct := range nReqBody.Content {
cnt[ct]++
}
for ct := range oReqBody.Content {
cnt[ct]--
}
for _, v := range cnt {
if v != 0 {
return true
}
}
for ct, nct := range nReqBody.Content {
oct := oReqBody.Content[ct]
if !isJsonSchemaEqual(nct.Schema.Value, oct.Schema.Value) {
return true
}
}
return false
}
func isJsonSchemaEqual(nsc, osc *openapi3.Schema) bool {
if nsc.Type != osc.Type {
return false
}
if nsc.Format != osc.Format {
return false
}
if nsc.Default != osc.Default {
return false
}
if nsc.Extensions[model.APISchemaExtendAssistType] != osc.Extensions[model.APISchemaExtendAssistType] {
return false
}
if nsc.Extensions[model.APISchemaExtendGlobalDisable] != osc.Extensions[model.APISchemaExtendGlobalDisable] {
return false
}
switch nsc.Type {
case openapi3.TypeObject:
if len(nsc.Required) != len(osc.Required) {
return false
}
if len(nsc.Required) > 0 {
cnt := make(map[string]int, len(nsc.Required))
for _, x := range nsc.Required {
cnt[x]++
}
for _, x := range osc.Required {
cnt[x]--
}
for _, v := range cnt {
if v != 0 {
return true
}
}
}
if len(nsc.Properties) != len(osc.Properties) {
return false
}
if len(nsc.Properties) > 0 {
for paramName, np := range nsc.Properties {
op, ok := osc.Properties[paramName]
if !ok {
return false
}
if !isJsonSchemaEqual(np.Value, op.Value) {
return false
}
}
}
case openapi3.TypeArray:
if !isJsonSchemaEqual(nsc.Items.Value, osc.Items.Value) {
return false
}
}
return true
}
func (p *pluginServiceImpl) UpdateDraftPlugin(ctx context.Context, req *UpdateDraftPluginRequest) (err error) {
oldPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, req.PluginID)
if err != nil {
return errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", req.PluginID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
doc, err := updatePluginOpenapiDoc(ctx, oldPlugin.OpenapiDoc, req)
if err != nil {
return errorx.Wrapf(err, "updatePluginOpenapiDoc failed")
}
mf, err := updatePluginManifest(ctx, oldPlugin.Manifest, req)
if err != nil {
return errorx.Wrapf(err, "updatePluginManifest failed")
}
newPlugin := entity.NewPluginInfo(&model.PluginInfo{
ID: req.PluginID,
IconURI: ptr.Of(mf.LogoURL),
ServerURL: req.URL,
Manifest: mf,
OpenapiDoc: doc,
})
if newPlugin.GetServerURL() == "" ||
oldPlugin.GetServerURL() == newPlugin.GetServerURL() {
err = p.pluginRepo.UpdateDraftPluginWithoutURLChanged(ctx, newPlugin)
if err != nil {
return errorx.Wrapf(err, "UpdateDraftPluginWithoutURLChanged failed, pluginID=%d", req.PluginID)
}
return nil
}
err = p.pluginRepo.UpdateDraftPlugin(ctx, newPlugin)
if err != nil {
return errorx.Wrapf(err, "UpdateDraftPlugin failed, pluginID=%d", req.PluginID)
}
return nil
}
func updatePluginOpenapiDoc(_ context.Context, doc *model.Openapi3T, req *UpdateDraftPluginRequest) (*model.Openapi3T, error) {
if req.Name != nil {
doc.Info.Title = *req.Name
}
if req.Desc != nil {
doc.Info.Description = *req.Desc
}
if req.URL != nil {
hasServer := false
for _, svr := range doc.Servers {
if svr.URL == *req.URL {
hasServer = true
}
}
if !hasServer {
doc.Servers = openapi3.Servers{{URL: *req.URL}}
}
}
return doc, nil
}
func updatePluginManifest(_ context.Context, mf *entity.PluginManifest, req *UpdateDraftPluginRequest) (*entity.PluginManifest, error) {
if req.Name != nil {
mf.NameForHuman = *req.Name
mf.NameForModel = *req.Name
}
if req.Desc != nil {
mf.DescriptionForHuman = *req.Desc
mf.DescriptionForModel = *req.Desc
}
if req.Icon != nil {
mf.LogoURL = req.Icon.URI
}
if len(req.CommonParams) > 0 {
if mf.CommonParams == nil {
mf.CommonParams = make(map[model.HTTPParamLocation][]*plugin_develop_common.CommonParamSchema, len(req.CommonParams))
}
for loc, params := range req.CommonParams {
location, ok := model.ToHTTPParamLocation(loc)
if !ok {
return nil, fmt.Errorf("invalid location '%s'", loc.String())
}
commonParams := make([]*plugin_develop_common.CommonParamSchema, 0, len(params))
for _, param := range params {
commonParams = append(commonParams, &plugin_develop_common.CommonParamSchema{
Name: param.Name,
Value: param.Value,
})
}
mf.CommonParams[location] = commonParams
}
}
if req.AuthInfo != nil {
authV2, err := req.AuthInfo.toAuthV2()
if err != nil {
return nil, err
}
mf.Auth = authV2
}
return mf, nil
}
func (p *pluginServiceImpl) DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error) {
return p.pluginRepo.DeleteDraftPlugin(ctx, pluginID)
}
func (p *pluginServiceImpl) MGetDraftTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error) {
tools, err = p.toolRepo.MGetDraftTools(ctx, toolIDs)
if err != nil {
return nil, errorx.Wrapf(err, "MGetDraftTools failed, toolIDs=%v", toolIDs)
}
return tools, nil
}
func (p *pluginServiceImpl) UpdateDraftTool(ctx context.Context, req *UpdateToolDraftRequest) (err error) {
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, req.PluginID)
if err != nil {
return errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", req.PluginID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
draftTool, exist, err := p.toolRepo.GetDraftTool(ctx, req.ToolID)
if err != nil {
return errorx.Wrapf(err, "GetDraftTool failed, toolID=%d", req.ToolID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
if req.Method != nil && req.SubURL != nil {
api := entity.UniqueToolAPI{
SubURL: ptr.FromOrDefault(req.SubURL, ""),
Method: ptr.FromOrDefault(req.Method, ""),
}
existTool, exist, err := p.toolRepo.GetDraftToolWithAPI(ctx, draftTool.PluginID, api)
if err != nil {
return errorx.Wrapf(err, "GetDraftToolWithAPI failed, pluginID=%d, api=%v", draftTool.PluginID, api)
}
if exist && draftTool.ID != existTool.ID {
return errorx.New(errno.ErrPluginDuplicatedTool, errorx.KVf(errno.PluginMsgKey, "[%s]:%s", api.Method, api.SubURL))
}
}
var activatedStatus *model.ActivatedStatus
if req.Disabled != nil {
if *req.Disabled {
activatedStatus = ptr.Of(model.DeactivateTool)
} else {
activatedStatus = ptr.Of(model.ActivateTool)
}
}
debugStatus := draftTool.DebugStatus
if req.Method != nil ||
req.SubURL != nil ||
req.Parameters != nil ||
req.RequestBody != nil ||
req.Responses != nil {
debugStatus = ptr.Of(common.APIDebugStatus_DebugWaiting)
}
op := draftTool.Operation
if req.Name != nil {
op.OperationID = *req.Name
}
if req.Desc != nil {
op.Summary = *req.Desc
}
if req.Parameters != nil {
op.Parameters = req.Parameters
}
if req.APIExtend != nil {
if op.Extensions == nil {
op.Extensions = map[string]any{}
}
authMode, ok := model.ToAPIAuthMode(req.APIExtend.AuthMode)
if ok {
op.Extensions[model.APISchemaExtendAuthMode] = authMode
}
}
if req.RequestBody == nil {
op.RequestBody = draftTool.Operation.RequestBody
} else {
mType, ok := req.RequestBody.Value.Content[model.MediaTypeJson]
if !ok {
return fmt.Errorf("the '%s' media type is not defined in request body", model.MediaTypeJson)
}
if op.RequestBody == nil || op.RequestBody.Value == nil || op.RequestBody.Value.Content == nil {
op.RequestBody = &openapi3.RequestBodyRef{
Value: &openapi3.RequestBody{
Content: map[string]*openapi3.MediaType{},
},
}
}
op.RequestBody.Value.Content[model.MediaTypeJson] = mType
}
if req.Responses == nil {
op.Responses = draftTool.Operation.Responses
} else {
newRespRef, ok := req.Responses[strconv.Itoa(http.StatusOK)]
if !ok {
return fmt.Errorf("the '%d' status code is not defined in responses", http.StatusOK)
}
newMIMEType, ok := newRespRef.Value.Content[model.MediaTypeJson]
if !ok {
return fmt.Errorf("the '%s' media type is not defined in responses", model.MediaTypeJson)
}
if op.Responses == nil {
op.Responses = map[string]*openapi3.ResponseRef{}
}
oldRespRef, ok := op.Responses[strconv.Itoa(http.StatusOK)]
if !ok {
oldRespRef = &openapi3.ResponseRef{
Value: &openapi3.Response{
Content: map[string]*openapi3.MediaType{},
},
}
op.Responses[strconv.Itoa(http.StatusOK)] = oldRespRef
}
if oldRespRef.Value.Content == nil {
oldRespRef.Value.Content = map[string]*openapi3.MediaType{}
}
oldRespRef.Value.Content[model.MediaTypeJson] = newMIMEType
}
updatedTool := &entity.ToolInfo{
ID: req.ToolID,
PluginID: req.PluginID,
ActivatedStatus: activatedStatus,
DebugStatus: debugStatus,
Method: req.Method,
SubURL: req.SubURL,
Operation: op,
}
components := draftPlugin.OpenapiDoc.Components
if req.SaveExample != nil && !*req.SaveExample &&
components != nil && components.Examples != nil {
delete(components.Examples, draftTool.Operation.OperationID)
} else if req.DebugExample != nil {
if components == nil {
components = &openapi3.Components{}
}
if components.Examples == nil {
components.Examples = make(map[string]*openapi3.ExampleRef)
}
draftPlugin.OpenapiDoc.Components = components
reqExample, respExample := map[string]any{}, map[string]any{}
if req.DebugExample.ReqExample != "" {
err = sonic.UnmarshalString(req.DebugExample.ReqExample, &reqExample)
if err != nil {
return errorx.WrapByCode(err, errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey, "invalid request example"))
}
}
if req.DebugExample.RespExample != "" {
err = sonic.UnmarshalString(req.DebugExample.RespExample, &respExample)
if err != nil {
return errorx.WrapByCode(err, errno.ErrPluginInvalidOpenapi3Doc, errorx.KV(errno.PluginMsgKey, "invalid response example"))
}
}
components.Examples[draftTool.Operation.OperationID] = &openapi3.ExampleRef{
Value: &openapi3.Example{
Value: map[string]any{
"ReqExample": reqExample,
"RespExample": respExample,
},
},
}
}
err = p.toolRepo.UpdateDraftToolAndDebugExample(ctx, draftPlugin.ID, draftPlugin.OpenapiDoc, updatedTool)
if err != nil {
return errorx.Wrapf(err, "UpdateDraftToolAndDebugExample failed, pluginID=%d, toolID=%d", draftPlugin.ID, req.ToolID)
}
return nil
}
func (p *pluginServiceImpl) ConvertToOpenapi3Doc(ctx context.Context, req *ConvertToOpenapi3DocRequest) (resp *ConvertToOpenapi3DocResponse) {
var err error
defer func() {
if err != nil {
logs.Errorf("ConvertToOpenapi3Doc failed, err=%s", err)
resp.ErrMsg = "internal server error"
var e errorx.StatusError
if errors.As(err, &e) {
resp.ErrMsg = e.Msg()
}
}
}()
resp = &ConvertToOpenapi3DocResponse{}
cvt, format, err := getConvertFunc(ctx, req.RawInput)
if err != nil {
resp.Format = format
return resp
}
doc, mf, err := cvt(ctx, req.RawInput)
if err != nil {
resp.Format = format
return resp
}
err = validateConvertResult(ctx, req, doc, mf)
if err != nil {
resp.Format = format
return resp
}
return &ConvertToOpenapi3DocResponse{
OpenapiDoc: doc,
Manifest: mf,
Format: format,
ErrMsg: "",
}
}
type convertFunc func(ctx context.Context, rawInput string) (*model.Openapi3T, *entity.PluginManifest, error)
func getConvertFunc(ctx context.Context, rawInput string) (convertFunc, common.PluginDataFormat, error) {
if strings.HasPrefix(rawInput, "curl") {
return openapi.CurlToOpenapi3Doc, common.PluginDataFormat_Curl, nil
}
if strings.Contains(rawInput, "_postman_id") { // postman collection
return openapi.PostmanToOpenapi3Doc, common.PluginDataFormat_Postman, nil
}
var vd struct {
OpenAPI string `json:"openapi" yaml:"openapi"`
Swagger string `json:"swagger" yaml:"swagger"`
}
err := sonic.UnmarshalString(rawInput, &vd)
if err != nil {
err = yaml.Unmarshal([]byte(rawInput), &vd)
if err != nil {
return nil, 0, fmt.Errorf("invalid schema")
}
}
if vd.OpenAPI == "3" || strings.HasPrefix(vd.OpenAPI, "3.") {
return openapi.ToOpenapi3Doc, common.PluginDataFormat_OpenAPI, nil
}
if vd.Swagger == "2" || strings.HasPrefix(vd.Swagger, "2.") {
return openapi.SwaggerToOpenapi3Doc, common.PluginDataFormat_Swagger, nil
}
return nil, 0, fmt.Errorf("invalid schema")
}
func validateConvertResult(ctx context.Context, req *ConvertToOpenapi3DocRequest, doc *model.Openapi3T, mf *entity.PluginManifest) error {
if req.PluginServerURL != nil {
if doc.Servers[0].URL != *req.PluginServerURL {
return errorx.New(errno.ErrPluginConvertProtocolFailed, errorx.KV(errno.PluginMsgKey, "inconsistent API URL prefix"))
}
}
err := doc.Validate(ctx)
if err != nil {
return err
}
err = mf.Validate(false)
if err != nil {
return err
}
return nil
}
func (p *pluginServiceImpl) CreateDraftToolsWithCode(ctx context.Context, req *CreateDraftToolsWithCodeRequest) (resp *CreateDraftToolsWithCodeResponse, err error) {
err = req.OpenapiDoc.Validate(ctx)
if err != nil {
return nil, err
}
toolAPIs := make([]entity.UniqueToolAPI, 0, len(req.OpenapiDoc.Paths))
for path, item := range req.OpenapiDoc.Paths {
for method := range item.Operations() {
toolAPIs = append(toolAPIs, entity.UniqueToolAPI{
SubURL: path,
Method: method,
})
}
}
existTools, err := p.toolRepo.MGetDraftToolWithAPI(ctx, req.PluginID, toolAPIs,
repository.WithToolID(),
repository.WithToolMethod(),
repository.WithToolSubURL())
if err != nil {
return nil, errorx.Wrapf(err, "MGetDraftToolWithAPI failed, pluginID=%d, apis=%v", req.PluginID, toolAPIs)
}
duplicatedTools := make([]entity.UniqueToolAPI, 0, len(existTools))
for _, api := range toolAPIs {
if _, exist := existTools[api]; exist {
duplicatedTools = append(duplicatedTools, api)
}
}
if !req.ConflictAndUpdate && len(duplicatedTools) > 0 {
return &CreateDraftToolsWithCodeResponse{
DuplicatedTools: duplicatedTools,
}, nil
}
tools := make([]*entity.ToolInfo, 0, len(toolAPIs))
for path, item := range req.OpenapiDoc.Paths {
for method, op := range item.Operations() {
tools = append(tools, &entity.ToolInfo{
PluginID: req.PluginID,
Method: ptr.Of(method),
SubURL: ptr.Of(path),
ActivatedStatus: ptr.Of(model.ActivateTool),
DebugStatus: ptr.Of(common.APIDebugStatus_DebugWaiting),
Operation: model.NewOpenapi3Operation(op),
})
}
}
err = p.toolRepo.UpsertDraftTools(ctx, req.PluginID, tools)
if err != nil {
return nil, errorx.Wrapf(err, "UpsertDraftTools failed, pluginID=%d", req.PluginID)
}
resp = &CreateDraftToolsWithCodeResponse{}
return resp, nil
}

View File

@@ -0,0 +1,512 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"encoding/json"
"fmt"
"os"
"strings"
"sync"
"time"
"golang.org/x/oauth2"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/utils"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/lang/conv"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/pkg/taskgroup"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
var (
initOnce = sync.Once{}
lastActiveInterval = 15 * 24 * time.Hour
)
func (p *pluginServiceImpl) processOAuthAccessToken(ctx context.Context) {
const (
deleteLimit = 100
refreshLimit = 50
)
for {
now := time.Now()
lastActiveAt := now.Add(-lastActiveInterval)
err := p.oauthRepo.DeleteInactiveAuthorizationCodeTokens(ctx, lastActiveAt.UnixMilli(), deleteLimit)
if err != nil {
logs.CtxWarnf(ctx, "DeleteInactiveAuthorizationCodeTokens failed, err=%v", err)
}
err = p.oauthRepo.DeleteExpiredAuthorizationCodeTokens(ctx, now.UnixMilli(), deleteLimit)
if err != nil {
logs.CtxWarnf(ctx, "DeleteExpiredAuthorizationCodeTokens failed, err=%v", err)
}
refreshTokenList, err := p.oauthRepo.GetAuthorizationCodeRefreshTokens(ctx, now.UnixMilli(), refreshLimit)
if err != nil {
logs.CtxErrorf(ctx, "GetAuthorizationCodeRefreshTokens failed, err=%v", err)
<-time.After(time.Second)
continue
}
taskGroups := taskgroup.NewTaskGroup(ctx, 3)
expired := make([]int64, 0, len(refreshTokenList))
for _, info := range refreshTokenList {
if info.GetNextTokenRefreshAtMS() == 0 || info.TokenExpiredAtMS == 0 {
continue
}
if info.GetNextTokenRefreshAtMS() > now.UnixMilli() ||
info.LastActiveAtMS <= lastActiveAt.UnixMilli() {
expired = append(expired, info.RecordID)
continue
}
taskGroups.Go(func() error {
p.refreshToken(ctx, info)
return nil
})
}
_ = taskGroups.Wait()
if len(expired) > 0 {
err = p.oauthRepo.BatchDeleteAuthorizationCodeByIDs(ctx, expired)
if err != nil {
logs.CtxWarnf(ctx, "BatchDeleteAuthorizationCodeByIDs failed, err=%v", err)
}
}
<-time.After(5 * time.Second)
}
}
func (p *pluginServiceImpl) refreshToken(ctx context.Context, info *entity.AuthorizationCodeInfo) {
config := oauth2.Config{
ClientID: info.Config.ClientID,
ClientSecret: info.Config.ClientSecret,
Endpoint: oauth2.Endpoint{
TokenURL: info.Config.AuthorizationURL,
},
Scopes: strings.Split(info.Config.Scope, " "),
}
token := &oauth2.Token{
AccessToken: info.AccessToken,
RefreshToken: info.RefreshToken,
Expiry: time.UnixMilli(info.TokenExpiredAtMS),
}
source := config.TokenSource(ctx, token)
var (
err error
newToken *oauth2.Token
)
for i := 0; i < 3; i++ {
newToken, err = source.Token()
if err == nil {
token = newToken
break
}
<-time.After(time.Second)
}
if err != nil {
logs.CtxInfof(ctx, "refreshToken failed, recordID=%d, err=%v", info.RecordID, err)
err = p.oauthRepo.BatchDeleteAuthorizationCodeByIDs(ctx, []int64{info.RecordID})
if err != nil {
logs.CtxErrorf(ctx, "BatchDeleteAuthorizationCodeByIDs failed, recordID=%d, err=%v", info.RecordID, err)
}
return
}
for i := 0; i < 3; i++ {
var expiredAtMS int64
if !token.Expiry.IsZero() && token.Expiry.After(time.Now()) {
expiredAtMS = token.Expiry.UnixMilli()
}
err = p.oauthRepo.UpsertAuthorizationCode(ctx, &entity.AuthorizationCodeInfo{
Meta: &entity.AuthorizationCodeMeta{
UserID: info.Meta.UserID,
PluginID: info.Meta.PluginID,
IsDraft: info.Meta.IsDraft,
},
Config: info.Config,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
TokenExpiredAtMS: expiredAtMS,
NextTokenRefreshAtMS: ptr.Of(getNextTokenRefreshAtMS(expiredAtMS)),
})
if err == nil {
break
}
<-time.After(time.Second)
}
if err != nil {
logs.CtxInfof(ctx, "UpsertAuthorizationCode failed, recordID=%d, err=%v", info.RecordID, err)
err = p.oauthRepo.BatchDeleteAuthorizationCodeByIDs(ctx, []int64{info.RecordID})
if err != nil {
logs.CtxErrorf(ctx, "BatchDeleteAuthorizationCodeByIDs failed, recordID=%d, err=%v", info.RecordID, err)
}
}
}
func (p *pluginServiceImpl) GetAccessToken(ctx context.Context, oa *entity.OAuthInfo) (accessToken string, err error) {
switch oa.OAuthMode {
case model.AuthzSubTypeOfOAuthAuthorizationCode:
accessToken, err = p.getAccessTokenByAuthorizationCode(ctx, oa.AuthorizationCode)
default:
return "", fmt.Errorf("invalid oauth mode '%s'", oa.OAuthMode)
}
if err != nil {
return "", err
}
return accessToken, nil
}
func (p *pluginServiceImpl) getAccessTokenByAuthorizationCode(ctx context.Context, ci *entity.AuthorizationCodeInfo) (accessToken string, err error) {
meta := ci.Meta
info, exist, err := p.oauthRepo.GetAuthorizationCode(ctx, ci.Meta)
if err != nil {
return "", errorx.Wrapf(err, "GetAuthorizationCode failed, userID=%s, pluginID=%d, isDraft=%p",
meta.UserID, meta.PluginID, meta.IsDraft)
}
if !exist {
return "", nil
}
if !isValidAuthCodeConfig(info.Config, ci.Config, info.TokenExpiredAtMS, info.LastActiveAtMS) {
return "", nil
}
now := time.Now().UnixMilli()
if now-info.LastActiveAtMS > time.Minute.Milliseconds() { // don't update too frequently
err = p.oauthRepo.UpdateAuthorizationCodeLastActiveAt(ctx, meta, now)
if err != nil {
logs.CtxWarnf(ctx, "UpdateAuthorizationCodeLastActiveAt failed, userID=%s, pluginID=%d, isDraft=%t, err=%v",
meta.UserID, meta.PluginID, meta.IsDraft, err)
}
}
return info.AccessToken, nil
}
func isValidAuthCodeConfig(o, n *model.OAuthAuthorizationCodeConfig, expireAt, lastActiveAt int64) bool {
now := time.Now()
if expireAt > 0 && expireAt <= now.UnixMilli() {
return false
}
if lastActiveAt > 0 && lastActiveAt <= now.Add(-lastActiveInterval).UnixMilli() {
return false
}
if o.ClientID != n.ClientID {
return false
}
if o.ClientSecret != n.ClientSecret {
return false
}
if o.ClientURL != n.ClientURL {
return false
}
if o.AuthorizationURL != n.AuthorizationURL {
return false
}
if o.AuthorizationContentType != n.AuthorizationContentType {
return false
}
oldScope := strings.Split(o.Scope, " ")
newScope := strings.Split(n.Scope, " ")
if len(oldScope) != len(newScope) {
return false
}
m := make(map[string]bool, len(oldScope))
for _, v := range oldScope {
m[v] = false
}
for _, v := range newScope {
if _, ok := m[v]; !ok {
return false
}
}
return true
}
func (p *pluginServiceImpl) OAuthCode(ctx context.Context, code string, state *entity.OAuthState) (err error) {
var plugin *entity.PluginInfo
if state.IsDraft {
plugin, err = p.GetDraftPlugin(ctx, state.PluginID)
} else {
plugin, err = p.GetOnlinePlugin(ctx, state.PluginID)
}
if err != nil {
return errorx.Wrapf(err, "GetPlugin failed, pluginID=%d", state.PluginID)
}
authInfo := plugin.GetAuthInfo()
if authInfo.SubType != model.AuthzSubTypeOfOAuthAuthorizationCode {
return errorx.New(errno.ErrPluginOAuthFailed, errorx.KV(errno.PluginMsgKey, "plugin auth type is not oauth authorization code"))
}
if authInfo.AuthOfOAuthAuthorizationCode == nil {
return errorx.New(errno.ErrPluginOAuthFailed, errorx.KV(errno.PluginMsgKey, "plugin auth info is nil"))
}
config := getStanderOAuthConfig(authInfo.AuthOfOAuthAuthorizationCode)
token, err := config.Exchange(ctx, code)
if err != nil {
return errorx.WrapByCode(err, errno.ErrPluginOAuthFailed, errorx.KV(errno.PluginMsgKey, "exchange token failed"))
}
meta := &entity.AuthorizationCodeMeta{
UserID: state.UserID,
PluginID: state.PluginID,
IsDraft: state.IsDraft,
}
var expiredAtMS int64
if !token.Expiry.IsZero() && token.Expiry.After(time.Now()) {
expiredAtMS = token.Expiry.UnixMilli()
}
err = p.saveAccessToken(ctx, &entity.OAuthInfo{
OAuthMode: model.AuthzSubTypeOfOAuthAuthorizationCode,
AuthorizationCode: &entity.AuthorizationCodeInfo{
Meta: meta,
Config: authInfo.AuthOfOAuthAuthorizationCode,
AccessToken: token.AccessToken,
RefreshToken: token.RefreshToken,
TokenExpiredAtMS: expiredAtMS,
NextTokenRefreshAtMS: ptr.Of(getNextTokenRefreshAtMS(expiredAtMS)),
LastActiveAtMS: time.Now().UnixMilli(),
},
})
if err != nil {
return errorx.Wrapf(err, "SaveAccessToken failed, pluginID=%d", state.PluginID)
}
return nil
}
func (p *pluginServiceImpl) saveAccessToken(ctx context.Context, oa *entity.OAuthInfo) (err error) {
switch oa.OAuthMode {
case model.AuthzSubTypeOfOAuthAuthorizationCode:
err = p.saveAuthCodeAccessToken(ctx, oa.AuthorizationCode)
default:
return fmt.Errorf("[standardOAuth] invalid oauth mode '%s'", oa.OAuthMode)
}
return err
}
func (p *pluginServiceImpl) saveAuthCodeAccessToken(ctx context.Context, info *entity.AuthorizationCodeInfo) (err error) {
meta := info.Meta
err = p.oauthRepo.UpsertAuthorizationCode(ctx, info)
if err != nil {
return errorx.Wrapf(err, "SaveAuthorizationCodeInfo failed, userID=%s, pluginID=%d, isDraft=%t",
meta.UserID, meta.PluginID, meta.IsDraft)
}
return nil
}
func getNextTokenRefreshAtMS(expiredAtMS int64) int64 {
if expiredAtMS == 0 {
return 0
}
return time.Now().Add(time.Duration((expiredAtMS-time.Now().UnixMilli())/2) * time.Millisecond).UnixMilli()
}
func (p *pluginServiceImpl) RevokeAccessToken(ctx context.Context, meta *entity.AuthorizationCodeMeta) (err error) {
return p.oauthRepo.DeleteAuthorizationCode(ctx, meta)
}
func (p *pluginServiceImpl) GetOAuthStatus(ctx context.Context, userID, pluginID int64) (resp *GetOAuthStatusResponse, err error) {
pl, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pluginID)
if err != nil {
return nil, err
}
if !exist {
return nil, fmt.Errorf("draft plugin '%d' not found", pluginID)
}
authInfo := pl.GetAuthInfo()
if authInfo.Type == model.AuthzTypeOfNone || authInfo.Type == model.AuthzTypeOfService {
return &GetOAuthStatusResponse{
IsOauth: false,
}, nil
}
needAuth, authURL, err := p.getPluginOAuthStatus(ctx, userID, pl, true)
if err != nil {
return nil, err
}
status := common.OAuthStatus_Authorized
if needAuth {
status = common.OAuthStatus_Unauthorized
}
resp = &GetOAuthStatusResponse{
IsOauth: true,
Status: status,
OAuthURL: authURL,
}
return resp, nil
}
func (p *pluginServiceImpl) getPluginOAuthStatus(ctx context.Context, userID int64, plugin *entity.PluginInfo, isDraft bool) (needAuth bool, authURL string, err error) {
authInfo := plugin.GetAuthInfo()
if authInfo.Type != model.AuthzTypeOfOAuth {
return false, "", fmt.Errorf("invalid auth type '%v'", authInfo.Type)
}
if authInfo.SubType != model.AuthzSubTypeOfOAuthAuthorizationCode {
return false, "", fmt.Errorf("invalid auth sub type '%v'", authInfo.SubType)
}
authCode := &entity.AuthorizationCodeInfo{
Meta: &entity.AuthorizationCodeMeta{
UserID: conv.Int64ToStr(userID),
PluginID: plugin.ID,
IsDraft: isDraft,
},
Config: plugin.Manifest.Auth.AuthOfOAuthAuthorizationCode,
}
accessToken, err := p.GetAccessToken(ctx, &entity.OAuthInfo{
OAuthMode: model.AuthzSubTypeOfOAuthAuthorizationCode,
AuthorizationCode: authCode,
})
if err != nil {
return false, "", err
}
needAuth = accessToken == ""
authURL, err = genAuthURL(authCode)
if err != nil {
return false, "", err
}
return needAuth, authURL, nil
}
func genAuthURL(info *entity.AuthorizationCodeInfo) (string, error) {
config := getStanderOAuthConfig(info.Config)
state := &entity.OAuthState{
ClientName: "",
UserID: info.Meta.UserID,
PluginID: info.Meta.PluginID,
IsDraft: info.Meta.IsDraft,
}
stateStr, err := json.Marshal(state)
if err != nil {
return "", fmt.Errorf("marshal state failed, err=%v", err)
}
encryptState, err := utils.EncryptByAES(stateStr, utils.StateSecretKey)
if err != nil {
return "", fmt.Errorf("encrypt state failed, err=%v", err)
}
authURL := config.AuthCodeURL(encryptState)
return authURL, nil
}
func getStanderOAuthConfig(config *model.OAuthAuthorizationCodeConfig) *oauth2.Config {
if config == nil {
return nil
}
return &oauth2.Config{
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
Endpoint: oauth2.Endpoint{
TokenURL: config.AuthorizationURL,
AuthURL: config.ClientURL,
},
RedirectURL: fmt.Sprintf("https://%s/api/oauth/authorization_code", os.Getenv("SERVER_HOST")),
Scopes: strings.Split(config.Scope, " "),
}
}
func (p *pluginServiceImpl) GetAgentPluginsOAuthStatus(ctx context.Context, userID, agentID int64) (status []*AgentPluginOAuthStatus, err error) {
pluginIDs, err := p.toolRepo.GetAgentPluginIDs(ctx, agentID)
if err != nil {
return nil, errorx.Wrapf(err, "GetAgentPluginIDs failed, agentID=%d", agentID)
}
if len(pluginIDs) == 0 {
return nil, nil
}
plugins, err := p.pluginRepo.MGetOnlinePlugins(ctx, pluginIDs)
if err != nil {
return nil, errorx.Wrapf(err, "MGetOnlinePlugins failed, pluginIDs=%v", pluginIDs)
}
for _, plugin := range plugins {
authInfo := plugin.GetAuthInfo()
if authInfo.Type == model.AuthzTypeOfNone || authInfo.Type == model.AuthzTypeOfService {
continue
}
needAuth, _, err := p.getPluginOAuthStatus(ctx, userID, plugin, false)
if err != nil {
logs.CtxErrorf(ctx, "getPluginOAuthStatus failed, pluginID=%d, err=%v", plugin.ID, err)
continue
}
iconURL := ""
if plugin.GetIconURI() != "" {
iconURL, _ = p.oss.GetObjectUrl(ctx, plugin.GetIconURI())
}
authStatus := common.OAuthStatus_Authorized
if needAuth {
authStatus = common.OAuthStatus_Unauthorized
}
status = append(status, &AgentPluginOAuthStatus{
PluginID: plugin.ID,
PluginName: plugin.GetName(),
PluginIconURL: iconURL,
Status: authStatus,
})
}
return status, nil
}

View File

@@ -0,0 +1,382 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"fmt"
"sort"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
searchModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/search"
pluginCommon "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
resCommon "github.com/coze-dev/coze-studio/backend/api/model/resource/common"
"github.com/coze-dev/coze-studio/backend/crossdomain/contract/crosssearch"
pluginConf "github.com/coze-dev/coze-studio/backend/domain/plugin/conf"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
func (p *pluginServiceImpl) GetOnlinePlugin(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, err error) {
pl, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pluginID)
if err != nil {
return nil, errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", pluginID)
}
if !exist {
return nil, errorx.New(errno.ErrPluginRecordNotFound)
}
return pl, nil
}
func (p *pluginServiceImpl) MGetOnlinePlugins(ctx context.Context, pluginIDs []int64) (plugins []*entity.PluginInfo, err error) {
plugins, err = p.pluginRepo.MGetOnlinePlugins(ctx, pluginIDs)
if err != nil {
return nil, errorx.Wrapf(err, "MGetOnlinePlugins failed, pluginIDs=%v", pluginIDs)
}
res := make([]*model.PluginInfo, 0, len(plugins))
for _, pl := range plugins {
res = append(res, pl.PluginInfo)
}
return plugins, nil
}
func (p *pluginServiceImpl) GetOnlineTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, err error) {
tool, exist, err := p.toolRepo.GetOnlineTool(ctx, toolID)
if err != nil {
return nil, errorx.Wrapf(err, "GetOnlineTool failed, toolID=%d", toolID)
}
if !exist {
return nil, errorx.New(errno.ErrPluginRecordNotFound)
}
return tool, nil
}
func (p *pluginServiceImpl) MGetOnlineTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error) {
tools, err = p.toolRepo.MGetOnlineTools(ctx, toolIDs)
if err != nil {
return nil, errorx.Wrapf(err, "MGetOnlineTools failed, toolIDs=%v", toolIDs)
}
return tools, nil
}
func (p *pluginServiceImpl) MGetVersionTools(ctx context.Context, versionTools []entity.VersionTool) (tools []*entity.ToolInfo, err error) {
tools, err = p.toolRepo.MGetVersionTools(ctx, versionTools)
if err != nil {
return nil, errorx.Wrapf(err, "MGetVersionTools failed, versionTools=%v", versionTools)
}
return tools, nil
}
func (p *pluginServiceImpl) ListPluginProducts(ctx context.Context, req *ListPluginProductsRequest) (resp *ListPluginProductsResponse, err error) {
plugins := slices.Transform(pluginConf.GetAllPluginProducts(), func(p *pluginConf.PluginInfo) *entity.PluginInfo {
return entity.NewPluginInfo(p.Info)
})
sort.Slice(plugins, func(i, j int) bool {
return plugins[i].GetRefProductID() < plugins[j].GetRefProductID()
})
return &ListPluginProductsResponse{
Plugins: plugins,
Total: int64(len(plugins)),
}, nil
}
func (p *pluginServiceImpl) GetPluginProductAllTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error) {
res, err := p.toolRepo.GetPluginAllOnlineTools(ctx, pluginID)
if err != nil {
return nil, errorx.Wrapf(err, "GetPluginAllOnlineTools failed, pluginID=%d", pluginID)
}
return res, nil
}
func (p *pluginServiceImpl) DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error) {
return p.pluginRepo.DeleteAPPAllPlugins(ctx, appID)
}
func (p *pluginServiceImpl) GetAPPAllPlugins(ctx context.Context, appID int64) (plugins []*entity.PluginInfo, err error) {
plugins, err = p.pluginRepo.GetAPPAllDraftPlugins(ctx, appID)
if err != nil {
return nil, errorx.Wrapf(err, "GetAPPAllDraftPlugins failed, appID=%d", appID)
}
return plugins, nil
}
func (p *pluginServiceImpl) MGetVersionPlugins(ctx context.Context, versionPlugins []entity.VersionPlugin) (plugins []*entity.PluginInfo, err error) {
plugins, err = p.pluginRepo.MGetVersionPlugins(ctx, versionPlugins)
if err != nil {
return nil, errorx.Wrapf(err, "MGetVersionPlugins failed, versionPlugins=%v", versionPlugins)
}
return plugins, nil
}
func (p *pluginServiceImpl) ListCustomOnlinePlugins(ctx context.Context, spaceID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error) {
if pageInfo.Name == nil || *pageInfo.Name == "" {
plugins, total, err = p.pluginRepo.ListCustomOnlinePlugins(ctx, spaceID, pageInfo)
if err != nil {
return nil, 0, errorx.Wrapf(err, "ListCustomOnlinePlugins failed, spaceID=%d", spaceID)
}
return plugins, total, nil
}
res, err := crosssearch.DefaultSVC().SearchResources(ctx, &searchModel.SearchResourcesRequest{
SpaceID: spaceID,
Name: *pageInfo.Name,
OrderAsc: false,
ResTypeFilter: []resCommon.ResType{
resCommon.ResType_Plugin,
},
OrderFiledName: func() string {
if pageInfo.SortBy == nil || *pageInfo.SortBy != entity.SortByCreatedAt {
return searchModel.FieldOfUpdateTime
}
return searchModel.FieldOfCreateTime
}(),
Page: ptr.Of(int32(pageInfo.Page)),
Limit: int32(pageInfo.Size),
})
if err != nil {
return nil, 0, errorx.Wrapf(err, "SearchResources failed, spaceID=%d", spaceID)
}
plugins = make([]*entity.PluginInfo, 0, len(res.Data))
for _, pl := range res.Data {
draftPlugin, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pl.ResID)
if err != nil {
return nil, 0, errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", pl.ResID)
}
if !exist {
logs.CtxWarnf(ctx, "online plugin not exist, pluginID=%d", pl.ResID)
continue
}
plugins = append(plugins, draftPlugin)
}
if res.TotalHits != nil {
total = *res.TotalHits
}
return plugins, total, nil
}
func (p *pluginServiceImpl) MGetPluginLatestVersion(ctx context.Context, pluginIDs []int64) (resp *MGetPluginLatestVersionResponse, err error) {
plugins, err := p.pluginRepo.MGetOnlinePlugins(ctx, pluginIDs,
repository.WithPluginID(),
repository.WithPluginVersion())
if err != nil {
return nil, errorx.Wrapf(err, "MGetOnlinePlugins failed, pluginIDs=%v", pluginIDs)
}
versions := make(map[int64]string, len(plugins))
for _, pl := range plugins {
versions[pl.ID] = pl.GetVersion()
}
resp = &MGetPluginLatestVersionResponse{
Versions: versions,
}
return resp, nil
}
func (p *pluginServiceImpl) CopyPlugin(ctx context.Context, req *CopyPluginRequest) (resp *CopyPluginResponse, err error) {
err = p.checkCanCopyPlugin(ctx, req.PluginID, req.CopyScene)
if err != nil {
return nil, err
}
plugin, tools, err := p.getCopySourcePluginAndTools(ctx, req.PluginID, req.CopyScene)
if err != nil {
return nil, err
}
p.changePluginAndToolsInfoForCopy(req, plugin, tools)
toolMap := make(map[int64]*entity.ToolInfo, len(tools))
for _, tool := range tools {
toolMap[tool.ID] = tool
}
plugin, tools, err = p.pluginRepo.CopyPlugin(ctx, &repository.CopyPluginRequest{
Plugin: plugin,
Tools: tools,
})
if err != nil {
return nil, errorx.Wrapf(err, "CopyPlugin failed, pluginID=%d", req.PluginID)
}
resp = &CopyPluginResponse{
Plugin: plugin,
Tools: toolMap,
}
return resp, nil
}
func (p *pluginServiceImpl) changePluginAndToolsInfoForCopy(req *CopyPluginRequest, plugin *entity.PluginInfo, tools []*entity.ToolInfo) {
plugin.Version = nil
plugin.VersionDesc = nil
plugin.DeveloperID = req.UserID
if req.CopyScene != model.CopySceneOfAPPDuplicate {
plugin.SetName(fmt.Sprintf("%s_copy", plugin.GetName()))
}
if req.CopyScene == model.CopySceneOfToLibrary {
const (
defaultVersion = "v0.0.1"
defaultVersionDesc = "copy to library"
)
plugin.APPID = nil
plugin.Version = ptr.Of(defaultVersion)
plugin.VersionDesc = ptr.Of(defaultVersionDesc)
for _, tool := range tools {
tool.Version = ptr.Of(defaultVersion)
}
}
if req.CopyScene == model.CopySceneOfToAPP {
plugin.APPID = req.TargetAPPID
for _, tool := range tools {
tool.DebugStatus = ptr.Of(pluginCommon.APIDebugStatus_DebugPassed)
}
}
if req.CopyScene == model.CopySceneOfAPPDuplicate {
plugin.APPID = req.TargetAPPID
}
}
func (p *pluginServiceImpl) checkCanCopyPlugin(ctx context.Context, pluginID int64, scene model.CopyScene) (err error) {
switch scene {
case model.CopySceneOfToAPP, model.CopySceneOfDuplicate, model.CopySceneOfAPPDuplicate:
return nil
case model.CopySceneOfToLibrary:
return p.checkToolsDebugStatus(ctx, pluginID)
default:
return fmt.Errorf("unsupported copy scene '%s'", scene)
}
}
func (p *pluginServiceImpl) getCopySourcePluginAndTools(ctx context.Context, pluginID int64, scene model.CopyScene) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
switch scene {
case model.CopySceneOfToAPP:
return p.getOnlinePluginAndTools(ctx, pluginID)
case model.CopySceneOfToLibrary, model.CopySceneOfDuplicate, model.CopySceneOfAPPDuplicate:
return p.getDraftPluginAndTools(ctx, pluginID)
default:
return nil, nil, fmt.Errorf("unsupported copy scene '%s'", scene)
}
}
func (p *pluginServiceImpl) getOnlinePluginAndTools(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
onlinePlugin, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pluginID)
if err != nil {
return nil, nil, err
}
if !exist {
return nil, nil, errorx.New(errno.ErrPluginRecordNotFound)
}
onlineTools, err := p.toolRepo.GetPluginAllOnlineTools(ctx, pluginID)
if err != nil {
return nil, nil, err
}
return onlinePlugin, onlineTools, nil
}
func (p *pluginServiceImpl) getDraftPluginAndTools(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, tools []*entity.ToolInfo, err error) {
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pluginID)
if err != nil {
return nil, nil, err
}
if !exist {
return nil, nil, errorx.New(errno.ErrPluginRecordNotFound)
}
draftTools, err := p.toolRepo.GetPluginAllDraftTools(ctx, pluginID)
if err != nil {
return nil, nil, err
}
return draftPlugin, draftTools, nil
}
func (p *pluginServiceImpl) MoveAPPPluginToLibrary(ctx context.Context, pluginID int64) (draftPlugin *entity.PluginInfo, err error) {
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, pluginID)
if err != nil {
return nil, err
}
if !exist {
return nil, errorx.New(errno.ErrPluginRecordNotFound)
}
err = p.checkToolsDebugStatus(ctx, pluginID)
if err != nil {
return nil, err
}
draftTools, err := p.toolRepo.GetPluginAllDraftTools(ctx, pluginID)
if err != nil {
return nil, err
}
p.changePluginAndToolsInfoForMove(draftPlugin, draftTools)
err = p.pluginRepo.MoveAPPPluginToLibrary(ctx, draftPlugin, draftTools)
if err != nil {
return nil, errorx.Wrapf(err, "MoveAPPPluginToLibrary failed, pluginID=%d", pluginID)
}
return draftPlugin, nil
}
func (p *pluginServiceImpl) changePluginAndToolsInfoForMove(plugin *entity.PluginInfo,
tools []*entity.ToolInfo) {
const (
defaultVersion = "v0.0.1"
defaultVersionDesc = "move to library"
)
plugin.Version = ptr.Of(defaultVersion)
plugin.VersionDesc = ptr.Of(defaultVersionDesc)
for _, tool := range tools {
tool.Version = ptr.Of(defaultVersion)
}
plugin.APPID = nil
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"fmt"
"strconv"
"strings"
"golang.org/x/mod/semver"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
"github.com/coze-dev/coze-studio/backend/pkg/lang/slices"
"github.com/coze-dev/coze-studio/backend/pkg/logs"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
func (p *pluginServiceImpl) GetPluginNextVersion(ctx context.Context, pluginID int64) (version string, err error) {
const defaultVersion = "v1.0.0"
pl, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, pluginID)
if err != nil {
return "", errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", pluginID)
}
if !exist {
return defaultVersion, nil
}
parts := strings.Split(pl.GetVersion(), ".") // Remove the 'v' and split
if len(parts) < 3 {
logs.CtxWarnf(ctx, "invalid version format '%s'", pl.GetVersion())
return defaultVersion, nil
}
patch, err := strconv.ParseInt(parts[2], 10, 64)
if err != nil {
logs.CtxWarnf(ctx, "invalid version format '%s'", pl.GetVersion())
return defaultVersion, nil
}
parts[2] = strconv.FormatInt(patch+1, 10)
nextVersion := strings.Join(parts, ".")
return nextVersion, nil
}
func (p *pluginServiceImpl) PublishPlugin(ctx context.Context, req *PublishPluginRequest) (err error) {
draftPlugin, exist, err := p.pluginRepo.GetDraftPlugin(ctx, req.PluginID)
if err != nil {
return errorx.Wrapf(err, "GetDraftPlugin failed, pluginID=%d", req.PluginID)
}
if !exist {
return errorx.New(errno.ErrPluginRecordNotFound)
}
err = p.checkToolsDebugStatus(ctx, req.PluginID)
if err != nil {
return err
}
onlinePlugin, exist, err := p.pluginRepo.GetOnlinePlugin(ctx, req.PluginID)
if err != nil {
return errorx.Wrapf(err, "GetOnlinePlugin failed, pluginID=%d", req.PluginID)
}
if exist && onlinePlugin.Version != nil {
if semver.Compare(req.Version, *onlinePlugin.Version) != 1 {
return errorx.New(errno.ErrPluginInvalidParamCode,
errorx.KVf(errno.PluginMsgKey, "version must be greater than the online version '%s' and format like 'v1.0.0'",
*onlinePlugin.Version))
}
}
draftPlugin.Version = &req.Version
draftPlugin.VersionDesc = &req.VersionDesc
err = p.pluginRepo.PublishPlugin(ctx, draftPlugin)
if err != nil {
return errorx.Wrapf(err, "PublishPlugin failed, pluginID=%d", req.PluginID)
}
return nil
}
func (p *pluginServiceImpl) PublishAPPPlugins(ctx context.Context, req *PublishAPPPluginsRequest) (resp *PublishAPPPluginsResponse, err error) {
resp = &PublishAPPPluginsResponse{}
draftPlugins, err := p.pluginRepo.GetAPPAllDraftPlugins(ctx, req.APPID)
if err != nil {
return nil, errorx.Wrapf(err, "GetAPPAllDraftPlugins failed, appID=%d", req.APPID)
}
failedPluginIDs, err := p.checkCanPublishAPPPlugins(ctx, req.Version, draftPlugins)
if err != nil {
return nil, errorx.Wrapf(err, "checkCanPublishAPPPlugins failed, appID=%d, appVerion=%s", req.APPID, req.Version)
}
for _, draftPlugin := range draftPlugins {
draftPlugin.Version = &req.Version
draftPlugin.VersionDesc = ptr.Of(fmt.Sprintf("publish %s", req.Version))
resp.AllDraftPlugins = append(resp.AllDraftPlugins, draftPlugin.PluginInfo)
}
if len(failedPluginIDs) > 0 {
draftPluginMap := slices.ToMap(draftPlugins, func(plugin *entity.PluginInfo) (int64, *entity.PluginInfo) {
return plugin.ID, plugin
})
failedPlugins := make([]*entity.PluginInfo, 0, len(failedPluginIDs))
for _, failedPluginID := range failedPluginIDs {
failedPlugins = append(failedPlugins, draftPluginMap[failedPluginID])
}
for _, failedPlugin := range failedPlugins {
resp.FailedPlugins = append(resp.FailedPlugins, failedPlugin.PluginInfo)
}
return resp, nil
}
err = p.pluginRepo.PublishPlugins(ctx, draftPlugins)
if err != nil {
return nil, errorx.Wrapf(err, "PublishPlugins failed, appID=%d", req.APPID)
}
return resp, nil
}
func (p *pluginServiceImpl) checkCanPublishAPPPlugins(ctx context.Context, version string, draftPlugins []*entity.PluginInfo) (failedPluginIDs []int64, err error) {
failedPluginIDs = make([]int64, 0, len(draftPlugins))
draftPluginIDs := slices.Transform(draftPlugins, func(plugin *entity.PluginInfo) int64 {
return plugin.ID
})
// 1. check version
onlinePlugins, err := p.pluginRepo.MGetOnlinePlugins(ctx, draftPluginIDs,
repository.WithPluginID(),
repository.WithPluginVersion())
if err != nil {
return nil, errorx.Wrapf(err, "MGetOnlinePlugins failed, pluginIDs=%v", draftPluginIDs)
}
if len(onlinePlugins) > 0 {
for _, onlinePlugin := range onlinePlugins {
if onlinePlugin.Version == nil {
continue
}
if semver.Compare(version, *onlinePlugin.Version) != 1 {
failedPluginIDs = append(failedPluginIDs, onlinePlugin.ID)
}
}
if len(failedPluginIDs) > 0 {
logs.CtxErrorf(ctx, "invalid version of plugins '%v'", failedPluginIDs)
return failedPluginIDs, nil
}
}
// 2. check debug status
for _, draftPlugin := range draftPlugins {
err = p.checkToolsDebugStatus(ctx, draftPlugin.ID)
if err != nil {
failedPluginIDs = append(failedPluginIDs, draftPlugin.ID)
logs.CtxErrorf(ctx, "checkToolsDebugStatus failed, pluginID=%d, err=%s", draftPlugin.ID, err)
}
}
if len(failedPluginIDs) > 0 {
return failedPluginIDs, nil
}
return failedPluginIDs, nil
}
func (p *pluginServiceImpl) checkToolsDebugStatus(ctx context.Context, pluginID int64) (err error) {
res, err := p.toolRepo.GetPluginAllDraftTools(ctx, pluginID,
repository.WithToolID(),
repository.WithToolDebugStatus(),
repository.WithToolActivatedStatus(),
)
if err != nil {
return errorx.Wrapf(err, "GetPluginAllDraftTools failed, pluginID=%d", pluginID)
}
if len(res) == 0 {
return errorx.New(errno.ErrPluginToolsCheckFailed, errorx.KVf(errno.PluginMsgKey,
"at least one activated tool is required in plugin"))
}
activatedTools := make([]*entity.ToolInfo, 0, len(res))
for _, tool := range res {
if tool.GetActivatedStatus() == model.DeactivateTool {
continue
}
activatedTools = append(activatedTools, tool)
}
if len(activatedTools) == 0 {
return errorx.New(errno.ErrPluginToolsCheckFailed, errorx.KVf(errno.PluginMsgKey,
"at least one activated tool is required in plugin"))
}
for _, tool := range activatedTools {
if tool.GetDebugStatus() != common.APIDebugStatus_DebugWaiting {
continue
}
return errorx.New(errno.ErrPluginToolsCheckFailed, errorx.KVf(errno.PluginMsgKey,
"tools in plugin have not debugged yet"))
}
return nil
}
func (p *pluginServiceImpl) CheckPluginToolsDebugStatus(ctx context.Context, pluginID int64) (err error) {
return p.checkToolsDebugStatus(ctx, pluginID)
}

View File

@@ -0,0 +1,400 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"fmt"
"strings"
"github.com/bytedance/sonic"
"github.com/getkin/kin-openapi/openapi3"
model "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/plugin"
common "github.com/coze-dev/coze-studio/backend/api/model/plugin_develop_common"
"github.com/coze-dev/coze-studio/backend/domain/plugin/entity"
"github.com/coze-dev/coze-studio/backend/pkg/errorx"
"github.com/coze-dev/coze-studio/backend/types/errno"
)
//go:generate mockgen -destination ../../../internal/mock/domain/plugin/interface.go --package mockPlugin -source service.go
type PluginService interface {
// Draft Plugin
CreateDraftPlugin(ctx context.Context, req *CreateDraftPluginRequest) (pluginID int64, err error)
CreateDraftPluginWithCode(ctx context.Context, req *CreateDraftPluginWithCodeRequest) (resp *CreateDraftPluginWithCodeResponse, err error)
GetDraftPlugin(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, err error)
MGetDraftPlugins(ctx context.Context, pluginIDs []int64) (plugins []*entity.PluginInfo, err error)
ListDraftPlugins(ctx context.Context, req *ListDraftPluginsRequest) (resp *ListDraftPluginsResponse, err error)
UpdateDraftPlugin(ctx context.Context, plugin *UpdateDraftPluginRequest) (err error)
UpdateDraftPluginWithCode(ctx context.Context, req *UpdateDraftPluginWithCodeRequest) (err error)
DeleteDraftPlugin(ctx context.Context, pluginID int64) (err error)
DeleteAPPAllPlugins(ctx context.Context, appID int64) (pluginIDs []int64, err error)
GetAPPAllPlugins(ctx context.Context, appID int64) (plugins []*entity.PluginInfo, err error)
// Online Plugin
PublishPlugin(ctx context.Context, req *PublishPluginRequest) (err error)
PublishAPPPlugins(ctx context.Context, req *PublishAPPPluginsRequest) (resp *PublishAPPPluginsResponse, err error)
GetOnlinePlugin(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, err error)
MGetOnlinePlugins(ctx context.Context, pluginIDs []int64) (plugins []*entity.PluginInfo, err error)
MGetPluginLatestVersion(ctx context.Context, pluginIDs []int64) (resp *MGetPluginLatestVersionResponse, err error)
GetPluginNextVersion(ctx context.Context, pluginID int64) (version string, err error)
MGetVersionPlugins(ctx context.Context, versionPlugins []entity.VersionPlugin) (plugins []*entity.PluginInfo, err error)
ListCustomOnlinePlugins(ctx context.Context, spaceID int64, pageInfo entity.PageInfo) (plugins []*entity.PluginInfo, total int64, err error)
// Draft Tool
MGetDraftTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error)
UpdateDraftTool(ctx context.Context, req *UpdateToolDraftRequest) (err error)
ConvertToOpenapi3Doc(ctx context.Context, req *ConvertToOpenapi3DocRequest) (resp *ConvertToOpenapi3DocResponse)
CreateDraftToolsWithCode(ctx context.Context, req *CreateDraftToolsWithCodeRequest) (resp *CreateDraftToolsWithCodeResponse, err error)
CheckPluginToolsDebugStatus(ctx context.Context, pluginID int64) (err error)
// Online Tool
GetOnlineTool(ctx context.Context, toolID int64) (tool *entity.ToolInfo, err error)
MGetOnlineTools(ctx context.Context, toolIDs []int64) (tools []*entity.ToolInfo, err error)
MGetVersionTools(ctx context.Context, versionTools []entity.VersionTool) (tools []*entity.ToolInfo, err error)
CopyPlugin(ctx context.Context, req *CopyPluginRequest) (resp *CopyPluginResponse, err error)
MoveAPPPluginToLibrary(ctx context.Context, pluginID int64) (plugin *entity.PluginInfo, err error)
// Agent Tool
BindAgentTools(ctx context.Context, agentID int64, toolIDs []int64) (err error)
DuplicateDraftAgentTools(ctx context.Context, fromAgentID, toAgentID int64) (err error)
GetDraftAgentToolByName(ctx context.Context, agentID int64, toolName string) (tool *entity.ToolInfo, err error)
MGetAgentTools(ctx context.Context, req *MGetAgentToolsRequest) (tools []*entity.ToolInfo, err error)
UpdateBotDefaultParams(ctx context.Context, req *UpdateBotDefaultParamsRequest) (err error)
PublishAgentTools(ctx context.Context, agentID int64, agentVersion string) (err error)
ExecuteTool(ctx context.Context, req *ExecuteToolRequest, opts ...entity.ExecuteToolOpt) (resp *ExecuteToolResponse, err error)
// Product
ListPluginProducts(ctx context.Context, req *ListPluginProductsRequest) (resp *ListPluginProductsResponse, err error)
GetPluginProductAllTools(ctx context.Context, pluginID int64) (tools []*entity.ToolInfo, err error)
GetOAuthStatus(ctx context.Context, userID, pluginID int64) (resp *GetOAuthStatusResponse, err error)
GetAgentPluginsOAuthStatus(ctx context.Context, userID, agentID int64) (status []*AgentPluginOAuthStatus, err error)
OAuthCode(ctx context.Context, code string, state *entity.OAuthState) (err error)
GetAccessToken(ctx context.Context, oa *entity.OAuthInfo) (accessToken string, err error)
RevokeAccessToken(ctx context.Context, meta *entity.AuthorizationCodeMeta) (err error)
}
type CreateDraftPluginRequest struct {
PluginType common.PluginType
IconURI string
SpaceID int64
DeveloperID int64
ProjectID *int64
Name string
Desc string
ServerURL string
CommonParams map[common.ParameterLocation][]*common.CommonParamSchema
AuthInfo *PluginAuthInfo
}
type UpdateDraftPluginWithCodeRequest struct {
UserID int64
PluginID int64
OpenapiDoc *model.Openapi3T
Manifest *entity.PluginManifest
}
type UpdateDraftPluginRequest struct {
PluginID int64
Name *string
Desc *string
URL *string
Icon *common.PluginIcon
CommonParams map[common.ParameterLocation][]*common.CommonParamSchema
AuthInfo *PluginAuthInfo
}
type ListDraftPluginsRequest struct {
SpaceID int64
APPID int64
PageInfo entity.PageInfo
}
type ListDraftPluginsResponse struct {
Plugins []*entity.PluginInfo
Total int64
}
type CreateDraftPluginWithCodeRequest struct {
SpaceID int64
DeveloperID int64
ProjectID *int64
Manifest *entity.PluginManifest
OpenapiDoc *model.Openapi3T
}
type CreateDraftPluginWithCodeResponse struct {
Plugin *entity.PluginInfo
Tools []*entity.ToolInfo
}
type CreateDraftToolsWithCodeRequest struct {
PluginID int64
OpenapiDoc *model.Openapi3T
ConflictAndUpdate bool
}
type CreateDraftToolsWithCodeResponse struct {
DuplicatedTools []entity.UniqueToolAPI
}
type PluginAuthInfo struct {
AuthzType *model.AuthzType
Location *model.HTTPParamLocation
Key *string
ServiceToken *string
OAuthInfo *string
AuthzSubType *model.AuthzSubType
AuthzPayload *string
}
func (p PluginAuthInfo) toAuthV2() (*model.AuthV2, error) {
if p.AuthzType == nil {
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey, "auth type is required"))
}
switch *p.AuthzType {
case model.AuthzTypeOfNone:
return &model.AuthV2{
Type: model.AuthzTypeOfNone,
}, nil
case model.AuthzTypeOfOAuth:
m, err := p.authOfOAuthToAuthV2()
if err != nil {
return nil, err
}
return m, nil
case model.AuthzTypeOfService:
m, err := p.authOfServiceToAuthV2()
if err != nil {
return nil, err
}
return m, nil
default:
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
"the type '%s' of auth is invalid", *p.AuthzType))
}
}
func (p PluginAuthInfo) authOfOAuthToAuthV2() (*model.AuthV2, error) {
if p.AuthzSubType == nil {
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey, "sub-auth type is required"))
}
if p.OAuthInfo == nil || *p.OAuthInfo == "" {
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey, "oauth info is required"))
}
oauthInfo := make(map[string]string)
err := sonic.Unmarshal([]byte(*p.OAuthInfo), &oauthInfo)
if err != nil {
return nil, errorx.WrapByCode(err, errno.ErrPluginInvalidManifest, errorx.KV(errno.PluginMsgKey, "invalid oauth info"))
}
if *p.AuthzSubType == model.AuthzSubTypeOfOAuthClientCredentials {
_oauthInfo := &model.OAuthClientCredentialsConfig{
ClientID: oauthInfo["client_id"],
ClientSecret: oauthInfo["client_secret"],
TokenURL: oauthInfo["token_url"],
}
str, err := sonic.MarshalString(_oauthInfo)
if err != nil {
return nil, fmt.Errorf("marshal oauth info failed, err=%v", err)
}
return &model.AuthV2{
Type: model.AuthzTypeOfOAuth,
SubType: model.AuthzSubTypeOfOAuthClientCredentials,
Payload: str,
AuthOfOAuthClientCredentials: _oauthInfo,
}, nil
}
if *p.AuthzSubType == model.AuthzSubTypeOfOAuthAuthorizationCode {
contentType := oauthInfo["authorization_content_type"]
if contentType != model.MediaTypeJson { // only support application/json
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
"the type '%s' of authorization content is invalid", contentType))
}
_oauthInfo := &model.OAuthAuthorizationCodeConfig{
ClientID: oauthInfo["client_id"],
ClientSecret: oauthInfo["client_secret"],
ClientURL: oauthInfo["client_url"],
Scope: oauthInfo["scope"],
AuthorizationURL: oauthInfo["authorization_url"],
AuthorizationContentType: contentType,
}
str, err := sonic.MarshalString(_oauthInfo)
if err != nil {
return nil, fmt.Errorf("marshal oauth info failed, err=%v", err)
}
return &model.AuthV2{
Type: model.AuthzTypeOfOAuth,
SubType: model.AuthzSubTypeOfOAuthAuthorizationCode,
Payload: str,
AuthOfOAuthAuthorizationCode: _oauthInfo,
}, nil
}
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
"the type '%s' of sub-auth is invalid", *p.AuthzSubType))
}
func (p PluginAuthInfo) authOfServiceToAuthV2() (*model.AuthV2, error) {
if p.AuthzSubType == nil {
return nil, fmt.Errorf("sub-auth type is required")
}
if *p.AuthzSubType == model.AuthzSubTypeOfServiceAPIToken {
if p.Location == nil {
return nil, fmt.Errorf("'Location' of sub-auth is required")
}
if p.ServiceToken == nil {
return nil, fmt.Errorf("'ServiceToken' of sub-auth is required")
}
if p.Key == nil {
return nil, fmt.Errorf("'Key' of sub-auth is required")
}
tokenAuth := &model.AuthOfAPIToken{
ServiceToken: *p.ServiceToken,
Location: model.HTTPParamLocation(strings.ToLower(string(*p.Location))),
Key: *p.Key,
}
str, err := sonic.MarshalString(tokenAuth)
if err != nil {
return nil, fmt.Errorf("marshal token auth failed, err=%v", err)
}
return &model.AuthV2{
Type: model.AuthzTypeOfService,
SubType: model.AuthzSubTypeOfServiceAPIToken,
Payload: str,
AuthOfAPIToken: tokenAuth,
}, nil
}
return nil, errorx.New(errno.ErrPluginInvalidManifest, errorx.KVf(errno.PluginMsgKey,
"the type '%s' of sub-auth is invalid", *p.AuthzSubType))
}
type PublishPluginRequest = model.PublishPluginRequest
type PublishAPPPluginsRequest = model.PublishAPPPluginsRequest
type PublishAPPPluginsResponse = model.PublishAPPPluginsResponse
type MGetPluginLatestVersionResponse = model.MGetPluginLatestVersionResponse
type UpdateToolDraftRequest struct {
PluginID int64
ToolID int64
Name *string
Desc *string
SubURL *string
Method *string
Parameters openapi3.Parameters
RequestBody *openapi3.RequestBodyRef
Responses openapi3.Responses
Disabled *bool
SaveExample *bool
DebugExample *common.DebugExample
APIExtend *common.APIExtend
}
type MGetAgentToolsRequest = model.MGetAgentToolsRequest
type UpdateBotDefaultParamsRequest struct {
PluginID int64
AgentID int64
ToolName string
Parameters openapi3.Parameters
RequestBody *openapi3.RequestBodyRef
Responses openapi3.Responses
}
type ExecuteToolRequest = model.ExecuteToolRequest
type ExecuteToolResponse = model.ExecuteToolResponse
type ListPluginProductsRequest struct{}
type ListPluginProductsResponse struct {
Plugins []*entity.PluginInfo
Total int64
}
type ConvertToOpenapi3DocRequest struct {
RawInput string
PluginServerURL *string
}
type ConvertToOpenapi3DocResponse struct {
OpenapiDoc *model.Openapi3T
Manifest *entity.PluginManifest
Format common.PluginDataFormat
ErrMsg string
}
type GetOAuthStatusResponse struct {
IsOauth bool
Status common.OAuthStatus
OAuthURL string
}
type AgentPluginOAuthStatus struct {
PluginID int64
PluginName string
PluginIconURL string
Status common.OAuthStatus
}
type CopyPluginRequest struct {
UserID int64
PluginID int64
CopyScene model.CopyScene
TargetAPPID *int64
}
type CopyPluginResponse struct {
Plugin *entity.PluginInfo
Tools map[int64]*entity.ToolInfo // old tool id -> new tool
}
type MoveAPPPluginToLibRequest struct {
PluginID int64
}
type GetAccessTokenRequest struct {
UserID string
PluginID *int64
Mode model.AuthzSubType
OAuthInfo *entity.OAuthInfo
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package service
import (
"context"
"github.com/go-resty/resty/v2"
"gorm.io/gorm"
"github.com/coze-dev/coze-studio/backend/domain/plugin/repository"
"github.com/coze-dev/coze-studio/backend/infra/contract/idgen"
"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
"github.com/coze-dev/coze-studio/backend/pkg/safego"
)
type Components struct {
IDGen idgen.IDGenerator
DB *gorm.DB
OSS storage.Storage
PluginRepo repository.PluginRepository
ToolRepo repository.ToolRepository
OAuthRepo repository.OAuthRepository
}
func NewService(components *Components) PluginService {
impl := &pluginServiceImpl{
db: components.DB,
oss: components.OSS,
pluginRepo: components.PluginRepo,
toolRepo: components.ToolRepo,
oauthRepo: components.OAuthRepo,
httpCli: resty.New(),
}
initOnce.Do(func() {
ctx := context.Background()
safego.Go(ctx, func() {
impl.processOAuthAccessToken(ctx)
})
})
return impl
}
type pluginServiceImpl struct {
db *gorm.DB
oss storage.Storage
pluginRepo repository.PluginRepository
toolRepo repository.ToolRepository
oauthRepo repository.OAuthRepository
httpCli *resty.Client
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utils
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
)
const (
AuthSecretKey = "^*6x3hdu2nc%-p38"
StateSecretKey = "osj^kfhsd*(z!sno"
OAuthTokenSecretKey = "cn+$PJ(HhJ[5d*z9"
)
func EncryptByAES(val []byte, secretKey string) (string, error) {
sb := []byte(secretKey)
block, err := aes.NewCipher(sb)
if err != nil {
return "", err
}
blockSize := block.BlockSize()
paddingData := pkcs7Padding(val, blockSize)
encrypted := make([]byte, len(paddingData))
blockMode := cipher.NewCBCEncrypter(block, sb[:blockSize])
blockMode.CryptBlocks(encrypted, paddingData)
return base64.RawURLEncoding.EncodeToString(encrypted), nil
}
func pkcs7Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
func DecryptByAES(data, secretKey string) ([]byte, error) {
dataBytes, err := base64.RawURLEncoding.DecodeString(data)
if err != nil {
return nil, err
}
sb := []byte(secretKey)
block, err := aes.NewCipher(sb)
if err != nil {
return nil, err
}
blockSize := block.BlockSize()
blockMode := cipher.NewCBCDecrypter(block, sb[:blockSize])
if len(dataBytes)%blockMode.BlockSize() != 0 {
return nil, fmt.Errorf("invalid block size")
}
decrypted := make([]byte, len(dataBytes))
blockMode.CryptBlocks(decrypted, dataBytes)
decrypted, err = pkcs7UnPadding(decrypted)
if err != nil {
return nil, err
}
return decrypted, nil
}
func pkcs7UnPadding(decrypted []byte) ([]byte, error) {
length := len(decrypted)
if length == 0 {
return nil, fmt.Errorf("decrypted is empty")
}
unPadding := int(decrypted[length-1])
if unPadding > length {
return nil, fmt.Errorf("invalid padding")
}
return decrypted[:(length - unPadding)], nil
}