This is an automated email from the ASF dual-hosted git repository.
lynwee pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
The following commit(s) were added to refs/heads/main by this push:
new df1a1b928 Complete #5643 Not returning the tokens or passwords on APIs
(#6494)
df1a1b928 is described below
commit df1a1b9288f8fb29c6733aad220dd94cdb332f3d
Author: Lynwee <[email protected]>
AuthorDate: Thu Nov 23 19:53:00 2023 +0800
Complete #5643 Not returning the tokens or passwords on APIs (#6494)
* fix(typo): rename
* feat(helper): remove sensitive token from GitHub/GitLab plugins
* feat(plugin): remove sensitive token from other plugins(except
AzureDevops)
* feat(plugin): add new test connection api
* fix(helper): remove sensitive info
* fix(framework): rename some functions
* refactor(helper): rename some methods
* refactor(helper): rename some parameters
---
backend/core/models/locking.go | 2 +-
backend/helpers/pluginhelper/api/api_extractor.go | 2 +-
.../pluginhelper/api/ds_connection_api_helper.go | 9 +-
backend/helpers/pluginhelper/api/ds_helper.go | 9 +-
.../pluginhelper/api/ds_scope_api_helper.go | 8 +-
.../pluginhelper/api/ds_scope_config_api_helper.go | 9 +-
.../helpers/pluginhelper/api/model_api_helper.go | 35 ++++-
backend/plugins/ae/api/connection.go | 74 +++++++---
backend/plugins/ae/impl/impl.go | 3 +
backend/plugins/ae/models/connection.go | 5 +
backend/plugins/bamboo/api/connection.go | 73 +++++++---
backend/plugins/bamboo/impl/impl.go | 3 +
backend/plugins/bamboo/models/connection.go | 10 ++
.../plugins/bamboo/tasks/plan_build_extractor.go | 2 +-
backend/plugins/bitbucket/api/connection.go | 89 +++++++++---
backend/plugins/bitbucket/impl/impl.go | 3 +
backend/plugins/bitbucket/models/connection.go | 10 ++
backend/plugins/circleci/api/connection.go | 83 ++++++++---
backend/plugins/circleci/impl/impl.go | 3 +
backend/plugins/circleci/models/connection.go | 5 +
backend/plugins/feishu/api/connection.go | 70 +++++++--
backend/plugins/feishu/impl/impl.go | 3 +
backend/plugins/feishu/models/connection.go | 10 ++
backend/plugins/gitee/api/connection.go | 89 +++++++++---
backend/plugins/gitee/impl/impl.go | 3 +
backend/plugins/gitee/models/connection.go | 10 ++
backend/plugins/github/api/connection_api.go | 158 ++++++++++++---------
backend/plugins/github/api/init.go | 8 +-
backend/plugins/github/impl/impl.go | 3 +
backend/plugins/github/models/connection.go | 9 +-
backend/plugins/gitlab/api/connection_api.go | 69 ++++++---
backend/plugins/gitlab/api/init.go | 5 +
backend/plugins/gitlab/impl/impl.go | 3 +
backend/plugins/gitlab/models/connection.go | 10 ++
backend/plugins/jenkins/api/connection.go | 91 +++++++++---
backend/plugins/jenkins/impl/impl.go | 3 +
backend/plugins/jenkins/models/connection.go | 10 ++
backend/plugins/jira/api/connection.go | 96 +++++++++----
backend/plugins/jira/impl/impl.go | 3 +
backend/plugins/jira/models/connection.go | 11 ++
backend/plugins/pagerduty/api/connection.go | 73 +++++++---
backend/plugins/pagerduty/impl/impl.go | 3 +
backend/plugins/pagerduty/models/connection.go | 5 +
backend/plugins/slack/api/connection.go | 69 +++++++--
backend/plugins/slack/impl/impl.go | 3 +
backend/plugins/slack/models/connection.go | 10 ++
backend/plugins/sonarqube/api/connection.go | 87 ++++++++----
backend/plugins/sonarqube/impl/impl.go | 3 +
backend/plugins/sonarqube/models/connection.go | 10 ++
backend/plugins/tapd/api/connection.go | 86 ++++++++---
backend/plugins/tapd/impl/impl.go | 3 +
backend/plugins/tapd/models/connection.go | 10 ++
backend/plugins/teambition/api/connection.go | 85 ++++++++---
backend/plugins/teambition/impl/impl.go | 3 +
backend/plugins/teambition/models/connection.go | 10 ++
backend/plugins/trello/api/connection.go | 87 +++++++++---
backend/plugins/trello/impl/impl.go | 3 +
backend/plugins/trello/models/connection.go | 10 ++
backend/plugins/zentao/api/connection.go | 92 +++++++++---
backend/plugins/zentao/impl/impl.go | 3 +
backend/plugins/zentao/models/connection.go | 33 +++++
61 files changed, 1394 insertions(+), 395 deletions(-)
diff --git a/backend/core/models/locking.go b/backend/core/models/locking.go
index 3bf02fc20..9510e24f3 100644
--- a/backend/core/models/locking.go
+++ b/backend/core/models/locking.go
@@ -43,7 +43,7 @@ func (LockingHistory) TableName() string {
// LockingStub does nothing but offer a locking target
type LockingStub struct {
- Stub string `gorm:"primaryKey"`
+ Stub string `gorm:"primaryKey;type:varchar(255)"`
}
func (LockingStub) TableName() string {
diff --git a/backend/helpers/pluginhelper/api/api_extractor.go
b/backend/helpers/pluginhelper/api/api_extractor.go
index 189b5618c..a2cd8a1eb 100644
--- a/backend/helpers/pluginhelper/api/api_extractor.go
+++ b/backend/helpers/pluginhelper/api/api_extractor.go
@@ -98,7 +98,7 @@ func (extractor *ApiExtractor) Execute() errors.Error {
// batch save divider
divider := NewBatchSaveDivider(extractor.args.Ctx,
extractor.args.BatchSize, extractor.table, extractor.params)
- // prgress
+ // progress
extractor.args.Ctx.SetProgress(0, -1)
ctx := extractor.args.Ctx.GetContext()
// iterate all rows
diff --git a/backend/helpers/pluginhelper/api/ds_connection_api_helper.go
b/backend/helpers/pluginhelper/api/ds_connection_api_helper.go
index 8d7bf5a55..3525ae2de 100644
--- a/backend/helpers/pluginhelper/api/ds_connection_api_helper.go
+++ b/backend/helpers/pluginhelper/api/ds_connection_api_helper.go
@@ -33,12 +33,16 @@ type DsConnectionApiHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScope
*srvhelper.ConnectionSrvHelper[C, S, SC]
}
-func NewDsConnectionApiHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScope, SC plugin.ToolLayerScopeConfig](
+func NewDsConnectionApiHelper[
+ C plugin.ToolLayerConnection,
+ S plugin.ToolLayerScope,
+ SC plugin.ToolLayerScopeConfig](
basicRes context.BasicRes,
connSrvHelper *srvhelper.ConnectionSrvHelper[C, S, SC],
+ sterilizer func(c C) C,
) *DsConnectionApiHelper[C, S, SC] {
return &DsConnectionApiHelper[C, S, SC]{
- ModelApiHelper: NewModelApiHelper[C](basicRes,
connSrvHelper.ModelSrvHelper, []string{"connectionId"}),
+ ModelApiHelper: NewModelApiHelper[C](basicRes,
connSrvHelper.ModelSrvHelper, []string{"connectionId"}, sterilizer),
ConnectionSrvHelper: connSrvHelper,
}
}
@@ -57,6 +61,7 @@ func (connApi *DsConnectionApiHelper[C, S, SC]) Delete(input
*plugin.ApiResource
Data: refs,
}, Status: err.GetType().GetHttpCode()}, nil
}
+ conn = connApi.Sanitize(conn)
return &plugin.ApiResourceOutput{
Body: conn,
}, nil
diff --git a/backend/helpers/pluginhelper/api/ds_helper.go
b/backend/helpers/pluginhelper/api/ds_helper.go
index 303789fdd..e4e823a86 100644
--- a/backend/helpers/pluginhelper/api/ds_helper.go
+++ b/backend/helpers/pluginhelper/api/ds_helper.go
@@ -44,13 +44,16 @@ func NewDataSourceHelper[
basicRes context.BasicRes,
pluginName string,
scopeSearchColumns []string,
+ connectionSterilizer func(c C) C,
+ scopeSterilizer func(s S) S,
+ scopeConfigSterilizer func(s SC) SC,
) *DsHelper[C, S, SC] {
connSrv := srvhelper.NewConnectionSrvHelper[C, S, SC](basicRes,
pluginName)
- connApi := NewDsConnectionApiHelper[C, S, SC](basicRes, connSrv)
+ connApi := NewDsConnectionApiHelper[C, S, SC](basicRes, connSrv,
connectionSterilizer)
scopeSrv := srvhelper.NewScopeSrvHelper[C, S, SC](basicRes, pluginName,
scopeSearchColumns)
- scopeApi := NewDsScopeApiHelper[C, S, SC](basicRes, scopeSrv)
+ scopeApi := NewDsScopeApiHelper[C, S, SC](basicRes, scopeSrv,
scopeSterilizer)
scSrv := srvhelper.NewScopeConfigSrvHelper[C, S, SC](basicRes,
scopeSearchColumns)
- scApi := NewDsScopeConfigApiHelper[C, S, SC](basicRes, scSrv)
+ scApi := NewDsScopeConfigApiHelper[C, S, SC](basicRes, scSrv,
scopeConfigSterilizer)
return &DsHelper[C, S, SC]{
ConnSrv: connSrv,
ConnApi: connApi,
diff --git a/backend/helpers/pluginhelper/api/ds_scope_api_helper.go
b/backend/helpers/pluginhelper/api/ds_scope_api_helper.go
index 279d9b1ae..cdf220694 100644
--- a/backend/helpers/pluginhelper/api/ds_scope_api_helper.go
+++ b/backend/helpers/pluginhelper/api/ds_scope_api_helper.go
@@ -36,12 +36,16 @@ type DsScopeApiHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScope, SC
*srvhelper.ScopeSrvHelper[C, S, SC]
}
-func NewDsScopeApiHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScope, SC plugin.ToolLayerScopeConfig](
+func NewDsScopeApiHelper[
+ C plugin.ToolLayerConnection,
+ S plugin.ToolLayerScope,
+ SC plugin.ToolLayerScopeConfig](
basicRes context.BasicRes,
srvHelper *srvhelper.ScopeSrvHelper[C, S, SC],
+ sterilizer func(s S) S,
) *DsScopeApiHelper[C, S, SC] {
return &DsScopeApiHelper[C, S, SC]{
- ModelApiHelper: NewModelApiHelper[S](basicRes,
srvHelper.ModelSrvHelper, []string{"connectionId", "scopeId"}),
+ ModelApiHelper: NewModelApiHelper[S](basicRes,
srvHelper.ModelSrvHelper, []string{"connectionId", "scopeId"}, sterilizer),
ScopeSrvHelper: srvHelper,
}
}
diff --git a/backend/helpers/pluginhelper/api/ds_scope_config_api_helper.go
b/backend/helpers/pluginhelper/api/ds_scope_config_api_helper.go
index 6a3e7cd19..8bfc52306 100644
--- a/backend/helpers/pluginhelper/api/ds_scope_config_api_helper.go
+++ b/backend/helpers/pluginhelper/api/ds_scope_config_api_helper.go
@@ -31,12 +31,17 @@ type DsScopeConfigApiHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScop
*srvhelper.ScopeConfigSrvHelper[C, S, SC]
}
-func NewDsScopeConfigApiHelper[C plugin.ToolLayerConnection, S
plugin.ToolLayerScope, SC plugin.ToolLayerScopeConfig](
+func NewDsScopeConfigApiHelper[
+ C plugin.ToolLayerConnection,
+ S plugin.ToolLayerScope,
+ SC plugin.ToolLayerScopeConfig,
+](
basicRes context.BasicRes,
dalHelper *srvhelper.ScopeConfigSrvHelper[C, S, SC],
+ sterilizer func(sc SC) SC,
) *DsScopeConfigApiHelper[C, S, SC] {
return &DsScopeConfigApiHelper[C, S, SC]{
- ModelApiHelper: NewModelApiHelper[SC](basicRes,
dalHelper.ModelSrvHelper, []string{"scopeConfigId"}),
+ ModelApiHelper: NewModelApiHelper[SC](basicRes,
dalHelper.ModelSrvHelper, []string{"scopeConfigId"}, sterilizer),
ScopeConfigSrvHelper: dalHelper,
}
}
diff --git a/backend/helpers/pluginhelper/api/model_api_helper.go
b/backend/helpers/pluginhelper/api/model_api_helper.go
index ce4d18be5..af4905eb6 100644
--- a/backend/helpers/pluginhelper/api/model_api_helper.go
+++ b/backend/helpers/pluginhelper/api/model_api_helper.go
@@ -39,22 +39,28 @@ type ModelApiHelper[M dal.Tabler] struct {
log log.Logger
modelName string
pkPathVarNames []string
+ sterilizers []func(m M) M
}
func NewModelApiHelper[M dal.Tabler](
basicRes context.BasicRes,
dalHelper *srvhelper.ModelSrvHelper[M],
pkPathVarNames []string, // path variable names of primary key
+ sterilizer func(m M) M,
) *ModelApiHelper[M] {
m := new(M)
modelName := fmt.Sprintf("%T", m)
- return &ModelApiHelper[M]{
+ modelApiHelper := &ModelApiHelper[M]{
basicRes: basicRes,
dalHelper: dalHelper,
log:
basicRes.GetLogger().Nested(fmt.Sprintf("%s_dal", modelName)),
modelName: modelName,
pkPathVarNames: pkPathVarNames,
}
+ if sterilizer != nil {
+ modelApiHelper.sterilizers = []func(m M) M{sterilizer}
+ }
+ return modelApiHelper
}
func (self *ModelApiHelper[M]) Post(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
@@ -98,11 +104,30 @@ func (self *ModelApiHelper[M]) GetDetail(input
*plugin.ApiResourceInput) (*plugi
if err != nil {
return nil, err
}
+ model = self.Sanitize(model)
return &plugin.ApiResourceOutput{
Body: model,
}, nil
}
+func (self *ModelApiHelper[M]) Sanitize(model *M) *M {
+ if self.sterilizers != nil {
+ for _, sterilizer := range self.sterilizers {
+ sanitizedModel := sterilizer(*model)
+ model = &sanitizedModel
+ }
+ }
+ return model
+}
+
+func (self *ModelApiHelper[M]) BatchSanitize(models []*M) []*M {
+ for idx, m := range models {
+ model := *m
+ models[idx] = self.Sanitize(&model)
+ }
+ return models
+}
+
func (self *ModelApiHelper[M]) Patch(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
model, err := self.FindByPk(input)
if err != nil {
@@ -116,6 +141,7 @@ func (self *ModelApiHelper[M]) Patch(input
*plugin.ApiResourceInput) (*plugin.Ap
if err != nil {
return nil, err
}
+ model = self.Sanitize(model)
return &plugin.ApiResourceOutput{
Body: model,
}, nil
@@ -130,6 +156,7 @@ func (self *ModelApiHelper[M]) Delete(input
*plugin.ApiResourceInput) (*plugin.A
if err != nil {
return nil, err
}
+ model = self.Sanitize(model)
return &plugin.ApiResourceOutput{
Body: model,
}, nil
@@ -137,6 +164,7 @@ func (self *ModelApiHelper[M]) Delete(input
*plugin.ApiResourceInput) (*plugin.A
func (self *ModelApiHelper[M]) GetAll(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
all, err := self.dalHelper.GetAll()
+ all = self.BatchSanitize(all)
return &plugin.ApiResourceOutput{
Body: all,
}, err
@@ -144,18 +172,19 @@ func (self *ModelApiHelper[M]) GetAll(input
*plugin.ApiResourceInput) (*plugin.A
func (self *ModelApiHelper[M]) PutMultiple(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
var req struct {
- Data []M `json:"data"`
+ Data []*M `json:"data"`
}
err := utils.DecodeMapStruct(input.Body, &req, false)
if err != nil {
return nil, err
}
for i, item := range req.Data {
- err := self.dalHelper.CreateOrUpdate(&item)
+ err := self.dalHelper.CreateOrUpdate(item)
if err != nil {
return nil, errors.BadInput.Wrap(err,
fmt.Sprintf("failed to save item %d", i))
}
}
+ req.Data = self.BatchSanitize(req.Data)
return &plugin.ApiResourceOutput{
Body: req.Data,
}, nil
diff --git a/backend/plugins/ae/api/connection.go
b/backend/plugins/ae/api/connection.go
index 20287e0ed..f2d8b8bdd 100644
--- a/backend/plugins/ae/api/connection.go
+++ b/backend/plugins/ae/api/connection.go
@@ -32,6 +32,32 @@ type ApiMeResponse struct {
Name string `json:"name"`
}
+func testConnection(ctx context.Context, connection models.AeConn)
(*plugin.ApiResourceOutput, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
+ }
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
+ if err != nil {
+ return nil, err
+ }
+ res, err := apiClient.Get("projects", nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ switch res.StatusCode {
+ case 200: // right StatusCode
+ return &plugin.ApiResourceOutput{Body: true, Status: 200}, nil
+ case 401: // error secretKey or nonceStr
+ return &plugin.ApiResourceOutput{Body: false, Status:
http.StatusBadRequest}, nil
+ default: // unknow what happen , back to user
+ return &plugin.ApiResourceOutput{Body: res.Body, Status:
res.StatusCode}, nil
+ }
+}
+
+// TestConnection test ae connection
// @Summary test ae connection
// @Description Test AE Connection
// @Tags plugins/ae
@@ -47,23 +73,25 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err = api.Decode(input.Body, &connection, vld); err != nil {
return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
}
+ return testConnection(context.TODO(), connection)
+}
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
- if err != nil {
- return nil, err
- }
- res, err := apiClient.Get("projects", nil, nil)
+// TestExistingConnection test ae connection
+// @Summary test ae connection
+// @Description Test AE Connection
+// @Tags plugins/ae
+// @Success 200 {object} shared.ApiBody "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/ae/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ connection := &models.AeConnection{}
+ err := connectionHelper.First(connection, input.Params)
if err != nil {
- return nil, err
- }
- switch res.StatusCode {
- case 200: // right StatusCode
- return &plugin.ApiResourceOutput{Body: true, Status: 200}, nil
- case 401: // error secretKey or nonceStr
- return &plugin.ApiResourceOutput{Body: false, Status:
http.StatusBadRequest}, nil
- default: // unknow what happen , back to user
- return &plugin.ApiResourceOutput{Body: res.Body, Status:
res.StatusCode}, nil
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
}
+ return testConnection(context.TODO(), connection.AeConn)
}
// @Summary create ae connection
@@ -80,7 +108,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary get all ae connections
@@ -96,6 +124,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -109,7 +140,7 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.AeConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
// @Summary patch ae connection
@@ -126,7 +157,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary delete a ae connection
@@ -138,5 +169,12 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/ae/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.AeConnection{}, input)
+ conn := &models.AeConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
diff --git a/backend/plugins/ae/impl/impl.go b/backend/plugins/ae/impl/impl.go
index db56e84ed..907975e48 100644
--- a/backend/plugins/ae/impl/impl.go
+++ b/backend/plugins/ae/impl/impl.go
@@ -139,6 +139,9 @@ func (p AE) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
}
}
diff --git a/backend/plugins/ae/models/connection.go
b/backend/plugins/ae/models/connection.go
index 7196d4fee..d13767c7b 100644
--- a/backend/plugins/ae/models/connection.go
+++ b/backend/plugins/ae/models/connection.go
@@ -65,6 +65,11 @@ func (AeConnection) TableName() string {
return "_tool_ae_connections"
}
+func (connection AeConnection) Sanitize() AeConnection {
+ connection.AeAppKey.SecretKey = ""
+ return connection
+}
+
func signRequest(query url.Values, appId, secretKey, nonceStr, timestamp
string) string {
// clone query because we need to add items
kvs := make([]string, 0, len(query)+3)
diff --git a/backend/plugins/bamboo/api/connection.go
b/backend/plugins/bamboo/api/connection.go
index 91df4cefe..96a0d8923 100644
--- a/backend/plugins/bamboo/api/connection.go
+++ b/backend/plugins/bamboo/api/connection.go
@@ -33,6 +33,27 @@ type BambooTestConnResponse struct {
Connection *models.BambooConn
}
+func testConnection(ctx context.Context, connection models.BambooConn)
(*BambooTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
+ }
+ // test connection
+ _, err := api.NewApiClientFromConnection(ctx, basicRes, &connection)
+ connection = connection.Sanitize()
+ if err != nil {
+ return nil, err
+ }
+ body := BambooTestConnResponse{}
+ body.Success = true
+ body.Message = "success"
+ body.Connection = &connection
+ return &body, nil
+}
+
+// TestConnection test bamboo connection
// @Summary test bamboo connection
// @Description Test bamboo Connection
// @Tags plugins/bamboo
@@ -48,23 +69,34 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err = api.Decode(input.Body, &connection, vld); err != nil {
return nil, err
}
-
// test connection
- _, err = api.NewApiClientFromConnection(
- context.TODO(),
- basicRes,
- &connection,
- )
+ result, err := testConnection(context.TODO(), connection)
if err != nil {
return nil, err
}
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
- body := BambooTestConnResponse{}
- body.Success = true
- body.Message = "success"
- body.Connection = &connection
-
- return &plugin.ApiResourceOutput{Body: body, Status: http.StatusOK}, nil
+// TestExistingConnection test bamboo connection
+// @Summary test bamboo connection
+// @Description Test bamboo Connection
+// @Tags plugins/bamboo
+// @Success 200 {object} BambooTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/bamboo/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.BambooConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.BambooConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create bamboo connection
@@ -82,7 +114,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch bamboo connection
@@ -100,7 +132,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a bamboo connection
@@ -113,7 +145,13 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internel Error"
// @Router /plugins/bamboo/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.BambooConnection{}, input)
+ conn := &models.BambooConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
}
// @Summary get all bamboo connections
@@ -129,6 +167,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -143,5 +184,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.BambooConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/bamboo/impl/impl.go
b/backend/plugins/bamboo/impl/impl.go
index 05965c456..23543fb91 100644
--- a/backend/plugins/bamboo/impl/impl.go
+++ b/backend/plugins/bamboo/impl/impl.go
@@ -215,6 +215,9 @@ func (p Bamboo) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/scope-configs": {
"POST": api.CreateScopeConfig,
"GET": api.GetScopeConfigList,
diff --git a/backend/plugins/bamboo/models/connection.go
b/backend/plugins/bamboo/models/connection.go
index fa0fceae1..1feeb5cc1 100644
--- a/backend/plugins/bamboo/models/connection.go
+++ b/backend/plugins/bamboo/models/connection.go
@@ -36,6 +36,11 @@ type BambooConnection struct {
BambooConn `mapstructure:",squash"`
}
+func (connection BambooConnection) Sanitize() BambooConnection {
+ connection.BambooConn = connection.BambooConn.Sanitize()
+ return connection
+}
+
// TODO Please modify the following code to fit your needs
// This object conforms to what the frontend currently sends.
type BambooConn struct {
@@ -44,6 +49,11 @@ type BambooConn struct {
api.BasicAuth `mapstructure:",squash"`
}
+func (conn *BambooConn) Sanitize() BambooConn {
+ conn.Password = ""
+ return *conn
+}
+
// PrepareApiClient test api and set the IsPrivateToken,version,UserId and so
on.
func (conn *BambooConn) PrepareApiClient(apiClient
apihelperabstract.ApiClientAbstract) errors.Error {
header := http.Header{}
diff --git a/backend/plugins/bamboo/tasks/plan_build_extractor.go
b/backend/plugins/bamboo/tasks/plan_build_extractor.go
index c03d8a7b3..273e61764 100644
--- a/backend/plugins/bamboo/tasks/plan_build_extractor.go
+++ b/backend/plugins/bamboo/tasks/plan_build_extractor.go
@@ -50,7 +50,7 @@ func ExtractPlanBuild(taskCtx plugin.SubTaskContext)
errors.Error {
results := make([]interface{}, 0)
results = append(results, body)
// As job build can get more accuracy repo info,
- // we can collect BambooPlanBuildVcsRevision in
job_biuld_extractor
+ // we can collect BambooPlanBuildVcsRevision in
job_build_extractor
for _, v := range res.VcsRevisions.VcsRevision {
results = append(results,
&models.BambooPlanBuildVcsRevision{
ConnectionId:
data.Options.ConnectionId,
diff --git a/backend/plugins/bitbucket/api/connection.go
b/backend/plugins/bitbucket/api/connection.go
index 4d88ba7c2..a3e637458 100644
--- a/backend/plugins/bitbucket/api/connection.go
+++ b/backend/plugins/bitbucket/api/connection.go
@@ -34,23 +34,15 @@ type BitBucketTestConnResponse struct {
Connection *models.BitbucketConn
}
-// @Summary test bitbucket connection
-// @Description Test bitbucket Connection
-// @Tags plugins/bitbucket
-// @Param body body models.BitbucketConn true "json body"
-// @Success 200 {object} BitBucketTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/bitbucket/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- // decode
- var err errors.Error
- var connection models.BitbucketConn
- if err := api.Decode(input.Body, &connection, vld); err != nil {
- return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
+func testConnection(ctx context.Context, connection models.BitbucketConn)
(*BitBucketTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
// test connection
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -66,12 +58,59 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected
status code when testing connection")
}
+ connection = connection.Sanitize()
body := BitBucketTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
// output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test bitbucket connection
+// @Summary test bitbucket connection
+// @Description Test bitbucket Connection
+// @Tags plugins/bitbucket
+// @Param body body models.BitbucketConn true "json body"
+// @Success 200 {object} BitBucketTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/bitbucket/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ var err errors.Error
+ var connection models.BitbucketConn
+ if err := api.Decode(input.Body, &connection, vld); err != nil {
+ return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test bitbucket connection
+// @Summary test bitbucket connection
+// @Description Test bitbucket Connection
+// @Tags plugins/bitbucket
+// @Success 200 {object} BitBucketTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/bitbucket/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.BitbucketConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.BitbucketConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create bitbucket connection
@@ -89,7 +128,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch bitbucket connection
@@ -106,7 +145,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a bitbucket connection
@@ -118,7 +157,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/bitbucket/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.BitbucketConnection{}, input)
+ conn := &models.BitbucketConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// @Summary get all bitbucket connections
@@ -134,6 +180,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -147,5 +196,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.BitbucketConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/bitbucket/impl/impl.go
b/backend/plugins/bitbucket/impl/impl.go
index 8611b1287..f79d82167 100644
--- a/backend/plugins/bitbucket/impl/impl.go
+++ b/backend/plugins/bitbucket/impl/impl.go
@@ -207,6 +207,9 @@ func (p Bitbucket) ApiResources()
map[string]map[string]plugin.ApiResourceHandle
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/scopes/*scopeId": {
"GET": api.GetScope,
"PATCH": api.UpdateScope,
diff --git a/backend/plugins/bitbucket/models/connection.go
b/backend/plugins/bitbucket/models/connection.go
index 9db3befc5..3e187a39e 100644
--- a/backend/plugins/bitbucket/models/connection.go
+++ b/backend/plugins/bitbucket/models/connection.go
@@ -30,6 +30,11 @@ type BitbucketConn struct {
api.BasicAuth `mapstructure:",squash"`
}
+func (connection BitbucketConn) Sanitize() BitbucketConn {
+ connection.Password = ""
+ return connection
+}
+
// BitbucketConnection holds BitbucketConn plus ID/Name for database storage
type BitbucketConnection struct {
api.BaseConnection `mapstructure:",squash"`
@@ -39,3 +44,8 @@ type BitbucketConnection struct {
func (BitbucketConnection) TableName() string {
return "_tool_bitbucket_connections"
}
+
+func (connection BitbucketConnection) Sanitize() BitbucketConnection {
+ connection.BitbucketConn = connection.BitbucketConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/circleci/api/connection.go
b/backend/plugins/circleci/api/connection.go
index 1f851cccc..84f7f78d2 100644
--- a/backend/plugins/circleci/api/connection.go
+++ b/backend/plugins/circleci/api/connection.go
@@ -33,7 +33,37 @@ type CircleciTestConnResponse struct {
shared.ApiBody
}
-// TestConnection @Summary test circleci connection
+func testConnection(ctx context.Context, connection models.CircleciConn)
(*CircleciTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
+ }
+ // test connection
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
+ if err != nil {
+ return nil, err
+ }
+
+ res, err := apiClient.Get("/v2/me", nil, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if res.StatusCode != http.StatusOK {
+ return nil,
errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code: %d",
res.StatusCode))
+ }
+
+ body := CircleciTestConnResponse{}
+ body.Success = true
+ body.Message = "success"
+ // output
+ return &body, nil
+}
+
+// TestConnection test circleci connection
+// @Summary test circleci connection
// @Description Test circleci Connection
// @Tags plugins/circleci
// @Param body body models.CircleciConnection true "json body"
@@ -48,27 +78,34 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
-
// test connection
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ result, err := testConnection(context.TODO(), connection)
if err != nil {
return nil, err
}
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
- res, err := apiClient.Get("/v2/me", nil, nil)
+// TestExistingConnection test circleci connection
+// @Summary test circleci connection
+// @Description Test circleci Connection
+// @Tags plugins/circleci
+// @Success 200 {object} CircleciTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/circleci/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.CircleciConnection{}
+ err := connectionHelper.First(connection, input.Params)
if err != nil {
- return nil, err
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
}
-
- if res.StatusCode != http.StatusOK {
- return nil,
errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code: %d",
res.StatusCode))
+ // test connection
+ result, err := testConnection(context.TODO(), connection.CircleciConn)
+ if err != nil {
+ return nil, err
}
-
- body := CircleciTestConnResponse{}
- body.Success = true
- body.Message = "success"
- // output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// PostConnections @Summary create circleci connection
@@ -86,7 +123,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// PatchConnection @Summary patch circleci connection
@@ -103,7 +140,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// DeleteConnection @Summary delete a circleci connection
@@ -114,7 +151,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/circleci/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.CircleciConnection{}, input)
+ conn := &models.CircleciConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// ListConnections @Summary get all circleci connections
@@ -130,6 +174,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -143,5 +190,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.CircleciConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/circleci/impl/impl.go
b/backend/plugins/circleci/impl/impl.go
index 19e73ca36..1025ea4cd 100644
--- a/backend/plugins/circleci/impl/impl.go
+++ b/backend/plugins/circleci/impl/impl.go
@@ -180,6 +180,9 @@ func (p Circleci) ApiResources()
map[string]map[string]plugin.ApiResourceHandler
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/remote-scopes": {
"GET": api.RemoteScopes,
},
diff --git a/backend/plugins/circleci/models/connection.go
b/backend/plugins/circleci/models/connection.go
index b1ae0544a..60d661581 100644
--- a/backend/plugins/circleci/models/connection.go
+++ b/backend/plugins/circleci/models/connection.go
@@ -43,3 +43,8 @@ func (cc *CircleciConn) SetupAuthentication(req
*http.Request) errors.Error {
func (CircleciConnection) TableName() string {
return "_tool_circleci_connections"
}
+
+func (connection CircleciConnection) Sanitize() CircleciConnection {
+ connection.Token = ""
+ return connection
+}
diff --git a/backend/plugins/feishu/api/connection.go
b/backend/plugins/feishu/api/connection.go
index 141b14c5b..35cd1d9e8 100644
--- a/backend/plugins/feishu/api/connection.go
+++ b/backend/plugins/feishu/api/connection.go
@@ -34,6 +34,27 @@ type FeishuTestConnResponse struct {
Connection *models.FeishuConn
}
+func testConnection(ctx context.Context, connection models.FeishuConn)
(*FeishuTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
+ }
+ _, err := api.NewApiClientFromConnection(ctx, basicRes, &connection)
+ if err != nil {
+ return nil, err
+ }
+ connection = connection.Sanitize()
+ body := FeishuTestConnResponse{}
+ body.Success = true
+ body.Message = "success"
+ body.Connection = &connection
+
+ return &body, nil
+}
+
+// TestConnection test feishu connection
// @Summary test feishu connection
// @Description Test feishu Connection. endpoint:
https://open.feishu.cn/open-apis/
// @Tags plugins/feishu
@@ -48,18 +69,34 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err := api.Decode(input.Body, &connection, vld); err != nil {
return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
}
-
// test connection
- _, err := api.NewApiClientFromConnection(context.TODO(), basicRes,
&connection)
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
- body := FeishuTestConnResponse{}
- body.Success = true
- body.Message = "success"
- body.Connection = &connection
+// TestExistingConnection test feishu connection
+// @Summary test feishu connection
+// @Description Test feishu Connection. endpoint:
https://open.feishu.cn/open-apis/
+// @Tags plugins/feishu
+// @Success 200 {object} FeishuTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/feishu/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.FeishuConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.FeishuConn)
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create feishu connection
@@ -76,7 +113,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch feishu connection
@@ -93,7 +130,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary delete a feishu connection
@@ -105,7 +142,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/feishu/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.FeishuConnection{}, input)
+ conn := &models.FeishuConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// @Summary get all feishu connections
@@ -121,7 +165,9 @@ func ListConnections(_ *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, err
if err != nil {
return nil, err
}
-
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections}, nil
}
@@ -138,5 +184,5 @@ func GetConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, e
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/feishu/impl/impl.go
b/backend/plugins/feishu/impl/impl.go
index 8429fc883..eb321a12b 100644
--- a/backend/plugins/feishu/impl/impl.go
+++ b/backend/plugins/feishu/impl/impl.go
@@ -141,6 +141,9 @@ func (p Feishu) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
}
}
diff --git a/backend/plugins/feishu/models/connection.go
b/backend/plugins/feishu/models/connection.go
index 2ad8988bc..9e0b26644 100644
--- a/backend/plugins/feishu/models/connection.go
+++ b/backend/plugins/feishu/models/connection.go
@@ -33,6 +33,11 @@ type FeishuConn struct {
helper.AppKey `mapstructure:",squash"`
}
+func (conn *FeishuConn) Sanitize() FeishuConn {
+ conn.SecretKey = ""
+ return *conn
+}
+
func (conn *FeishuConn) PrepareApiClient(apiClient
apihelperabstract.ApiClientAbstract) errors.Error {
// request for access token
tokenReqBody := &apimodels.ApiAccessTokenRequest{
@@ -71,3 +76,8 @@ type FeishuConnection struct {
func (FeishuConnection) TableName() string {
return "_tool_feishu_connections"
}
+
+func (connection FeishuConnection) Sanitize() FeishuConnection {
+ connection.FeishuConn = connection.FeishuConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/gitee/api/connection.go
b/backend/plugins/gitee/api/connection.go
index db926bce8..f946df928 100644
--- a/backend/plugins/gitee/api/connection.go
+++ b/backend/plugins/gitee/api/connection.go
@@ -34,22 +34,14 @@ type GiteeTestConnResponse struct {
Connection *models.GiteeConn
}
-// @Summary test gitee connection
-// @Description Test gitee Connection. endpoint: https://gitee.com/api/v5/
-// @Tags plugins/gitee
-// @Param body body models.GiteeConn true "json body"
-// @Success 200 {object} GiteeTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/gitee/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- var err errors.Error
- var connection models.GiteeConn
- if err = helper.Decode(input.Body, &connection, vld); err != nil {
- return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
+func testConnection(ctx context.Context, connection models.GiteeConn)
(*GiteeTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
-
- apiClient, err := helper.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := helper.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -70,12 +62,58 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected
status code when testing connection")
}
+ connection = connection.Sanitize()
body := GiteeTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
// output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test gitee connection
+// @Summary test gitee connection
+// @Description Test gitee Connection. endpoint: https://gitee.com/api/v5/
+// @Tags plugins/gitee
+// @Param body body models.GiteeConn true "json body"
+// @Success 200 {object} GiteeTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/gitee/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ var err errors.Error
+ var connection models.GiteeConn
+ if err = helper.Decode(input.Body, &connection, vld); err != nil {
+ return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test gitee connection
+// @Summary test gitee connection
+// @Description Test gitee Connection. endpoint: https://gitee.com/api/v5/
+// @Tags plugins/gitee
+// @Success 200 {object} GiteeTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/gitee/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.GiteeConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.GiteeConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create gitee connection
@@ -92,7 +130,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch gitee connection
@@ -109,7 +147,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary delete a gitee connection
@@ -121,7 +159,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/gitee/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.GiteeConnection{}, input)
+ conn := &models.GiteeConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// @Summary get all gitee connections
@@ -137,7 +182,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
-
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections}, nil
}
@@ -151,5 +198,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.GiteeConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/gitee/impl/impl.go
b/backend/plugins/gitee/impl/impl.go
index 7ccf03a4f..b31ec5bb7 100644
--- a/backend/plugins/gitee/impl/impl.go
+++ b/backend/plugins/gitee/impl/impl.go
@@ -196,6 +196,9 @@ func (p Gitee) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
}
}
diff --git a/backend/plugins/gitee/models/connection.go
b/backend/plugins/gitee/models/connection.go
index fc94a7487..996009113 100644
--- a/backend/plugins/gitee/models/connection.go
+++ b/backend/plugins/gitee/models/connection.go
@@ -40,6 +40,11 @@ type GiteeConn struct {
GiteeAccessToken `mapstructure:",squash"`
}
+func (connection GiteeConn) Sanitize() GiteeConn {
+ connection.Token = ""
+ return connection
+}
+
// GiteeConnection holds GiteeConn plus ID/Name for database storage
type GiteeConnection struct {
helper.BaseConnection `mapstructure:",squash"`
@@ -67,3 +72,8 @@ type GiteeScopeConfig struct {
func (GiteeConnection) TableName() string {
return "_tool_gitee_connections"
}
+
+func (connection GiteeConnection) Sanitize() GiteeConnection {
+ connection.GiteeConn = connection.GiteeConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/github/api/connection_api.go
b/backend/plugins/github/api/connection_api.go
index b2531a17d..f5af1b32c 100644
--- a/backend/plugins/github/api/connection_api.go
+++ b/backend/plugins/github/api/connection_api.go
@@ -60,6 +60,7 @@ type GithubTestConnResponse struct {
Installations []models.GithubAppInstallation `json:"installations"`
}
+// TestConnection test github connection
// @Summary test github connection
// @Description Test github Connection
// @Tags plugins/github
@@ -75,35 +76,96 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if e != nil {
return nil, errors.Convert(e)
}
- e = vld.StructExcept(conn, "GithubAppKey", "GithubAccessToken")
- if e != nil {
- return nil, errors.Convert(e)
+ testConnectionResult, err := testConnection(context.TODO(), conn)
+ if err != nil {
+ return nil, errors.Convert(err)
}
+ return &plugin.ApiResourceOutput{Body: testConnectionResult, Status:
http.StatusOK}, nil
+}
+
+// @Summary create github connection
+// @Description Create github connection
+// @Tags plugins/github
+// @Param body body models.GithubConnection true "json body"
+// @Success 200 {object} models.GithubConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/github/connections [POST]
+func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ return dsHelper.ConnApi.Post(input)
+}
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &conn)
+// @Summary patch github connection
+// @Description Patch github connection
+// @Tags plugins/github
+// @Param body body models.GithubConnection true "json body"
+// @Success 200 {object} models.GithubConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/github/connections/{connectionId} [PATCH]
+func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ return dsHelper.ConnApi.Patch(input)
+}
+
+// @Summary delete a github connection
+// @Description Delete a github connection
+// @Tags plugins/github
+// @Success 200 {object} models.GithubConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/github/connections/{connectionId} [DELETE]
+func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ return dsHelper.ConnApi.Delete(input)
+}
+
+// @Summary get all github connections
+// @Description Get all github connections
+// @Tags plugins/github
+// @Success 200 {object} []models.GithubConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/github/connections [GET]
+func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ return dsHelper.ConnApi.GetAll(input)
+}
+
+// @Summary get github connection detail
+// @Description Get github connection detail
+// @Tags plugins/github
+// @Success 200 {object} models.GithubConnection
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/github/connections/{connectionId} [GET]
+func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
+ return dsHelper.ConnApi.GetDetail(input)
+}
+
+func testConnection(ctx context.Context, conn models.GithubConn)
(*GithubTestConnResponse, errors.Error) {
+ if vld != nil {
+ if err := vld.StructExcept(conn, "GithubAppKey",
"GithubAccessToken"); err != nil {
+ return nil, errors.Convert(err)
+ }
+ }
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes, &conn)
if err != nil {
return nil, err
}
-
githubApiResponse := &GithubTestConnResponse{}
-
if conn.AuthMethod == "AppKey" {
jwt, err := conn.GithubAppKey.CreateJwt()
if err != nil {
return nil, err
}
-
res, err := apiClient.Get("app", nil, http.Header{
"Authorization": []string{fmt.Sprintf("Bearer %s",
jwt)},
})
-
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token
failed")
}
if res.StatusCode != http.StatusOK {
return nil,
errors.HttpStatus(res.StatusCode).New("unexpected status code while testing
connection")
}
-
githubApp := &models.GithubApp{}
err = api.UnmarshalResponse(res, githubApp)
if err != nil {
@@ -111,24 +173,20 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
} else if githubApp.Slug == "" {
return nil, errors.BadInput.Wrap(err, "invalid token")
}
-
res, err = apiClient.Get("app/installations", nil, http.Header{
"Authorization": []string{fmt.Sprintf("Bearer %s",
jwt)},
})
-
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token
failed")
}
if res.StatusCode != http.StatusOK {
return nil,
errors.HttpStatus(res.StatusCode).New("unexpected status code while testing
connection")
}
-
githubAppInstallations := &[]models.GithubAppInstallation{}
err = api.UnmarshalResponse(res, githubAppInstallations)
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token
failed")
}
-
githubApiResponse.Success = true
githubApiResponse.Message = "success"
githubApiResponse.Login = githubApp.Slug
@@ -139,15 +197,12 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token
failed")
}
-
if res.StatusCode == http.StatusUnauthorized {
return nil,
errors.HttpStatus(http.StatusBadRequest).New("StatusUnauthorized error when
testing connection")
}
-
if res.StatusCode != http.StatusOK {
return nil,
errors.HttpStatus(res.StatusCode).New("unexpected status code while testing
connection")
}
-
githubUserOfToken := &models.GithubUserOfToken{}
err = api.UnmarshalResponse(res, githubUserOfToken)
if err != nil {
@@ -155,7 +210,6 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
} else if githubUserOfToken.Login == "" {
return nil, errors.BadInput.Wrap(err, "invalid token")
}
-
success := false
warning := false
messages := []string{}
@@ -200,63 +254,25 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil, errors.BadInput.New("invalid authentication method")
}
- return &plugin.ApiResourceOutput{Body: githubApiResponse, Status:
http.StatusOK}, nil
-}
-
-// @Summary create github connection
-// @Description Create github connection
-// @Tags plugins/github
-// @Param body body models.GithubConnection true "json body"
-// @Success 200 {object} models.GithubConnection
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/github/connections [POST]
-func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return dsHelper.ConnApi.Post(input)
-}
-
-// @Summary patch github connection
-// @Description Patch github connection
-// @Tags plugins/github
-// @Param body body models.GithubConnection true "json body"
-// @Success 200 {object} models.GithubConnection
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/github/connections/{connectionId} [PATCH]
-func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return dsHelper.ConnApi.Patch(input)
-}
-
-// @Summary delete a github connection
-// @Description Delete a github connection
-// @Tags plugins/github
-// @Success 200 {object} models.GithubConnection
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 409 {object} services.BlueprintProjectPairs "References exist to
this connection"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/github/connections/{connectionId} [DELETE]
-func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return dsHelper.ConnApi.Delete(input)
-}
-
-// @Summary get all github connections
-// @Description Get all github connections
-// @Tags plugins/github
-// @Success 200 {object} []models.GithubConnection
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/github/connections [GET]
-func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return dsHelper.ConnApi.GetAll(input)
+ return githubApiResponse, nil
}
-// @Summary get github connection detail
-// @Description Get github connection detail
+// TestExistingConnection test github connection options
+// @Summary test github connection
+// @Description Test github Connection
// @Tags plugins/github
-// @Success 200 {object} models.GithubConnection
+// @Success 200 {object} GithubTestConnResponse
// @Failure 400 {string} errcode.Error "Bad Request"
// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/github/connections/{connectionId} [GET]
-func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
- return dsHelper.ConnApi.GetDetail(input)
+// @Router /plugins/github/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection, err := dsHelper.ConnApi.FindByPk(input)
+ if err != nil {
+ return nil, err
+ }
+ testConnectionResult, testConnectionErr :=
testConnection(context.TODO(), connection.GithubConn)
+ if testConnectionErr != nil {
+ return nil, testConnectionErr
+ }
+ return &plugin.ApiResourceOutput{Body: testConnectionResult, Status:
http.StatusOK}, nil
}
diff --git a/backend/plugins/github/api/init.go
b/backend/plugins/github/api/init.go
index 6f6df7dfa..74d3d5293 100644
--- a/backend/plugins/github/api/init.go
+++ b/backend/plugins/github/api/init.go
@@ -37,11 +37,17 @@ func Init(br context.BasicRes, p plugin.PluginMeta) {
basicRes = br
dsHelper = api.NewDataSourceHelper[
models.GithubConnection,
- models.GithubRepo, models.GithubScopeConfig,
+ models.GithubRepo,
+ models.GithubScopeConfig,
](
br,
p.Name(),
[]string{"full_name"},
+ func(c models.GithubConnection) models.GithubConnection {
+ return c.Sanitize()
+ },
+ nil,
+ nil,
)
// TODO: refactor remoteHelper
vld = validator.New()
diff --git a/backend/plugins/github/impl/impl.go
b/backend/plugins/github/impl/impl.go
index 51ed55dcd..90929564e 100644
--- a/backend/plugins/github/impl/impl.go
+++ b/backend/plugins/github/impl/impl.go
@@ -187,6 +187,9 @@ func (p Github) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/scopes/:scopeId": {
"GET": api.GetScope,
"PATCH": api.PatchScope,
diff --git a/backend/plugins/github/models/connection.go
b/backend/plugins/github/models/connection.go
index b1ac0252b..4b06a8788 100644
--- a/backend/plugins/github/models/connection.go
+++ b/backend/plugins/github/models/connection.go
@@ -43,7 +43,7 @@ type GithubAppKey struct {
InstallationID int `mapstructure:"installationId" validate:"required"
json:"installationId"`
}
-// GithubConn holds the essential information to connect to the Github API
+// GithubConn holds the essential information to connect to the GitHub API
type GithubConn struct {
helper.RestConnection `mapstructure:",squash"`
helper.MultiAuth `mapstructure:",squash"`
@@ -94,10 +94,15 @@ type GithubConnection struct {
EnableGraphql bool `mapstructure:"enableGraphql"
json:"enableGraphql"`
}
-func (GithubConnection) TableName() string {
+func (connection GithubConnection) TableName() string {
return "_tool_github_connections"
}
+func (connection GithubConnection) Sanitize() GithubConnection {
+ connection.Token = ""
+ return connection
+}
+
// Using GithubUserOfToken because it requires authentication, and it is
public information anyway.
type GithubUserOfToken struct {
Login string `json:"login"`
diff --git a/backend/plugins/gitlab/api/connection_api.go
b/backend/plugins/gitlab/api/connection_api.go
index ef00ac349..c03cf1727 100644
--- a/backend/plugins/gitlab/api/connection_api.go
+++ b/backend/plugins/gitlab/api/connection_api.go
@@ -35,23 +35,14 @@ type GitlabTestConnResponse struct {
Connection *models.GitlabConn
}
-// @Summary test gitlab connection
-// @Description Test gitlab Connection
-// @Tags plugins/gitlab
-// @Param body body models.GitlabConn true "json body"
-// @Success 200 {object} GitlabTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/gitlab/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- // decode
- var err errors.Error
- var connection models.GitlabConn
- if err = api.Decode(input.Body, &connection, vld); err != nil {
- return nil, err
+func testConnection(ctx context.Context, connection models.GitlabConn)
(*GitlabTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
-
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -73,12 +64,56 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil, errors.BadInput.New("token need api or read_api
permissions scope")
}
+ connection = connection.Sanitize()
body := GitlabTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
- return &plugin.ApiResourceOutput{Body: body, Status: http.StatusOK}, nil
+ return &body, nil
+}
+
+// TestConnection test gitlab connection
+// @Summary test gitlab connection
+// @Description Test gitlab Connection
+// @Tags plugins/gitlab
+// @Param body body models.GitlabConn true "json body"
+// @Success 200 {object} GitlabTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/gitlab/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ var err errors.Error
+ var connection models.GitlabConn
+ if err = api.Decode(input.Body, &connection, vld); err != nil {
+ return nil, err
+ }
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test gitlab connection
+// @Summary test gitlab connection
+// @Description Test gitlab Connection
+// @Tags plugins/gitlab
+// @Success 200 {object} GitlabTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/gitlab/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection, err := dsHelper.ConnApi.FindByPk(input)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ result, err := testConnection(context.TODO(), connection.GitlabConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create gitlab connection
diff --git a/backend/plugins/gitlab/api/init.go
b/backend/plugins/gitlab/api/init.go
index 4a88534c4..02bf69694 100644
--- a/backend/plugins/gitlab/api/init.go
+++ b/backend/plugins/gitlab/api/init.go
@@ -42,6 +42,11 @@ func Init(br context.BasicRes, p plugin.PluginMeta) {
br,
p.Name(),
[]string{"name"},
+ func(c models.GitlabConnection) models.GitlabConnection {
+ return c.Sanitize()
+ },
+ nil,
+ nil,
)
// TODO: remove connectionHelper and refactor remoteHelper
vld = validator.New()
diff --git a/backend/plugins/gitlab/impl/impl.go
b/backend/plugins/gitlab/impl/impl.go
index 2de57fa02..9095db6cf 100644
--- a/backend/plugins/gitlab/impl/impl.go
+++ b/backend/plugins/gitlab/impl/impl.go
@@ -239,6 +239,9 @@ func (p Gitlab) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/scopes/:scopeId": {
"GET": api.GetScope,
"PATCH": api.PatchScope,
diff --git a/backend/plugins/gitlab/models/connection.go
b/backend/plugins/gitlab/models/connection.go
index 48d33d069..411b7a82f 100644
--- a/backend/plugins/gitlab/models/connection.go
+++ b/backend/plugins/gitlab/models/connection.go
@@ -42,6 +42,11 @@ func (conn *GitlabConn) SetupAuthentication(request
*http.Request) errors.Error
return nil
}
+func (conn *GitlabConn) Sanitize() GitlabConn {
+ conn.Token = ""
+ return *conn
+}
+
// PrepareApiClient test api and set the IsPrivateToken,version,UserId and so
on.
func (conn *GitlabConn) PrepareApiClient(apiClient
apihelperabstract.ApiClientAbstract) errors.Error {
header1 := http.Header{}
@@ -139,3 +144,8 @@ type ApiUserResponse struct {
func (GitlabConnection) TableName() string {
return "_tool_gitlab_connections"
}
+
+func (connection GitlabConnection) Sanitize() GitlabConnection {
+ connection.GitlabConn = connection.GitlabConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/jenkins/api/connection.go
b/backend/plugins/jenkins/api/connection.go
index ac4f90693..5ea1058da 100644
--- a/backend/plugins/jenkins/api/connection.go
+++ b/backend/plugins/jenkins/api/connection.go
@@ -35,28 +35,19 @@ type JenkinsTestConnResponse struct {
Connection *models.JenkinsConn
}
-// @Summary test jenkins connection
-// @Description Test Jenkins Connection
-// @Tags plugins/jenkins
-// @Param body body models.JenkinsConn true "json body"
-// @Success 200 {object} JenkinsTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/jenkins/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- // decode
- var err errors.Error
- var connection models.JenkinsConn
- err = api.Decode(input.Body, &connection, vld)
- if err != nil {
- return nil, err
+func testConnection(ctx context.Context, connection models.JenkinsConn)
(*JenkinsTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
// Check if the URL contains "/api"
if strings.Contains(connection.Endpoint, "/api") {
return nil,
errors.HttpStatus(http.StatusBadRequest).New("Invalid URL. Please use the base
URL without /api")
}
// test connection
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -72,12 +63,60 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected
status code when testing connection")
}
+ connection = connection.Sanitize()
body := JenkinsTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
// output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test jenkins connection
+// @Summary test jenkins connection
+// @Description Test Jenkins Connection
+// @Tags plugins/jenkins
+// @Param body body models.JenkinsConn true "json body"
+// @Success 200 {object} JenkinsTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/jenkins/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ var err errors.Error
+ var connection models.JenkinsConn
+ err = api.Decode(input.Body, &connection, vld)
+ if err != nil {
+ return nil, err
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test jenkins connection
+// @Summary test jenkins connection
+// @Description Test Jenkins Connection
+// @Tags plugins/jenkins
+// @Success 200 {object} JenkinsTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/jenkins/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.JenkinsConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.JenkinsConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create jenkins connection
@@ -97,7 +136,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch jenkins connection
@@ -115,7 +154,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a jenkins connection
@@ -127,7 +166,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/jenkins/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.JenkinsConnection{}, input)
+ conn := &models.JenkinsConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// @Summary get all jenkins connections
@@ -144,6 +190,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -160,5 +209,5 @@ func GetConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, e
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/jenkins/impl/impl.go
b/backend/plugins/jenkins/impl/impl.go
index d0807fd64..8dee70297 100644
--- a/backend/plugins/jenkins/impl/impl.go
+++ b/backend/plugins/jenkins/impl/impl.go
@@ -183,6 +183,9 @@ func (p Jenkins) ApiResources()
map[string]map[string]plugin.ApiResourceHandler
"connections/:connectionId/remote-scopes": {
"GET": api.RemoteScopes,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/search-remote-scopes": {
"GET": api.SearchRemoteScopes,
},
diff --git a/backend/plugins/jenkins/models/connection.go
b/backend/plugins/jenkins/models/connection.go
index 0967ebb79..665ab4d66 100644
--- a/backend/plugins/jenkins/models/connection.go
+++ b/backend/plugins/jenkins/models/connection.go
@@ -27,6 +27,11 @@ type JenkinsConn struct {
helper.BasicAuth `mapstructure:",squash"`
}
+func (connection JenkinsConn) Sanitize() JenkinsConn {
+ connection.Password = ""
+ return connection
+}
+
// JenkinsConnection holds JenkinsConn plus ID/Name for database storage
type JenkinsConnection struct {
helper.BaseConnection `mapstructure:",squash"`
@@ -36,3 +41,8 @@ type JenkinsConnection struct {
func (JenkinsConnection) TableName() string {
return "_tool_jenkins_connections"
}
+
+func (connection JenkinsConnection) Sanitize() JenkinsConnection {
+ connection.JenkinsConn = connection.JenkinsConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/jira/api/connection.go
b/backend/plugins/jira/api/connection.go
index 6720afd13..f72a182d2 100644
--- a/backend/plugins/jira/api/connection.go
+++ b/backend/plugins/jira/api/connection.go
@@ -38,28 +38,16 @@ type JiraTestConnResponse struct {
Connection *models.JiraConn
}
-// @Summary test jira connection
-// @Description Test Jira Connection
-// @Tags plugins/jira
-// @Param body body models.JiraConn true "json body"
-// @Success 200 {object} JiraTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/jira/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- // decode
- var err errors.Error
- var connection models.JiraConn
- e := mapstructure.Decode(input.Body, &connection)
- if e != nil {
- return nil, errors.Convert(e)
- }
- e = vld.StructExcept(connection, "BasicAuth", "AccessToken")
- if e != nil {
- return nil, errors.Convert(e)
+func testConnection(ctx context.Context, connection models.JiraConn)
(*JiraTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ e := vld.StructExcept(connection, "BasicAuth", "AccessToken")
+ if e != nil {
+ return nil, errors.Convert(e)
+ }
}
// test connection
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -118,6 +106,7 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if res.StatusCode != http.StatusOK {
return nil,
errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("%s Unexpected [%s] status
code: %d %s", getStatusFail, res.Request.URL, res.StatusCode, errMsg))
}
+ connection = connection.Sanitize()
body := JiraTestConnResponse{}
body.Success = true
body.Message = "success"
@@ -125,7 +114,54 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test jira connection
+// @Summary test jira connection
+// @Description Test Jira Connection
+// @Tags plugins/jira
+// @Param body body models.JiraConn true "json body"
+// @Success 200 {object} JiraTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/jira/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ var err errors.Error
+ var connection models.JiraConn
+ e := mapstructure.Decode(input.Body, &connection)
+ if e != nil {
+ return nil, errors.Convert(e)
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test jira connection
+// @Summary test jira connection
+// @Description Test Jira Connection
+// @Tags plugins/jira
+// @Success 200 {object} JiraTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/jira/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.JiraConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.JiraConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create jira connection
@@ -143,7 +179,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch jira connection
@@ -160,7 +196,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a jira connection
@@ -172,7 +208,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/jira/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.JiraConnection{}, input)
+ conn := &models.JiraConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// @Summary get all jira connections
@@ -188,6 +231,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -204,5 +250,5 @@ func GetConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, e
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/jira/impl/impl.go
b/backend/plugins/jira/impl/impl.go
index d95587c3f..0b428bbce 100644
--- a/backend/plugins/jira/impl/impl.go
+++ b/backend/plugins/jira/impl/impl.go
@@ -290,6 +290,9 @@ func (p Jira) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"connections/:connectionId/proxy/rest/*path": {
"GET": api.Proxy,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/remote-scopes": {
"GET": api.RemoteScopes,
},
diff --git a/backend/plugins/jira/models/connection.go
b/backend/plugins/jira/models/connection.go
index 8e79a0aee..0229988f8 100644
--- a/backend/plugins/jira/models/connection.go
+++ b/backend/plugins/jira/models/connection.go
@@ -44,6 +44,12 @@ type JiraConn struct {
helper.AccessToken `mapstructure:",squash"`
}
+func (jc *JiraConn) Sanitize() JiraConn {
+ jc.Password = ""
+ jc.AccessToken.Token = ""
+ return *jc
+}
+
// SetupAuthentication implements the `IAuthentication` interface by delegating
// the actual logic to the `MultiAuth` struct to help us write less code
func (jc *JiraConn) SetupAuthentication(req *http.Request) errors.Error {
@@ -59,3 +65,8 @@ type JiraConnection struct {
func (JiraConnection) TableName() string {
return "_tool_jira_connections"
}
+
+func (connection JiraConnection) Sanitize() JiraConnection {
+ connection.JiraConn = connection.JiraConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/pagerduty/api/connection.go
b/backend/plugins/pagerduty/api/connection.go
index 54e9ca900..95a9b97be 100644
--- a/backend/plugins/pagerduty/api/connection.go
+++ b/backend/plugins/pagerduty/api/connection.go
@@ -27,6 +27,30 @@ import (
"github.com/apache/incubator-devlake/plugins/pagerduty/models"
)
+func testConnection(ctx context.Context, connection models.PagerDutyConn)
(*plugin.ApiResourceOutput, errors.Error) {
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
+ }
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
+ if err != nil {
+ return nil, err
+ }
+ response, err := apiClient.Get("licenses", nil, nil)
+ if err != nil {
+ return nil, err
+ }
+ if response.StatusCode == http.StatusUnauthorized {
+ return nil,
errors.HttpStatus(http.StatusBadRequest).New("StatusUnauthorized error while
testing connection")
+ }
+ if response.StatusCode == http.StatusOK {
+ return &plugin.ApiResourceOutput{Body: nil, Status:
http.StatusOK}, nil
+ }
+ return &plugin.ApiResourceOutput{Body: nil, Status:
response.StatusCode}, errors.HttpStatus(response.StatusCode).Wrap(err, "could
not validate connection")
+}
+
+// TestConnection test pagerduty connection
// @Summary test pagerduty connection
// @Description Test Pagerduty Connection
// @Tags plugins/pagerduty
@@ -41,23 +65,24 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
- if err != nil {
- return nil, err
- }
- response, err := apiClient.Get("licenses", nil, nil)
- if err != nil {
- return nil, err
- }
-
- if response.StatusCode == http.StatusUnauthorized {
- return nil,
errors.HttpStatus(http.StatusBadRequest).New("StatusUnauthorized error while
testing connection")
- }
+ return testConnection(context.TODO(), connection)
+}
- if response.StatusCode == http.StatusOK {
- return &plugin.ApiResourceOutput{Body: nil, Status:
http.StatusOK}, nil
+// TestExistingConnection test pagerduty connection
+// @Summary test pagerduty connection
+// @Description Test Pagerduty Connection
+// @Tags plugins/pagerduty
+// @Success 200 {object} shared.ApiBody "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/pagerduty/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.PagerDutyConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
}
- return &plugin.ApiResourceOutput{Body: nil, Status:
response.StatusCode}, errors.HttpStatus(response.StatusCode).Wrap(err, "could
not validate connection")
+ return testConnection(context.TODO(), connection.PagerDutyConn)
}
// @Summary create pagerduty connection
@@ -74,7 +99,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch pagerduty connection
@@ -91,7 +116,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary delete pagerduty connection
@@ -103,7 +128,13 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/pagerduty/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.PagerDutyConnection{}, input)
+ conn := &models.PagerDutyConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
}
// @Summary list pagerduty connections
@@ -119,7 +150,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
-
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections}, nil
}
@@ -136,5 +169,5 @@ func GetConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, e
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
diff --git a/backend/plugins/pagerduty/impl/impl.go
b/backend/plugins/pagerduty/impl/impl.go
index ef15eb9c1..8f726e436 100644
--- a/backend/plugins/pagerduty/impl/impl.go
+++ b/backend/plugins/pagerduty/impl/impl.go
@@ -146,6 +146,9 @@ func (p PagerDuty) ApiResources()
map[string]map[string]plugin.ApiResourceHandle
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/remote-scopes": {
"GET": api.RemoteScopes,
},
diff --git a/backend/plugins/pagerduty/models/connection.go
b/backend/plugins/pagerduty/models/connection.go
index 3d18839f1..e287b4f48 100644
--- a/backend/plugins/pagerduty/models/connection.go
+++ b/backend/plugins/pagerduty/models/connection.go
@@ -62,3 +62,8 @@ type ApiUserResponse struct {
func (PagerDutyConnection) TableName() string {
return "_tool_pagerduty_connections"
}
+
+func (connection PagerDutyConnection) Sanitize() PagerDutyConnection {
+ connection.Token = ""
+ return connection
+}
diff --git a/backend/plugins/slack/api/connection.go
b/backend/plugins/slack/api/connection.go
index 620230e7b..1094986c0 100644
--- a/backend/plugins/slack/api/connection.go
+++ b/backend/plugins/slack/api/connection.go
@@ -34,6 +34,27 @@ type SlackTestConnResponse struct {
Connection *models.SlackConn
}
+func testConnection(ctx context.Context, connection models.SlackConn)
(*SlackTestConnResponse, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
+ }
+ // test connection
+ _, err := api.NewApiClientFromConnection(context.TODO(), basicRes,
&connection)
+ if err != nil {
+ return nil, err
+ }
+ connection = connection.Sanitize()
+ body := SlackTestConnResponse{}
+ body.Success = true
+ body.Message = "success"
+ body.Connection = &connection
+ return &body, nil
+}
+
+// TestConnection test slack connection
// @Summary test slack connection
// @Description Test slack Connection. endpoint:
https://open.slack.cn/open-apis/
// @Tags plugins/slack
@@ -48,18 +69,34 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err := api.Decode(input.Body, &connection, vld); err != nil {
return nil, errors.BadInput.Wrap(err, "could not decode request
parameters")
}
-
// test connection
- _, err := api.NewApiClientFromConnection(context.TODO(), basicRes,
&connection)
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
- body := SlackTestConnResponse{}
- body.Success = true
- body.Message = "success"
- body.Connection = &connection
+// TestExistingConnection test slack connection
+// @Summary test slack connection
+// @Description Test slack Connection. endpoint:
https://open.slack.cn/open-apis/
+// @Tags plugins/slack
+// @Success 200 {object} SlackTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/slack/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.SlackConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.SlackConn)
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create slack connection
@@ -76,7 +113,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch slack connection
@@ -93,7 +130,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary delete a slack connection
@@ -105,7 +142,13 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/slack/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.SlackConnection{}, input)
+ conn := &models.SlackConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
}
// @Summary get all slack connections
@@ -121,7 +164,9 @@ func ListConnections(_ *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, err
if err != nil {
return nil, err
}
-
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections}, nil
}
@@ -138,5 +183,5 @@ func GetConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, e
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/slack/impl/impl.go
b/backend/plugins/slack/impl/impl.go
index 8bd7ad9c5..e526d0642 100644
--- a/backend/plugins/slack/impl/impl.go
+++ b/backend/plugins/slack/impl/impl.go
@@ -140,6 +140,9 @@ func (p Slack) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
}
}
diff --git a/backend/plugins/slack/models/connection.go
b/backend/plugins/slack/models/connection.go
index 89182e35b..e227e9ba7 100644
--- a/backend/plugins/slack/models/connection.go
+++ b/backend/plugins/slack/models/connection.go
@@ -27,6 +27,11 @@ type SlackConn struct {
helper.AccessToken `mapstructure:",squash"`
}
+func (connection SlackConn) Sanitize() SlackConn {
+ connection.Token = ""
+ return connection
+}
+
// SlackConnection holds SlackConn plus ID/Name for database storage
type SlackConnection struct {
helper.BaseConnection `mapstructure:",squash"`
@@ -36,3 +41,8 @@ type SlackConnection struct {
func (SlackConnection) TableName() string {
return "_tool_slack_connections"
}
+
+func (connection SlackConnection) Sanitize() SlackConnection {
+ connection.SlackConn = connection.SlackConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/sonarqube/api/connection.go
b/backend/plugins/sonarqube/api/connection.go
index f34d89462..cb70e715f 100644
--- a/backend/plugins/sonarqube/api/connection.go
+++ b/backend/plugins/sonarqube/api/connection.go
@@ -36,23 +36,14 @@ type SonarqubeTestConnResponse struct {
Connection *models.SonarqubeConn
}
-// TestConnection test sonarqube connection options
-// @Summary test sonarqube connection
-// @Description Test sonarqube Connection
-// @Tags plugins/sonarqube
-// @Param body body models.SonarqubeConn true "json body"
-// @Success 200 {object} SonarqubeTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/sonarqube/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- // decode
- var err errors.Error
- var connection models.SonarqubeConn
- if err = api.Decode(input.Body, &connection, vld); err != nil {
- return nil, err
+func testConnection(ctx context.Context, connection models.SonarqubeConn)
(*plugin.ApiResourceOutput, errors.Error) {
+ // validate
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -65,24 +56,62 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
case 200: // right StatusCode
valid := &validation{}
err = api.UnmarshalResponse(res, valid)
+ if err != nil {
+ return nil, err
+ }
body := SonarqubeTestConnResponse{}
body.Success = true
body.Message = "success"
+ connection = connection.Sanitize()
body.Connection = &connection
- if err != nil {
- return nil, err
- }
if !valid.Valid {
return nil, errors.Default.New("Authentication failed,
please check your access token.")
}
return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
case 401: // error secretKey or nonceStr
return &plugin.ApiResourceOutput{Body: false, Status:
http.StatusBadRequest}, nil
- default: // unknow what happen , back to user
+ default: // unknown what happen , back to user
return &plugin.ApiResourceOutput{Body: res.Body, Status:
res.StatusCode}, nil
}
}
+// TestConnection test sonarqube connection options
+// @Summary test sonarqube connection
+// @Description Test sonarqube Connection
+// @Tags plugins/sonarqube
+// @Param body body models.SonarqubeConn true "json body"
+// @Success 200 {object} SonarqubeTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/sonarqube/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // decode
+ var err errors.Error
+ var connection models.SonarqubeConn
+ if err = api.Decode(input.Body, &connection, vld); err != nil {
+ return nil, err
+ }
+ return testConnection(context.TODO(), connection)
+}
+
+// TestExistingConnection test sonarqube connection options
+// @Summary test sonarqube connection
+// @Description Test sonarqube Connection
+// @Tags plugins/sonarqube
+// @Success 200 {object} SonarqubeTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/sonarqube/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.SonarqubeConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ return testConnection(context.TODO(), connection.SonarqubeConn)
+}
+
// PostConnections create sonarqube connection
// @Summary create sonarqube connection
// @Description Create sonarqube connection
@@ -99,7 +128,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// PatchConnection patch sonarqube connection
@@ -118,7 +147,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// DeleteConnection delete a sonarqube connection
@@ -132,7 +161,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/sonarqube/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.SonarqubeConnection{}, input)
+ conn := &models.SonarqubeConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// ListConnections get all sonarqube connections
@@ -149,6 +185,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -164,5 +203,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.SonarqubeConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/sonarqube/impl/impl.go
b/backend/plugins/sonarqube/impl/impl.go
index 3bf4894ae..1f2de31e7 100644
--- a/backend/plugins/sonarqube/impl/impl.go
+++ b/backend/plugins/sonarqube/impl/impl.go
@@ -176,6 +176,9 @@ func (p Sonarqube) ApiResources()
map[string]map[string]plugin.ApiResourceHandle
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/remote-scopes": {
"GET": api.RemoteScopes,
},
diff --git a/backend/plugins/sonarqube/models/connection.go
b/backend/plugins/sonarqube/models/connection.go
index 3b8cd3125..f881c6e3a 100644
--- a/backend/plugins/sonarqube/models/connection.go
+++ b/backend/plugins/sonarqube/models/connection.go
@@ -50,6 +50,11 @@ type SonarqubeConn struct {
SonarqubeAccessToken `mapstructure:",squash"`
}
+func (connection SonarqubeConn) Sanitize() SonarqubeConn {
+ connection.Token = ""
+ return connection
+}
+
// This object conforms to what the frontend currently sends.
type SonarqubeConnection struct {
helper.BaseConnection `mapstructure:",squash"`
@@ -66,3 +71,8 @@ type SonarqubeResponse struct {
func (SonarqubeConnection) TableName() string {
return "_tool_sonarqube_connections"
}
+
+func (connection SonarqubeConnection) Sanitize() SonarqubeConnection {
+ connection.SonarqubeConn = connection.SonarqubeConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/tapd/api/connection.go
b/backend/plugins/tapd/api/connection.go
index ea2cb946f..ee054209c 100644
--- a/backend/plugins/tapd/api/connection.go
+++ b/backend/plugins/tapd/api/connection.go
@@ -35,24 +35,15 @@ type TapdTestConnResponse struct {
Connection *models.TapdConn
}
-// @Summary test tapd connection
-// @Description Test Tapd Connection
-// @Tags plugins/tapd
-// @Param body body models.TapdConn true "json body"
-// @Success 200 {object} TapdTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/tapd/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+func testConnection(ctx context.Context, connection models.TapdConn)
(*TapdTestConnResponse, errors.Error) {
// process input
- var connection models.TapdConn
- err := api.Decode(input.Body, &connection, vld)
- if err != nil {
- return nil, err
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
-
// test connection
- apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := api.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, errors.Default.Wrap(err, fmt.Sprintf("verify token
failed for %s", connection.Username))
}
@@ -66,12 +57,59 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if res.StatusCode != http.StatusOK {
return nil,
errors.HttpStatus(res.StatusCode).New(fmt.Sprintf("unexpected status code: %d",
res.StatusCode))
}
+ connection = connection.Sanitize()
body := TapdTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
// output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test tap connection
+// @Summary test tapd connection
+// @Description Test Tapd Connection
+// @Tags plugins/tapd
+// @Param body body models.TapdConn true "json body"
+// @Success 200 {object} TapdTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/tapd/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // process input
+ var connection models.TapdConn
+ err := api.Decode(input.Body, &connection, vld)
+ if err != nil {
+ return nil, err
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test tapd connection options
+// @Summary test tapd connection
+// @Description Test Tapd Connection
+// @Tags plugins/tapd
+// @Success 200 {object} TapdTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/tapd/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.TapdConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection.TapdConn)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
}
// @Summary create tapd connection
@@ -93,7 +131,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch tapd connection
@@ -111,7 +149,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a tapd connection
@@ -123,7 +161,13 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/tapd/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.TapdConnection{}, input)
+ conn := &models.TapdConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
}
// @Summary get all tapd connections
@@ -139,7 +183,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
-
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
diff --git a/backend/plugins/tapd/impl/impl.go
b/backend/plugins/tapd/impl/impl.go
index 04ec1d62d..c28bf35ce 100644
--- a/backend/plugins/tapd/impl/impl.go
+++ b/backend/plugins/tapd/impl/impl.go
@@ -287,6 +287,9 @@ func (p Tapd) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/proxy/rest/*path": {
"GET": api.Proxy,
},
diff --git a/backend/plugins/tapd/models/connection.go
b/backend/plugins/tapd/models/connection.go
index 5a13a9c9e..e5d295adc 100644
--- a/backend/plugins/tapd/models/connection.go
+++ b/backend/plugins/tapd/models/connection.go
@@ -27,6 +27,11 @@ type TapdConn struct {
helper.BasicAuth `mapstructure:",squash"`
}
+func (connection TapdConn) Sanitize() TapdConn {
+ connection.Password = ""
+ return connection
+}
+
// TapdConnection holds TapdConn plus ID/Name for database storage
type TapdConnection struct {
helper.BaseConnection `mapstructure:",squash"`
@@ -36,3 +41,8 @@ type TapdConnection struct {
func (TapdConnection) TableName() string {
return "_tool_tapd_connections"
}
+
+func (connection TapdConnection) Sanitize() TapdConnection {
+ connection.TapdConn = connection.TapdConn.Sanitize()
+ return connection
+}
diff --git a/backend/plugins/teambition/api/connection.go
b/backend/plugins/teambition/api/connection.go
index 142ac7fe8..aec27bf42 100644
--- a/backend/plugins/teambition/api/connection.go
+++ b/backend/plugins/teambition/api/connection.go
@@ -35,22 +35,13 @@ type TeambitionTestConnResponse struct {
Connection *models.TeambitionConn
}
-// TestConnection @Summary test teambition connection
-// @Description Test teambition Connection
-// @Tags plugins/teambition
-// @Param body body models.TeambitionConn true "json body"
-// @Success 200 {object} TeambitionTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/teambition/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+func testConnection(ctx context.Context, connection models.TeambitionConn)
(*TeambitionTestConnResponse, errors.Error) {
// process input
- var connection models.TeambitionConn
- err := api.Decode(input.Body, &connection, vld)
- if err != nil {
- return nil, err
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
-
// test connection
apiClient, err := api.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
if err != nil {
@@ -80,12 +71,58 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
return nil,
errors.HttpStatus(resBody.Code).New(fmt.Sprintf("unexpected body status code:
%d", resBody.Code))
}
+ connection = connection.Sanitize()
body := TeambitionTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
// output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection @Summary test teambition connection
+// @Description Test teambition Connection
+// @Tags plugins/teambition
+// @Param body body models.TeambitionConn true "json body"
+// @Success 200 {object} TeambitionTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/teambition/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // process input
+ var connection models.TeambitionConn
+ err := api.Decode(input.Body, &connection, vld)
+ if err != nil {
+ return nil, err
+ }
+
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test teambition connection options
+// @Summary test teambition connection
+// @Description Test teambition Connection
+// @Tags plugins/teambition
+// @Success 200 {object} TeambitionTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/teambition/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.TeambitionConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ testConnectionResult, testConnectionErr :=
testConnection(context.TODO(), connection.TeambitionConn)
+ if testConnectionErr != nil {
+ return nil, testConnectionErr
+ }
+ return &plugin.ApiResourceOutput{Body: testConnectionResult, Status:
http.StatusOK}, nil
}
// PostConnections @Summary create teambition connection
@@ -103,7 +140,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// PatchConnection @Summary patch teambition connection
@@ -120,7 +157,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// DeleteConnection @Summary delete a teambition connection
@@ -132,7 +169,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/teambition/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.TeambitionConnection{}, input)
+ conn := &models.TeambitionConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// ListConnections @Summary get all teambition connections
@@ -148,6 +192,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -161,5 +208,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.TeambitionConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/teambition/impl/impl.go
b/backend/plugins/teambition/impl/impl.go
index 410dfd173..2140dfe6d 100644
--- a/backend/plugins/teambition/impl/impl.go
+++ b/backend/plugins/teambition/impl/impl.go
@@ -177,6 +177,9 @@ func (p Teambition) ApiResources()
map[string]map[string]plugin.ApiResourceHandl
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
}
}
diff --git a/backend/plugins/teambition/models/connection.go
b/backend/plugins/teambition/models/connection.go
index b50d4d13b..d58c07035 100644
--- a/backend/plugins/teambition/models/connection.go
+++ b/backend/plugins/teambition/models/connection.go
@@ -34,12 +34,22 @@ type TeambitionConn struct {
TenantType string `mapstructure:"tenantType"
validate:"required" json:"tenantType"`
}
+func (tc TeambitionConn) Sanitize() TeambitionConn {
+ tc.SecretKey = ""
+ return tc
+}
+
// TeambitionConnection holds TeambitionConn plus ID/Name for database storage
type TeambitionConnection struct {
helper.BaseConnection `mapstructure:",squash"`
TeambitionConn `mapstructure:",squash"`
}
+func (connection TeambitionConnection) Sanitize() TeambitionConnection {
+ connection.TeambitionConn = connection.TeambitionConn.Sanitize()
+ return connection
+}
+
func (tc *TeambitionConn) SetupAuthentication(req *http.Request) errors.Error {
token := jwt.New(jwt.SigningMethodHS256)
claims := make(jwt.MapClaims)
diff --git a/backend/plugins/trello/api/connection.go
b/backend/plugins/trello/api/connection.go
index 6e4776112..e6a500218 100644
--- a/backend/plugins/trello/api/connection.go
+++ b/backend/plugins/trello/api/connection.go
@@ -34,23 +34,14 @@ type TrelloTestConnResponse struct {
Connection *models.TrelloConn
}
-// @Summary test trello connection
-// @Description Test trello Connection
-// @Tags plugins/trello
-// @Param body body models.TrelloConn true "json body"
-// @Success 200 {object} TrelloTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/trello/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+func testConnection(ctx context.Context, connection models.TrelloConn)
(*TrelloTestConnResponse, errors.Error) {
// process input
- var connection models.TrelloConn
- err := helper.Decode(input.Body, &connection, vld)
- if err != nil {
- return nil, err
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
-
- apiClient, err := helper.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ apiClient, err := helper.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -66,12 +57,58 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected
status code while testing connection")
}
+ connection = connection.Sanitize()
body := TrelloTestConnResponse{}
body.Success = true
body.Message = "success"
body.Connection = &connection
// output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test trello connection
+// @Summary test trello connection
+// @Description Test trello Connection
+// @Tags plugins/trello
+// @Param body body models.TrelloConn true "json body"
+// @Success 200 {object} TrelloTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/trello/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // process input
+ var connection models.TrelloConn
+ err := helper.Decode(input.Body, &connection, vld)
+ if err != nil {
+ return nil, err
+ }
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test trello connection options
+// @Summary test trello connection
+// @Description Test trello Connection
+// @Tags plugins/trello
+// @Success 200 {object} TrelloTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/trello/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.TrelloConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ testConnectionResult, testConnectionErr :=
testConnection(context.TODO(), connection.TrelloConn)
+ if testConnectionErr != nil {
+ return nil, testConnectionErr
+ }
+ return &plugin.ApiResourceOutput{Body: testConnectionResult, Status:
http.StatusOK}, nil
}
// @Summary create trello connection
@@ -89,7 +126,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch trello connection
@@ -106,7 +143,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a trello connection
@@ -118,7 +155,14 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/trello/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.TrelloConnection{}, input)
+ conn := &models.TrelloConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
+
}
// @Summary get all trello connections
@@ -134,6 +178,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -147,5 +194,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.TrelloConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/trello/impl/impl.go
b/backend/plugins/trello/impl/impl.go
index 2b2edaaea..8454f9b33 100644
--- a/backend/plugins/trello/impl/impl.go
+++ b/backend/plugins/trello/impl/impl.go
@@ -168,6 +168,9 @@ func (p Trello) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"DELETE": api.DeleteConnection,
"GET": api.GetConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/proxy/rest/*path": {
"GET": api.Proxy,
},
diff --git a/backend/plugins/trello/models/connection.go
b/backend/plugins/trello/models/connection.go
index 92fc59155..9fce2389a 100644
--- a/backend/plugins/trello/models/connection.go
+++ b/backend/plugins/trello/models/connection.go
@@ -30,12 +30,22 @@ type TrelloConn struct {
helper.AppKey `mapstructure:",squash"`
}
+func (tc *TrelloConn) Sanitize() TrelloConn {
+ tc.SecretKey = ""
+ return *tc
+}
+
// TrelloConnection holds TrelloConn plus ID/Name for database storage
type TrelloConnection struct {
helper.BaseConnection `mapstructure:",squash"`
TrelloConn `mapstructure:",squash"`
}
+func (connection TrelloConnection) Sanitize() TrelloConnection {
+ connection.TrelloConn = connection.TrelloConn.Sanitize()
+ return connection
+}
+
// SetupAuthentication sets up the HTTP Request Authentication
func (tc *TrelloConn) SetupAuthentication(req *http.Request) errors.Error {
req.Header.Set("Authorization", fmt.Sprintf("OAuth
oauth_consumer_key=\"%s\", oauth_token=\"%s\"", tc.AppId, tc.SecretKey))
diff --git a/backend/plugins/zentao/api/connection.go
b/backend/plugins/zentao/api/connection.go
index 8bc9fee04..84168c958 100644
--- a/backend/plugins/zentao/api/connection.go
+++ b/backend/plugins/zentao/api/connection.go
@@ -36,24 +36,15 @@ type ZentaoTestConnResponse struct {
Connection *models.ZentaoConn
}
-// @Summary test zentao connection
-// @Description Test zentao Connection
-// @Tags plugins/zentao
-// @Param body body models.ZentaoConn true "json body"
-// @Success 200 {object} ZentaoTestConnResponse "Success"
-// @Failure 400 {string} errcode.Error "Bad Request"
-// @Failure 500 {string} errcode.Error "Internal Error"
-// @Router /plugins/zentao/test [POST]
-func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+func testConnection(ctx context.Context, connection models.ZentaoConn)
(*ZentaoTestConnResponse, errors.Error) {
// process input
- var connection models.ZentaoConn
- err := helper.Decode(input.Body, &connection, vld)
- if err != nil {
- return nil, errors.BadInput.Wrap(err, "failed to decode input
to be zentao connection")
+ if vld != nil {
+ if err := vld.Struct(connection); err != nil {
+ return nil, errors.Default.Wrap(err, "error validating
target")
+ }
}
-
// try to create apiClient
- client, err := helper.NewApiClientFromConnection(context.TODO(),
basicRes, &connection)
+ client, err := helper.NewApiClientFromConnection(ctx, basicRes,
&connection)
if err != nil {
return nil, err
}
@@ -65,21 +56,67 @@ func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if resp.StatusCode != http.StatusOK {
body.Success = false
body.Message = err.Error()
- return &plugin.ApiResourceOutput{Body: body, Status:
http.StatusBadRequest}, nil
+ return &body, nil
}
if connection.DbUrl != "" {
err = runner.CheckDbConnection(connection.DbUrl, 5*time.Second)
if err != nil {
body.Success = false
body.Message = "invalid DbUrl"
- return &plugin.ApiResourceOutput{Body: body, Status:
http.StatusBadRequest}, nil
+ return &body, nil
}
}
body.Success = true
body.Message = "success"
+ connection = connection.Sanitize()
body.Connection = &connection
- // output
- return &plugin.ApiResourceOutput{Body: body, Status: 200}, nil
+ return &body, nil
+}
+
+// TestConnection test zentao connection
+// @Summary test zentao connection
+// @Description Test zentao Connection
+// @Tags plugins/zentao
+// @Param body body models.ZentaoConn true "json body"
+// @Success 200 {object} ZentaoTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/zentao/test [POST]
+func TestConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ // process input
+ var connection models.ZentaoConn
+ err := helper.Decode(input.Body, &connection, vld)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "failed to decode input
to be zentao connection")
+ }
+
+ // test connection
+ result, err := testConnection(context.TODO(), connection)
+ if err != nil {
+ return nil, err
+ }
+ return &plugin.ApiResourceOutput{Body: result, Status: http.StatusOK},
nil
+}
+
+// TestExistingConnection test zentao connection options
+// @Summary test zentao connection
+// @Description Test zentao Connection
+// @Tags plugins/zentao
+// @Success 200 {object} ZentaoTestConnResponse "Success"
+// @Failure 400 {string} errcode.Error "Bad Request"
+// @Failure 500 {string} errcode.Error "Internal Error"
+// @Router /plugins/zentao/{connectionId}/test [POST]
+func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
+ connection := &models.ZentaoConnection{}
+ err := connectionHelper.First(connection, input.Params)
+ if err != nil {
+ return nil, errors.BadInput.Wrap(err, "find connection from db")
+ }
+ testConnectionResult, testConnectionErr :=
testConnection(context.TODO(), connection.ZentaoConn)
+ if testConnectionErr != nil {
+ return nil, testConnectionErr
+ }
+ return &plugin.ApiResourceOutput{Body: testConnectionResult, Status:
http.StatusOK}, nil
}
// @Summary create zentao connection
@@ -97,7 +134,7 @@ func PostConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection, Status:
http.StatusOK}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize(), Status:
http.StatusOK}, nil
}
// @Summary patch zentao connection
@@ -114,7 +151,7 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
- return &plugin.ApiResourceOutput{Body: connection}, nil
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, nil
}
// @Summary delete a zentao connection
@@ -126,7 +163,13 @@ func PatchConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
// @Failure 500 {string} errcode.Error "Internal Error"
// @Router /plugins/zentao/connections/{connectionId} [DELETE]
func DeleteConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, errors.Error) {
- return connectionHelper.Delete(&models.ZentaoConnection{}, input)
+ conn := &models.ZentaoConnection{}
+ output, err := connectionHelper.Delete(conn, input)
+ if err != nil {
+ return output, err
+ }
+ output.Body = conn.Sanitize()
+ return output, nil
}
// @Summary get all zentao connections
@@ -142,6 +185,9 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
if err != nil {
return nil, err
}
+ for idx, c := range connections {
+ connections[idx] = c.Sanitize()
+ }
return &plugin.ApiResourceOutput{Body: connections, Status:
http.StatusOK}, nil
}
@@ -155,5 +201,5 @@ func ListConnections(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput,
func GetConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput,
errors.Error) {
connection := &models.ZentaoConnection{}
err := connectionHelper.First(connection, input.Params)
- return &plugin.ApiResourceOutput{Body: connection}, err
+ return &plugin.ApiResourceOutput{Body: connection.Sanitize()}, err
}
diff --git a/backend/plugins/zentao/impl/impl.go
b/backend/plugins/zentao/impl/impl.go
index 9d8f0a6b6..3cbbbf296 100644
--- a/backend/plugins/zentao/impl/impl.go
+++ b/backend/plugins/zentao/impl/impl.go
@@ -253,6 +253,9 @@ func (p Zentao) ApiResources()
map[string]map[string]plugin.ApiResourceHandler {
"PATCH": api.PatchConnection,
"DELETE": api.DeleteConnection,
},
+ "connections/:connectionId/test": {
+ "POST": api.TestExistingConnection,
+ },
"connections/:connectionId/scopes": {
"PUT": api.PutProjectScope,
"GET": api.GetProjectScopeList,
diff --git a/backend/plugins/zentao/models/connection.go
b/backend/plugins/zentao/models/connection.go
index 09c28cef6..0d68067f3 100644
--- a/backend/plugins/zentao/models/connection.go
+++ b/backend/plugins/zentao/models/connection.go
@@ -20,6 +20,8 @@ package models
import (
"fmt"
"net/http"
+ "net/url"
+ "strings"
"github.com/apache/incubator-devlake/core/errors"
helper "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
@@ -67,12 +69,43 @@ type ZentaoConn struct {
DbMaxConns int `json:"dbMaxConns" mapstructure:"dbMaxConns"`
}
+func (connection ZentaoConn) Sanitize() ZentaoConn {
+ connection.Password = ""
+ if connection.DbUrl != "" {
+ connection.DbUrl = connection.SanitizeDbUrl()
+ }
+ return connection
+}
+
// ZentaoConnection holds ZentaoConn plus ID/Name for database storage
type ZentaoConnection struct {
helper.BaseConnection `mapstructure:",squash"`
ZentaoConn `mapstructure:",squash"`
}
+func (connection ZentaoConn) SanitizeDbUrl() string {
+ if connection.DbUrl == "" {
+ return connection.DbUrl
+ }
+ dbUrl := connection.DbUrl
+ u, _ := url.Parse(dbUrl)
+ if u != nil && u.User != nil {
+ password, ok := u.User.Password()
+ if ok {
+ dbUrl = strings.Replace(dbUrl, password,
strings.Repeat("*", len(password)), -1)
+ }
+ }
+ if dbUrl == connection.DbUrl {
+ dbUrl = ""
+ }
+ return dbUrl
+}
+
+func (connection ZentaoConnection) Sanitize() ZentaoConnection {
+ connection.ZentaoConn = connection.ZentaoConn.Sanitize()
+ return connection
+}
+
// This object conforms to what the frontend currently expects.
type ZentaoResponse struct {
Name string `json:"name"`