You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by wa...@apache.org on 2022/06/06 15:49:49 UTC
[incubator-devlake] 01/04: feat(api): change jira basicauthencoded to username/password and extract common utils
This is an automated email from the ASF dual-hosted git repository.
warren pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git
commit f88e5c22fb6e6699930967ab9c145cab162ec752
Author: Yingchu Chen <yi...@merico.dev>
AuthorDate: Wed May 25 17:24:19 2022 +0800
feat(api): change jira basicauthencoded to username/password and extract common utils
closes #2003
---
api/shared/api_output.go | 2 +-
config-ui/src/hooks/useConnectionManager.jsx | 2 +-
config-ui/src/pages/configure/settings/jira.jsx | 26 +--
plugins/feishu/tasks/api_client.go | 2 +-
plugins/github/tasks/api_client.go | 2 +-
plugins/gitlab/tasks/api_client.go | 2 +-
plugins/helper/connection.go | 217 +++++++++++++++++++++
plugins/jira/api/connection.go | 191 +++---------------
plugins/jira/api/issue_status_mapping.go | 216 --------------------
plugins/jira/api/issue_type_mapping.go | 214 --------------------
plugins/jira/api/proxy.go | 16 +-
plugins/jira/jira.go | 17 +-
plugins/jira/models/connection.go | 16 +-
.../migrationscripts/updateSchemas20220505.go | 20 +-
.../migrationscripts/updateSchemas20220524.go | 72 +++++++
plugins/jira/tasks/api_client.go | 8 +-
plugins/tapd/tasks/api_client.go | 4 +-
17 files changed, 353 insertions(+), 674 deletions(-)
diff --git a/api/shared/api_output.go b/api/shared/api_output.go
index 8e006acd..28e2e630 100644
--- a/api/shared/api_output.go
+++ b/api/shared/api_output.go
@@ -35,7 +35,7 @@ func ApiOutputError(c *gin.Context, err error, status int) {
Message: err.Error(),
})
} else {
- logger.Global.Error("Server Internal Error: %w", err)
+ logger.Global.Error("Server Internal Error: %s", err.Error())
c.JSON(status, &ApiBody{
Success: false,
Message: err.Error(),
diff --git a/config-ui/src/hooks/useConnectionManager.jsx b/config-ui/src/hooks/useConnectionManager.jsx
index a3558df0..f9116919 100644
--- a/config-ui/src/hooks/useConnectionManager.jsx
+++ b/config-ui/src/hooks/useConnectionManager.jsx
@@ -83,7 +83,7 @@ function useConnectionManager ({
let connectionPayload
switch (activeProvider.id) {
case Providers.JIRA:
- connectionPayload = { endpoint: endpointUrl, auth: token, proxy: proxy }
+ connectionPayload = { endpoint: endpointUrl, username: username, password: password, proxy: proxy }
break
case Providers.GITHUB:
connectionPayload = { endpoint: endpointUrl, auth: token, proxy: proxy }
diff --git a/config-ui/src/pages/configure/settings/jira.jsx b/config-ui/src/pages/configure/settings/jira.jsx
index 8305eaa0..cda3defc 100644
--- a/config-ui/src/pages/configure/settings/jira.jsx
+++ b/config-ui/src/pages/configure/settings/jira.jsx
@@ -88,25 +88,6 @@ export default function JiraSettings (props) {
: null
}
- const parseTypeMappings = useCallback((mappings = []) => {
- const GroupedMappings = {
- [MAPPING_TYPES.Requirement]: [],
- [MAPPING_TYPES.Incident]: [],
- [MAPPING_TYPES.Bug]: [],
- }
- Object.entries(mappings).forEach(([tag, typeObj]) => {
- GroupedMappings[typeObj.standardType].push(tag)
- })
- console.log('>>>> PARSED TYPE MAPPINGS ....', GroupedMappings)
- setTypeMappingRequirement(GroupedMappings[MAPPING_TYPES.Requirement])
- setTypeMappingBug(GroupedMappings[MAPPING_TYPES.Bug])
- setTypeMappingIncident(GroupedMappings[MAPPING_TYPES.Incident])
- setRequirementTags(requirementTagsList?.filter(t => GroupedMappings[MAPPING_TYPES.Requirement].includes(t.value)))
- setBugTags(bugTagsList?.filter(t => GroupedMappings[MAPPING_TYPES.Bug].includes(t.value)))
- setIncidentTags(incidentTagsList?.filter(t => GroupedMappings[MAPPING_TYPES.Incident].includes(t.value)))
- return GroupedMappings
- }, [requirementTagsList, bugTagsList, incidentTagsList])
-
useEffect(() => {
const settings = {
epicKeyField: jiraIssueEpicKeyField?.value || '',
@@ -164,13 +145,12 @@ export default function JiraSettings (props) {
console.log('>> CONN SETTINGS OBJECT ', connection)
if (connection && connection.ID) {
// Parse Type Mappings (V2)
- parseTypeMappings(connection.typeMappings)
setStatusMappings([])
setRemoteLinkCommitSha(connection.remotelinkCommitShaPattern)
// setJiraIssueEpicKeyField(fieldsList.find(f => f.value === connection.epicKeyField))
// setJiraIssueStoryPointField(fieldsList.find(f => f.value === connection.storyPointField))
}
- }, [connection, parseTypeMappings])
+ }, [connection])
useEffect(() => {
setTypeMappingRequirement(requirementTags)
@@ -208,10 +188,6 @@ export default function JiraSettings (props) {
setJiraIssueStoryPointField(fieldsList.find(f => f.value === connection.storyPointField))
}, [fieldsList, connection.epicKeyField, connection.storyPointField])
- useEffect(() => {
- parseTypeMappings(connection.typeMappings)
- }, [requirementTagsList, bugTagsList, incidentTagsList, connection.typeMappings, parseTypeMappings])
-
return (
<>
<div className='headlineContainer'>
diff --git a/plugins/feishu/tasks/api_client.go b/plugins/feishu/tasks/api_client.go
index d6b7b7d0..da54b5f9 100644
--- a/plugins/feishu/tasks/api_client.go
+++ b/plugins/feishu/tasks/api_client.go
@@ -92,7 +92,7 @@ func NewFeishuApiClient(taskCtx core.TaskContext) (*helper.ApiAsyncClient, error
apiClient.SetAfterFunction(func(res *http.Response) error {
if res.StatusCode == http.StatusUnauthorized {
- return fmt.Errorf("feishu authentication failed, please check your Bearer Auth Token")
+ return fmt.Errorf("feishu authentication failed, please check your AccessToken")
}
return nil
})
diff --git a/plugins/github/tasks/api_client.go b/plugins/github/tasks/api_client.go
index 94a60e05..aa0e9aa0 100644
--- a/plugins/github/tasks/api_client.go
+++ b/plugins/github/tasks/api_client.go
@@ -60,7 +60,7 @@ func CreateApiClient(taskCtx core.TaskContext) (*helper.ApiAsyncClient, error) {
})
apiClient.SetAfterFunction(func(res *http.Response) error {
if res.StatusCode == http.StatusUnauthorized {
- return fmt.Errorf("authentication failed, please check your Token configuration")
+ return fmt.Errorf("authentication failed, please check your AccessToken configuration")
}
return nil
})
diff --git a/plugins/gitlab/tasks/api_client.go b/plugins/gitlab/tasks/api_client.go
index 0dc8bf64..f4c2b653 100644
--- a/plugins/gitlab/tasks/api_client.go
+++ b/plugins/gitlab/tasks/api_client.go
@@ -54,7 +54,7 @@ func NewGitlabApiClient(taskCtx core.TaskContext) (*helper.ApiAsyncClient, error
}
apiClient.SetAfterFunction(func(res *http.Response) error {
if res.StatusCode == http.StatusUnauthorized {
- return fmt.Errorf("authentication failed, please check your Basic Auth Token")
+ return fmt.Errorf("authentication failed, please check your AccessToken")
}
return nil
})
diff --git a/plugins/helper/connection.go b/plugins/helper/connection.go
new file mode 100644
index 00000000..93974f73
--- /dev/null
+++ b/plugins/helper/connection.go
@@ -0,0 +1,217 @@
+package helper
+
+import (
+ "encoding/base64"
+ "fmt"
+ "github.com/apache/incubator-devlake/config"
+ "github.com/apache/incubator-devlake/models/common"
+ "github.com/apache/incubator-devlake/plugins/core"
+ "github.com/go-playground/validator/v10"
+ "github.com/mitchellh/mapstructure"
+ "gorm.io/gorm"
+ "gorm.io/gorm/clause"
+ "reflect"
+ "strconv"
+)
+
+type BaseConnection struct {
+ Name string `gorm:"type:varchar(100);uniqueIndex" json:"name" validate:"required"`
+ common.Model
+}
+
+type BasicAuth struct {
+ Username string `mapstructure:"username" validate:"required" json:"username"`
+ Password string `mapstructure:"password" validate:"required" json:"password" encrypt:"yes"`
+}
+
+func (ba BasicAuth) GetEncodedToken() string {
+ return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%v:%v", ba.Username, ba.Password)))
+}
+
+type AccessToken struct {
+ Token string `mapstructure:"token" validate:"required" json:"token" encrypt:"yes"`
+}
+
+type RestConnection struct {
+ BaseConnection `mapstructure:",squash"`
+ Endpoint string `mapstructure:"endpoint" validate:"required" json:"endpoint"`
+ Proxy string `mapstructure:"proxy" json:"proxy"`
+ RateLimit int `comment:"api request rate limt per hour" json:"rateLimit"`
+}
+
+// RefreshAndSaveConnection populate from request input into connection which come from REST functions to connection struct and save to DB
+// and only change value which `data` has
+// mergeFieldsToConnection merges fields from data
+// `connection` is the pointer of a plugin connection
+// `data` is http request input param
+func RefreshAndSaveConnection(connection interface{}, data map[string]interface{}, db *gorm.DB) error {
+ var err error
+ // update fields from request body
+ err = mergeFieldsToConnection(connection, data)
+ if err != nil {
+ return err
+ }
+
+ err = saveToDb(connection, db)
+
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func saveToDb(connection interface{}, db *gorm.DB) error {
+ dataVal := reflect.ValueOf(connection)
+ if dataVal.Kind() != reflect.Ptr {
+ panic("entityPtr is not a pointer")
+ }
+
+ dataType := reflect.Indirect(dataVal).Type()
+ fieldName := getEncryptField(dataType, "encrypt")
+ plainPwd := ""
+ err := doEncrypt(dataVal, fieldName)
+ if err != nil {
+ return err
+ }
+ err = db.Clauses(clause.OnConflict{UpdateAll: true}).Save(connection).Error
+ if err != nil {
+ return err
+ }
+
+ err = doDecrypt(dataVal, fieldName)
+ if err != nil {
+ return err
+ }
+ dataVal.Elem().FieldByName(fieldName).Set(reflect.ValueOf(plainPwd))
+
+ return err
+}
+
+// mergeFieldsToConnection will populate all value in map to connection struct and validate the struct
+func mergeFieldsToConnection(specificConnection interface{}, connections ...map[string]interface{}) error {
+ // decode
+ for _, connection := range connections {
+ err := mapstructure.Decode(connection, specificConnection)
+ if err != nil {
+ return err
+ }
+ }
+ // validate
+ vld := validator.New()
+ err := vld.Struct(specificConnection)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func getEncKey() (string, error) {
+ // encrypt
+ v := config.GetConfig()
+ encKey := v.GetString(core.EncodeKeyEnvStr)
+ if encKey == "" {
+ // Randomly generate a bunch of encryption keys and set them to config
+ encKey = core.RandomEncKey()
+ v.Set(core.EncodeKeyEnvStr, encKey)
+ err := config.WriteConfig(v)
+ if err != nil {
+ return encKey, err
+ }
+ }
+ return encKey, nil
+}
+
+// FindConnectionByInput finds connection from db by parsing request input and decrypt it
+func FindConnectionByInput(input *core.ApiResourceInput, connection interface{}, db *gorm.DB) error {
+ dataVal := reflect.ValueOf(connection)
+ if dataVal.Kind() != reflect.Ptr {
+ return fmt.Errorf("connection is not a pointer")
+ }
+
+ id, err := GetConnectionIdByInputParam(input)
+ if err != nil {
+ return fmt.Errorf("invalid connectionId")
+ }
+
+ err = db.First(connection, id).Error
+ if err != nil {
+ fmt.Printf("--- %s", err.Error())
+ return err
+ }
+
+ dataType := reflect.Indirect(dataVal).Type()
+
+ fieldName := getEncryptField(dataType, "encrypt")
+ return doDecrypt(dataVal, fieldName)
+
+}
+
+// GetConnectionIdByInputParam gets connectionId by parsing request input
+func GetConnectionIdByInputParam(input *core.ApiResourceInput) (uint64, error) {
+ connectionId := input.Params["connectionId"]
+ if connectionId == "" {
+ return 0, fmt.Errorf("missing connectionId")
+ }
+ return strconv.ParseUint(connectionId, 10, 64)
+}
+
+func getEncryptField(t reflect.Type, tag string) string {
+ fieldName := ""
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ if field.Type.Kind() == reflect.Struct {
+ fieldName = getEncryptField(field.Type, tag)
+ } else {
+ if field.Tag.Get(tag) == "yes" {
+ fieldName = field.Name
+ }
+ }
+ }
+ return fieldName
+}
+
+// DecryptConnection decrypts password/token field for connection
+func DecryptConnection(connection interface{}, fieldName string) error {
+ dataVal := reflect.ValueOf(connection)
+ if dataVal.Kind() != reflect.Ptr {
+ panic("connection is not a pointer")
+ }
+ if len(fieldName) == 0 {
+ dataType := reflect.Indirect(dataVal).Type()
+ fieldName = getEncryptField(dataType, "encrypt")
+ }
+ return doDecrypt(dataVal, fieldName)
+}
+
+func doDecrypt(dataVal reflect.Value, fieldName string) error {
+ encryptCode, err := getEncKey()
+ if err != nil {
+ return err
+ }
+ if len(fieldName) > 0 {
+ decryptStr, err := core.Decrypt(encryptCode, dataVal.Elem().FieldByName(fieldName).String())
+ if err != nil {
+ return err
+ }
+ dataVal.Elem().FieldByName(fieldName).Set(reflect.ValueOf(decryptStr))
+ }
+ return nil
+}
+
+func doEncrypt(dataVal reflect.Value, fieldName string) error {
+ encryptCode, err := getEncKey()
+ if err != nil {
+ return err
+ }
+ if len(fieldName) > 0 {
+ plainPwd := dataVal.Elem().FieldByName(fieldName).String()
+ encyptedStr, err := core.Encrypt(encryptCode, plainPwd)
+
+ if err != nil {
+ return err
+ }
+ dataVal.Elem().FieldByName(fieldName).Set(reflect.ValueOf(encyptedStr))
+ }
+ return nil
+}
diff --git a/plugins/jira/api/connection.go b/plugins/jira/api/connection.go
index 96970d77..aa94537a 100644
--- a/plugins/jira/api/connection.go
+++ b/plugins/jira/api/connection.go
@@ -25,9 +25,6 @@ import (
"strings"
"time"
- "github.com/apache/incubator-devlake/config"
- "github.com/apache/incubator-devlake/models/common"
-
"github.com/apache/incubator-devlake/errors"
"github.com/apache/incubator-devlake/plugins/core"
"github.com/apache/incubator-devlake/plugins/helper"
@@ -52,11 +49,12 @@ func TestConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, erro
if err != nil {
return nil, err
}
+
// test connection
apiClient, err := helper.NewApiClient(
connection.Endpoint,
map[string]string{
- "Authorization": fmt.Sprintf("Basic %v", connection.Auth),
+ "Authorization": fmt.Sprintf("Basic %v", connection.GetEncodedToken()),
},
3*time.Second,
connection.Proxy,
@@ -100,111 +98,6 @@ func TestConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, erro
return nil, nil
}
-func findConnectionByInputParam(input *core.ApiResourceInput) (*models.JiraConnection, error) {
- jiraConnectionId, err := getJiraConnectionIdByInputParam(input)
- if err != nil {
- return nil, fmt.Errorf("invalid connectionId")
- }
- return getJiraConnectionById(jiraConnectionId)
-}
-
-func getJiraConnectionIdByInputParam(input *core.ApiResourceInput) (uint64, error) {
- connectionId := input.Params["connectionId"]
- if connectionId == "" {
- return 0, fmt.Errorf("missing connectionId")
- }
- return strconv.ParseUint(connectionId, 10, 64)
-}
-
-func getJiraConnectionById(id uint64) (*models.JiraConnection, error) {
- jiraConnection := &models.JiraConnection{}
- err := db.First(jiraConnection, id).Error
- if err != nil {
- return nil, err
- }
-
- // decrypt
- v := config.GetConfig()
- encKey := v.GetString(core.EncodeKeyEnvStr)
- jiraConnection.BasicAuthEncoded, err = core.Decrypt(encKey, jiraConnection.BasicAuthEncoded)
- if err != nil {
- log.Error("failed to decrypt basic auth: %s", err)
- }
-
- return jiraConnection, nil
-}
-func mergeFieldsToJiraConnection(jiraConnection *models.JiraConnection, connections ...map[string]interface{}) error {
- // decode
- for _, connection := range connections {
- err := mapstructure.Decode(connection, jiraConnection)
- if err != nil {
- return err
- }
- }
-
- // validate
- vld := validator.New()
- err := vld.Struct(jiraConnection)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func refreshAndSaveJiraConnection(jiraConnection *models.JiraConnection, data map[string]interface{}) error {
- var err error
- // update fields from request body
- err = mergeFieldsToJiraConnection(jiraConnection, data)
- if err != nil {
- return err
- }
-
- encKey, err := getEncKey()
- if err != nil {
- return err
- }
- jiraConnection.BasicAuthEncoded, err = core.Encrypt(encKey, jiraConnection.BasicAuthEncoded)
- if err != nil {
- return err
- }
-
- // transaction for nested operations
- tx := db.Begin()
- defer func() {
- if err != nil {
- tx.Rollback()
- } else {
- tx.Commit()
- }
- }()
- if jiraConnection.ID > 0 {
- err = tx.Save(jiraConnection).Error
- } else {
- err = tx.Create(jiraConnection).Error
- }
- if err != nil {
- if common.IsDuplicateError(err) {
- return fmt.Errorf("jira connection with name %s already exists", jiraConnection.Name)
- }
- return err
- }
- // perform optional operation
- typeMappings := data["typeMappings"]
- if typeMappings != nil {
- err = saveTypeMappings(tx, jiraConnection.ID, typeMappings)
- if err != nil {
- return err
- }
- }
-
- jiraConnection.BasicAuthEncoded, err = core.Decrypt(encKey, jiraConnection.BasicAuthEncoded)
- if err != nil {
- log.Error("failed to decrypt basic auth: %s", err)
- }
- return nil
-}
-
/*
POST /plugins/jira/connections
{
@@ -230,7 +123,7 @@ func PostConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, err
jiraConnection := &models.JiraConnection{}
// update from request and save to database
- err := refreshAndSaveJiraConnection(jiraConnection, input.Body)
+ err := helper.RefreshAndSaveConnection(jiraConnection, input.Body, db)
if err != nil {
return nil, err
}
@@ -259,14 +152,15 @@ PATCH /plugins/jira/connections/:connectionId
}
*/
func PatchConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
+ jiraConnection := &models.JiraConnection{}
// load from db
- jiraConnection, err := findConnectionByInputParam(input)
+ err := helper.FindConnectionByInput(input, jiraConnection, db)
if err != nil {
return nil, err
}
// update from request and save to database
- err = refreshAndSaveJiraConnection(jiraConnection, input.Body)
+ err = helper.RefreshAndSaveConnection(jiraConnection, input.Body, db)
if err != nil {
return nil, err
}
@@ -279,7 +173,7 @@ DELETE /plugins/jira/connections/:connectionId
*/
func DeleteConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
// load from db
- jiraConnectionID, err := getJiraConnectionIdByInputParam(input)
+ jiraConnectionID, err := helper.GetConnectionIdByInputParam(input)
if err != nil {
return nil, err
}
@@ -304,22 +198,19 @@ func DeleteConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, er
GET /plugins/jira/connections
*/
func ListConnections(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraConnections := make([]models.JiraConnection, 0)
+ jiraConnections := make([]*models.JiraConnection, 0)
err := db.Find(&jiraConnections).Error
if err != nil {
return nil, err
}
- encKey, err := getEncKey()
- if err != nil {
- return nil, err
- }
- for i := range jiraConnections {
- jiraConnections[i].BasicAuthEncoded, err = core.Decrypt(encKey, jiraConnections[i].BasicAuthEncoded)
+ for i, _ := range jiraConnections {
+ err = helper.DecryptConnection(jiraConnections[i], "Password")
if err != nil {
- log.Error("failed to decrypt basic auth: %s", err)
+ return nil, err
}
}
- return &core.ApiResourceOutput{Body: jiraConnections}, nil
+
+ return &core.ApiResourceOutput{Body: jiraConnections, Status: http.StatusOK}, nil
}
/*
@@ -345,53 +236,27 @@ GET /plugins/jira/connections/:connectionId
}
*/
func GetConnection(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraConnection, err := findConnectionByInputParam(input)
+ jiraConnection := &models.JiraConnection{}
+ err := helper.FindConnectionByInput(input, jiraConnection, db)
if err != nil {
return nil, err
}
detail := &models.JiraConnectionDetail{
JiraConnection: *jiraConnection,
- TypeMappings: make(map[string]map[string]interface{}),
}
- typeMappings, err := findIssueTypeMappingByConnectionId(jiraConnection.ID)
if err != nil {
return nil, err
}
- for _, jiraTypeMapping := range typeMappings {
- // type mapping
- typeMappingDict := map[string]interface{}{
- "standardType": jiraTypeMapping.StandardType,
- }
- detail.TypeMappings[jiraTypeMapping.UserType] = typeMappingDict
-
- // status mapping
- statusMappings, err := findIssueStatusMappingByConnectionIdAndUserType(
- jiraConnection.ID,
- jiraTypeMapping.UserType,
- )
- if err != nil {
- return nil, err
- }
- if len(statusMappings) == 0 {
- continue
- }
- statusMappingsDict := make(map[string]interface{})
- for _, jiraStatusMapping := range statusMappings {
- statusMappingsDict[jiraStatusMapping.UserStatus] = map[string]interface{}{
- "standardStatus": jiraStatusMapping.StandardStatus,
- }
- }
- typeMappingDict["statusMappings"] = statusMappingsDict
- }
return &core.ApiResourceOutput{Body: detail}, nil
}
// GET /plugins/jira/connections/:connectionId/epics
func GetEpicsByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraConnection, err := findConnectionByInputParam(input)
+ jiraConnection := &models.JiraConnection{}
+ err := helper.FindConnectionByInput(input, jiraConnection, db)
if err != nil {
return nil, err
}
@@ -410,7 +275,11 @@ type GranularitiesResponse struct {
}
func GetGranularitiesByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraConnection, err := findConnectionByInputParam(input)
+ jiraConnection := &models.JiraConnection{}
+ err := helper.FindConnectionByInput(input, jiraConnection, db)
+ if err != nil {
+ return nil, err
+ }
if err != nil {
return nil, err
}
@@ -448,19 +317,3 @@ func GetBoardsByConnectionId(input *core.ApiResourceInput) (*core.ApiResourceOut
}
return &core.ApiResourceOutput{Body: boardResponses}, nil
}
-
-func getEncKey() (string, error) {
- // encrypt
- v := config.GetConfig()
- encKey := v.GetString(core.EncodeKeyEnvStr)
- if encKey == "" {
- // Randomly generate a bunch of encryption keys and set them to config
- encKey = core.RandomEncKey()
- v.Set(core.EncodeKeyEnvStr, encKey)
- err := config.WriteConfig(v)
- if err != nil {
- return encKey, err
- }
- }
- return encKey, nil
-}
diff --git a/plugins/jira/api/issue_status_mapping.go b/plugins/jira/api/issue_status_mapping.go
deleted file mode 100644
index 9caa90b3..00000000
--- a/plugins/jira/api/issue_status_mapping.go
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements. See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package api
-
-import (
- "fmt"
- "net/http"
-
- "github.com/apache/incubator-devlake/models/common"
-
- "github.com/apache/incubator-devlake/plugins/core"
- "github.com/apache/incubator-devlake/plugins/jira/models"
- "github.com/go-playground/validator/v10"
- "github.com/mitchellh/mapstructure"
- "gorm.io/gorm"
-)
-
-func findIssueStatusMappingFromInput(input *core.ApiResourceInput) (*models.JiraIssueStatusMapping, error) {
- // load type mapping
- jiraIssueTypeMapping, err := findIssueTypeMappingByInputParam(input)
- if err != nil {
- return nil, err
- }
- // load status mapping from db
- userStatus := input.Params["userStatus"]
- if userStatus == "" {
- return nil, fmt.Errorf("missing userStatus")
- }
- jiraIssueStatusMapping := &models.JiraIssueStatusMapping{}
- err = db.First(
- jiraIssueStatusMapping,
- jiraIssueTypeMapping.ConnectionID,
- jiraIssueTypeMapping.UserType,
- userStatus,
- ).Error
- if err != nil {
- return nil, err
- }
-
- return jiraIssueStatusMapping, nil
-}
-
-func mergeFieldsToJiraStatusMapping(
- jiraIssueStatusMapping *models.JiraIssueStatusMapping,
- connections ...map[string]interface{},
-) error {
- // merge fields from connections to jiraIssueStatusMapping
- for _, connection := range connections {
- err := mapstructure.Decode(connection, jiraIssueStatusMapping)
- if err != nil {
- return err
- }
- }
- // validate
- vld := validator.New()
- err := vld.Struct(jiraIssueStatusMapping)
- if err != nil {
- return err
- }
- return nil
-}
-
-func wrapIssueStatusDuplicateErr(err error) error {
- if common.IsDuplicateError(err) {
- return fmt.Errorf("jira issue status mapping already exists")
- }
- return err
-}
-
-func saveStatusMappings(tx *gorm.DB, jiraConnectionId uint64, userType string, statusMappings interface{}) error {
- statusMappingsMap, ok := statusMappings.(map[string]interface{})
- if !ok {
- return fmt.Errorf("statusMappings is not a JSON object: %v", statusMappings)
- }
- err := tx.Where(
- "connection_id = ? AND user_type = ?",
- jiraConnectionId,
- userType).Delete(&models.JiraIssueStatusMapping{}).Error
- if err != nil {
- return err
- }
- for userStatus, statusMapping := range statusMappingsMap {
- statusMappingMap, ok := statusMapping.(map[string]interface{})
- if !ok {
- return fmt.Errorf("statusMapping is not a JSON object: %v", statusMappings)
- }
- jiraIssueStatusMapping := &models.JiraIssueStatusMapping{}
- err = mergeFieldsToJiraStatusMapping(jiraIssueStatusMapping, statusMappingMap, map[string]interface{}{
- "ConnectionID": jiraConnectionId,
- "UserType": userType,
- "UserStatus": userStatus,
- })
- if err != nil {
- return err
- }
- err = tx.Create(jiraIssueStatusMapping).Error
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func findIssueStatusMappingByConnectionIdAndUserType(
- jiraConnectionId uint64,
- userType string,
-) ([]*models.JiraIssueStatusMapping, error) {
- jiraIssueStatusMappings := make([]*models.JiraIssueStatusMapping, 0)
- err := db.Where(
- "connection_id = ? AND user_type = ?",
- jiraConnectionId,
- userType,
- ).Find(&jiraIssueStatusMappings).Error
- return jiraIssueStatusMappings, err
-}
-
-/*
-POST /plugins/jira/connections/:connectionId/type-mappings/:userType/status-mappings
-{
- "userStatus": "user custom status",
- "standardStatus": "devlake standard status"
-}
-*/
-func PostIssueStatusMappings(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraIssueTypeMapping, err := findIssueTypeMappingByInputParam(input)
- if err != nil {
- return nil, err
- }
- jiraIssueStatusMapping := &models.JiraIssueStatusMapping{}
- err = mergeFieldsToJiraStatusMapping(jiraIssueStatusMapping, input.Body, map[string]interface{}{
- "ConnectionID": jiraIssueTypeMapping.ConnectionID,
- "UserType": jiraIssueTypeMapping.UserType,
- })
- if err != nil {
- return nil, err
- }
- // save
- err = wrapIssueStatusDuplicateErr(db.Create(jiraIssueStatusMapping).Error)
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueStatusMapping, Status: http.StatusOK}, nil
-}
-
-/*
-PUT /plugins/jira/connections/:connectionId/type-mappings/:userType/status-mappings/:userStatus
-{
- "standardStatus": "devlake standard status"
-}
-*/
-func PutIssueStatusMapping(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- // load from db
- jiraIssueStatusMapping, err := findIssueStatusMappingFromInput(input)
- if err != nil {
- return nil, err
- }
- // update with request body
- err = mergeFieldsToJiraStatusMapping(jiraIssueStatusMapping, input.Body)
- if err != nil {
- return nil, err
- }
- // save
- err = wrapIssueStatusDuplicateErr(db.Save(jiraIssueStatusMapping).Error)
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueStatusMapping}, nil
-}
-
-/*
-DELETE /plugins/jira/connections/:connectionId/type-mappings/:userType/status-mappings/:userStatus
-*/
-func DeleteIssueStatusMapping(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraIssueStatusMapping, err := findIssueStatusMappingFromInput(input)
- if err != nil {
- return nil, err
- }
- err = db.Delete(jiraIssueStatusMapping).Error
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueStatusMapping}, nil
-}
-
-/*
-GET /plugins/jira/connections/:connectionId/type-mappings/:userType/status-mappings
-*/
-func ListIssueStatusMappings(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraIssueTypeMapping, err := findIssueTypeMappingByInputParam(input)
- if err != nil {
- return nil, err
- }
- jiraIssueStatusMappings, err := findIssueStatusMappingByConnectionIdAndUserType(
- jiraIssueTypeMapping.ConnectionID,
- jiraIssueTypeMapping.UserType,
- )
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueStatusMappings}, nil
-}
diff --git a/plugins/jira/api/issue_type_mapping.go b/plugins/jira/api/issue_type_mapping.go
deleted file mode 100644
index 7f135646..00000000
--- a/plugins/jira/api/issue_type_mapping.go
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements. See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to You under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package api
-
-import (
- "fmt"
- "net/http"
-
- "github.com/apache/incubator-devlake/models/common"
-
- "github.com/apache/incubator-devlake/plugins/core"
- "github.com/apache/incubator-devlake/plugins/jira/models"
- "github.com/go-playground/validator/v10"
- "github.com/mitchellh/mapstructure"
- "gorm.io/gorm"
-)
-
-func findIssueTypeMappingByInputParam(input *core.ApiResourceInput) (*models.JiraIssueTypeMapping, error) {
- // load jira connection
- jiraConnection, err := findConnectionByInputParam(input)
- if err != nil {
- return nil, err
- }
- // load jira type mapping from db
- userType := input.Params["userType"]
- if userType == "" {
- return nil, fmt.Errorf("missing userType")
- }
- jiraIssueTypeMapping := &models.JiraIssueTypeMapping{}
- err = db.First(jiraIssueTypeMapping, jiraConnection.ID, userType).Error
- if err != nil {
- return nil, err
- }
-
- return jiraIssueTypeMapping, nil
-}
-
-func mergeFieldsToJiraTypeMapping(
- jiraIssueTypeMapping *models.JiraIssueTypeMapping,
- connections ...map[string]interface{},
-) error {
- // merge fields from connections to jiraIssueTypeMapping
- for _, connection := range connections {
- err := mapstructure.Decode(connection, jiraIssueTypeMapping)
- if err != nil {
- return err
- }
- }
- // validate
- vld := validator.New()
- err := vld.Struct(jiraIssueTypeMapping)
- if err != nil {
- return err
- }
- return nil
-}
-
-func wrapIssueTypeDuplicateErr(err error) error {
- if common.IsDuplicateError(err) {
- return fmt.Errorf("jira issue type mapping already exists")
- }
- return err
-}
-
-func saveTypeMappings(tx *gorm.DB, jiraConnectionId uint64, typeMappings interface{}) error {
- typeMappingsMap, ok := typeMappings.(map[string]interface{})
- if !ok {
- return fmt.Errorf("typeMappings is not a JSON object: %v", typeMappings)
- }
- err := tx.Where("connection_id = ?", jiraConnectionId).Delete(&models.JiraIssueTypeMapping{}).Error
- if err != nil {
- return err
- }
- for userType, typeMapping := range typeMappingsMap {
- typeMappingMap, ok := typeMapping.(map[string]interface{})
- if !ok {
- return fmt.Errorf("typeMapping is not a JSON object: %v", typeMapping)
- }
- jiraIssueTypeMapping := &models.JiraIssueTypeMapping{}
- err = mergeFieldsToJiraTypeMapping(jiraIssueTypeMapping, typeMappingMap, map[string]interface{}{
- "ConnectionID": jiraConnectionId,
- "UserType": userType,
- })
- if err != nil {
- return err
- }
- err = wrapIssueTypeDuplicateErr(tx.Create(jiraIssueTypeMapping).Error)
- if err != nil {
- return err
- }
-
- statusMappings := typeMappingMap["statusMappings"]
- if statusMappings != nil {
- err = saveStatusMappings(tx, jiraConnectionId, userType, statusMappings)
- if err != nil {
- return err
- }
- }
- }
- return nil
-}
-
-func findIssueTypeMappingByConnectionId(jiraConnectionId uint64) ([]*models.JiraIssueTypeMapping, error) {
- jiraIssueTypeMappings := make([]*models.JiraIssueTypeMapping, 0)
- err := db.Where("connection_id = ?", jiraConnectionId).Find(&jiraIssueTypeMappings).Error
- if err != nil {
- return nil, err
- }
- return jiraIssueTypeMappings, nil
-}
-
-/*
-POST /plugins/jira/connections/:connectionId/type-mappings
-{
- "userType": "user custom type",
- "standardType": "devlake standard type"
-}
-*/
-func PostIssueTypeMappings(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- // create new
- jiraConnection, err := findConnectionByInputParam(input)
- if err != nil {
- return nil, err
- }
- jiraIssueTypeMapping := &models.JiraIssueTypeMapping{}
- err = mergeFieldsToJiraTypeMapping(jiraIssueTypeMapping, input.Body, map[string]interface{}{
- "ConnectionID": jiraConnection.ID,
- })
- if err != nil {
- return nil, err
- }
- // save
- err = wrapIssueTypeDuplicateErr(db.Create(jiraIssueTypeMapping).Error)
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueTypeMapping, Status: http.StatusOK}, nil
-}
-
-/*
-PUT /plugins/jira/connections/:connectionId/type-mappings/:userType
-{
- "standardType": "devlake standard type"
-}
-*/
-func PutIssueTypeMapping(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- // load from db
- jiraIssueTypeMapping, err := findIssueTypeMappingByInputParam(input)
- if err != nil {
- return nil, err
- }
- // update with request body
- err = mergeFieldsToJiraTypeMapping(jiraIssueTypeMapping, input.Body)
- if err != nil {
- return nil, err
- }
- // save
- err = wrapIssueTypeDuplicateErr(db.Save(jiraIssueTypeMapping).Error)
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueTypeMapping}, nil
-}
-
-/*
-DELETE /plugins/jira/connections/:connectionId/type-mappings/:userType
-*/
-func DeleteIssueTypeMapping(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- // load from db
- jiraIssueTypeMapping, err := findIssueTypeMappingByInputParam(input)
- if err != nil {
- return nil, err
- }
- err = db.Delete(jiraIssueTypeMapping).Error
- if err != nil {
- return nil, err
- }
- err = db.Where(
- "connection_id = ? AND user_type = ?",
- jiraIssueTypeMapping.ConnectionID,
- jiraIssueTypeMapping.UserType,
- ).Delete(&models.JiraIssueStatusMapping{}).Error
- if err != nil {
- return nil, err
- }
- return &core.ApiResourceOutput{Body: jiraIssueTypeMapping}, nil
-}
-
-/*
-GET /plugins/jira/connections/:connectionId/type-mappings
-*/
-func ListIssueTypeMappings(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- jiraConnection, err := findConnectionByInputParam(input)
- if err != nil {
- return nil, err
- }
- jiraIssueTypeMappings, err := findIssueTypeMappingByConnectionId(jiraConnection.ID)
- return &core.ApiResourceOutput{Body: jiraIssueTypeMappings}, err
-}
diff --git a/plugins/jira/api/proxy.go b/plugins/jira/api/proxy.go
index 55331e01..e4a3eb90 100644
--- a/plugins/jira/api/proxy.go
+++ b/plugins/jira/api/proxy.go
@@ -20,8 +20,8 @@ package api
import (
"encoding/json"
"fmt"
+ "github.com/apache/incubator-devlake/utils"
"io/ioutil"
- "strconv"
"time"
"github.com/apache/incubator-devlake/plugins/core"
@@ -34,21 +34,13 @@ const (
)
func Proxy(input *core.ApiResourceInput) (*core.ApiResourceOutput, error) {
- connectionId := input.Params["connectionId"]
- if connectionId == "" {
- return nil, fmt.Errorf("missing connectionid")
- }
- jiraConnectionId, err := strconv.ParseUint(connectionId, 10, 64)
- if err != nil {
- return nil, err
- }
jiraConnection := &models.JiraConnection{}
- err = db.First(jiraConnection, jiraConnectionId).Error
+ err := helper.FindConnectionByInput(input, jiraConnection, db)
if err != nil {
return nil, err
}
- encKey := cfg.GetString(core.EncodeKeyEnvStr)
- basicAuth, err := core.Decrypt(encKey, jiraConnection.BasicAuthEncoded)
+ basicAuth := utils.GetEncodedToken(jiraConnection.Username, jiraConnection.Password)
+
if err != nil {
return nil, err
}
diff --git a/plugins/jira/jira.go b/plugins/jira/jira.go
index 2b865ea6..2a40b901 100644
--- a/plugins/jira/jira.go
+++ b/plugins/jira/jira.go
@@ -150,6 +150,7 @@ func (plugin Jira) MigrationScripts() []migration.Script {
new(migrationscripts.UpdateSchemas20220505),
new(migrationscripts.UpdateSchemas20220507),
new(migrationscripts.UpdateSchemas20220518),
+ new(migrationscripts.UpdateSchemas20220524),
new(migrationscripts.UpdateSchemas20220525),
new(migrationscripts.UpdateSchemas20220526),
new(migrationscripts.UpdateSchemas20220527),
@@ -184,22 +185,6 @@ func (plugin Jira) ApiResources() map[string]map[string]core.ApiResourceHandler
"connections/:connectionId/boards": {
"GET": api.GetBoardsByConnectionId,
},
- "connections/:connectionId/type-mappings": {
- "POST": api.PostIssueTypeMappings,
- "GET": api.ListIssueTypeMappings,
- },
- "connections/:connectionId/type-mappings/:userType": {
- "PUT": api.PutIssueTypeMapping,
- "DELETE": api.DeleteIssueTypeMapping,
- },
- "connections/:connectionId/type-mappings/:userType/status-mappings": {
- "POST": api.PostIssueStatusMappings,
- "GET": api.ListIssueStatusMappings,
- },
- "connections/:connectionId/type-mappings/:userType/status-mappings/:userStatus": {
- "PUT": api.PutIssueStatusMapping,
- "DELETE": api.DeleteIssueStatusMapping,
- },
"connections/:connectionId/proxy/rest/*path": {
"GET": api.Proxy,
},
diff --git a/plugins/jira/models/connection.go b/plugins/jira/models/connection.go
index edb6b88f..f1ed2f8a 100644
--- a/plugins/jira/models/connection.go
+++ b/plugins/jira/models/connection.go
@@ -18,7 +18,7 @@ limitations under the License.
package models
import (
- "github.com/apache/incubator-devlake/models/common"
+ "github.com/apache/incubator-devlake/plugins/helper"
)
type EpicResponse struct {
@@ -28,9 +28,9 @@ type EpicResponse struct {
}
type TestConnectionRequest struct {
- Endpoint string `json:"endpoint"`
- Auth string `json:"auth"`
- Proxy string `json:"proxy"`
+ Endpoint string `json:"endpoint"`
+ Proxy string `json:"proxy"`
+ helper.BasicAuth `mapstructure:",squash"`
}
type BoardResponse struct {
@@ -40,15 +40,11 @@ type BoardResponse struct {
}
type JiraConnection struct {
- common.Model
- Name string `gorm:"type:varchar(100);uniqueIndex" json:"name" validate:"required"`
- Endpoint string `json:"endpoint" validate:"required"`
- BasicAuthEncoded string `json:"basicAuthEncoded" validate:"required"`
+ helper.RestConnection `mapstructure:",squash"`
+ helper.BasicAuth `mapstructure:",squash"`
EpicKeyField string `gorm:"type:varchar(50);" json:"epicKeyField"`
StoryPointField string `gorm:"type:varchar(50);" json:"storyPointField"`
RemotelinkCommitShaPattern string `gorm:"type:varchar(255);comment='golang regexp, the first group will be recognized as commit sha, ref https://github.com/google/re2/wiki/Syntax'" json:"remotelinkCommitShaPattern"`
- Proxy string `json:"proxy"`
- RateLimit int `comment:"api request rate limt per hour" json:"rateLimit"`
}
type JiraIssueTypeMapping struct {
diff --git a/plugins/jira/models/migrationscripts/updateSchemas20220505.go b/plugins/jira/models/migrationscripts/updateSchemas20220505.go
index 8e0e1610..ff4a6c81 100644
--- a/plugins/jira/models/migrationscripts/updateSchemas20220505.go
+++ b/plugins/jira/models/migrationscripts/updateSchemas20220505.go
@@ -19,16 +19,32 @@ package migrationscripts
import (
"context"
- "github.com/apache/incubator-devlake/plugins/jira/models"
+ "github.com/apache/incubator-devlake/models/common"
"github.com/apache/incubator-devlake/plugins/jira/models/migrationscripts/archived"
"gorm.io/gorm"
)
+type JiraConnection20220505 struct {
+ common.Model
+ Name string `gorm:"type:varchar(100);uniqueIndex" json:"name" validate:"required"`
+ Endpoint string `json:"endpoint" validate:"required"`
+ BasicAuthEncoded string `json:"basicAuthEncoded" validate:"required"`
+ EpicKeyField string `gorm:"type:varchar(50);" json:"epicKeyField"`
+ StoryPointField string `gorm:"type:varchar(50);" json:"storyPointField"`
+ RemotelinkCommitShaPattern string `gorm:"type:varchar(255);comment='golang regexp, the first group will be recognized as commit sha, ref https://github.com/google/re2/wiki/Syntax'" json:"remotelinkCommitShaPattern"`
+ Proxy string `json:"proxy"`
+ RateLimit int `comment:"api request rate limt per hour" json:"rateLimit"`
+}
+
+func (JiraConnection20220505) TableName() string {
+ return "_tool_jira_connections"
+}
+
type UpdateSchemas20220505 struct{}
func (*UpdateSchemas20220505) Up(ctx context.Context, db *gorm.DB) error {
- err := db.Migrator().RenameTable(archived.JiraSource{}, models.JiraConnection{})
+ err := db.Migrator().RenameTable(archived.JiraSource{}, JiraConnection20220505{})
if err != nil {
return err
}
diff --git a/plugins/jira/models/migrationscripts/updateSchemas20220524.go b/plugins/jira/models/migrationscripts/updateSchemas20220524.go
new file mode 100644
index 00000000..9c753610
--- /dev/null
+++ b/plugins/jira/models/migrationscripts/updateSchemas20220524.go
@@ -0,0 +1,72 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package migrationscripts
+
+import (
+ "context"
+ "github.com/apache/incubator-devlake/plugins/helper"
+ "gorm.io/gorm"
+)
+
+type JiraConnection20220524 struct {
+ helper.RestConnection
+ helper.BasicAuth
+ EpicKeyField string `gorm:"type:varchar(50);" json:"epicKeyField"`
+ StoryPointField string `gorm:"type:varchar(50);" json:"storyPointField"`
+ RemotelinkCommitShaPattern string `gorm:"type:varchar(255);comment='golang regexp, the first group will be recognized as commit sha, ref https://github.com/google/re2/wiki/Syntax'" json:"remotelinkCommitShaPattern"`
+}
+
+func (JiraConnection20220524) TableName() string {
+ return "_tool_jira_connections"
+}
+
+type UpdateSchemas20220524 struct{}
+
+func (*UpdateSchemas20220524) Up(ctx context.Context, db *gorm.DB) error {
+ var err error
+ if !db.Migrator().HasColumn(&JiraConnection20220505{}, "password") {
+ err = db.Migrator().AddColumn(&JiraConnection20220524{}, "password")
+ if err != nil {
+ return err
+ }
+ }
+
+ if !db.Migrator().HasColumn(&JiraConnection20220505{}, "username") {
+ err = db.Migrator().AddColumn(&JiraConnection20220524{}, "username")
+ if err != nil {
+ return err
+ }
+ }
+
+ if db.Migrator().HasColumn(&JiraConnection20220505{}, "basic_auth_encoded") {
+ err = db.Migrator().DropColumn(&JiraConnection20220505{}, "basic_auth_encoded")
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (*UpdateSchemas20220524) Version() uint64 {
+ return 20220507154646
+}
+
+func (*UpdateSchemas20220524) Name() string {
+ return "Add icon_url column to JiraIssue"
+}
diff --git a/plugins/jira/tasks/api_client.go b/plugins/jira/tasks/api_client.go
index 4896c05a..3673bee5 100644
--- a/plugins/jira/tasks/api_client.go
+++ b/plugins/jira/tasks/api_client.go
@@ -29,10 +29,12 @@ import (
func NewJiraApiClient(taskCtx core.TaskContext, connection *models.JiraConnection) (*helper.ApiAsyncClient, error) {
// load configuration
encKey := taskCtx.GetConfig(core.EncodeKeyEnvStr)
- auth, err := core.Decrypt(encKey, connection.BasicAuthEncoded)
+ decodedPassword, err := core.Decrypt(encKey, connection.Password)
if err != nil {
- return nil, fmt.Errorf("Failed to decrypt Auth Token: %w", err)
+ return nil, fmt.Errorf("Failed to decrypt Auth AccessToken: %w", err)
}
+ connection.Password = decodedPassword
+ auth := connection.GetEncodedToken()
// create synchronize api client so we can calculate api rate limit dynamically
headers := map[string]string{
@@ -44,7 +46,7 @@ func NewJiraApiClient(taskCtx core.TaskContext, connection *models.JiraConnectio
}
apiClient.SetAfterFunction(func(res *http.Response) error {
if res.StatusCode == http.StatusUnauthorized {
- return fmt.Errorf("authentication failed, please check your Basic Auth Token")
+ return fmt.Errorf("authentication failed, please check your AccessToken")
}
return nil
})
diff --git a/plugins/tapd/tasks/api_client.go b/plugins/tapd/tasks/api_client.go
index 406bc97a..977d076f 100644
--- a/plugins/tapd/tasks/api_client.go
+++ b/plugins/tapd/tasks/api_client.go
@@ -31,7 +31,7 @@ func NewTapdApiClient(taskCtx core.TaskContext, connection *models.TapdConnectio
encKey := taskCtx.GetConfig(core.EncodeKeyEnvStr)
auth, err := core.Decrypt(encKey, connection.BasicAuthEncoded)
if err != nil {
- return nil, fmt.Errorf("Failed to decrypt Auth Token: %w", err)
+ return nil, fmt.Errorf("Failed to decrypt Auth AccessToken: %w", err)
}
// create synchronize api client so we can calculate api rate limit dynamically
@@ -44,7 +44,7 @@ func NewTapdApiClient(taskCtx core.TaskContext, connection *models.TapdConnectio
}
apiClient.SetAfterFunction(func(res *http.Response) error {
if res.StatusCode == http.StatusUnprocessableEntity {
- return fmt.Errorf("authentication failed, please check your Basic Auth Token")
+ return fmt.Errorf("authentication failed, please check your AccessToken")
}
return nil
})