This is an automated email from the ASF dual-hosted git repository.

likyh 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 3f7b47f7a refactor(framework): modify gitlab (#4660)
3f7b47f7a is described below

commit 3f7b47f7a50e40810cf8701d17e6671aa7af3f20
Author: Warren Chen <[email protected]>
AuthorDate: Tue Mar 14 20:48:57 2023 +0800

    refactor(framework): modify gitlab (#4660)
---
 backend/helpers/pluginhelper/api/scope_helper.go   | 93 ++++++++++++++++++----
 .../helpers/pluginhelper/api/scope_helper_test.go  | 57 +++++++++++--
 backend/plugins/github/api/scope.go                | 41 ++++------
 backend/plugins/github/models/repo.go              |  2 +-
 backend/plugins/gitlab/api/remote.go               |  6 ++
 backend/plugins/gitlab/api/scope.go                | 83 ++-----------------
 backend/plugins/gitlab/models/project.go           |  6 +-
 7 files changed, 158 insertions(+), 130 deletions(-)

diff --git a/backend/helpers/pluginhelper/api/scope_helper.go 
b/backend/helpers/pluginhelper/api/scope_helper.go
index 962002a69..04244290e 100644
--- a/backend/helpers/pluginhelper/api/scope_helper.go
+++ b/backend/helpers/pluginhelper/api/scope_helper.go
@@ -18,6 +18,7 @@ limitations under the License.
 package api
 
 import (
+       "encoding/json"
        "fmt"
        "github.com/apache/incubator-devlake/core/context"
        "github.com/apache/incubator-devlake/core/dal"
@@ -27,6 +28,7 @@ import (
        "github.com/go-playground/validator/v10"
        "github.com/mitchellh/mapstructure"
        "gorm.io/gorm"
+       "net/http"
        "strconv"
        "strings"
        "time"
@@ -63,7 +65,7 @@ func NewScopeHelper[Conn any, Scope any, Tr any](
 }
 
 type ScopeRes[T any] struct {
-       Scope                  T
+       Scope                  T      `mapstructure:",squash"`
        TransformationRuleName string `json:"transformationRuleName,omitempty"`
 }
 
@@ -74,7 +76,7 @@ type ScopeReq[T any] struct {
 // Put saves the given scopes to the database. It expects a slice of struct 
pointers
 // as the scopes argument. It also expects a fieldName argument, which is used 
to extract
 // the connection ID from the input.Params map.
-func (c *ScopeApiHelper[Conn, Scope, Tr]) Put(input *plugin.ApiResourceInput) 
([]*Scope, errors.Error) {
+func (c *ScopeApiHelper[Conn, Scope, Tr]) Put(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, errors.Error) {
        var req struct {
                Data []*Scope `json:"data"`
        }
@@ -114,43 +116,47 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) Put(input 
*plugin.ApiResourceInput) ([
                        return nil, err
                }
        }
+       err = c.save(&req.Data)
+       if err != nil {
+               return nil, err
+       }
 
        // Save the scopes to the database
-       return req.Data, c.save(&req.Data)
+       return &plugin.ApiResourceOutput{Body: req.Data, Status: 
http.StatusOK}, nil
 }
 
-func (c *ScopeApiHelper[Conn, Scope, Tr]) Update(input 
*plugin.ApiResourceInput, fieldName string) (*Scope, errors.Error) {
+func (c *ScopeApiHelper[Conn, Scope, Tr]) Update(input 
*plugin.ApiResourceInput, fieldName string) (*plugin.ApiResourceOutput, 
errors.Error) {
        connectionId, scopeId := extractFromReqParam(input.Params)
 
        if connectionId == 0 || len(scopeId) == 0 || scopeId == "0" {
-               return nil, errors.BadInput.New("invalid connectionId")
+               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, errors.BadInput.New("invalid connectionId")
        }
        err := c.VerifyConnection(connectionId)
        if err != nil {
-               return nil, err
+               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, err
        }
        var scope Scope
        err = c.db.First(&scope, dal.Where(fmt.Sprintf("connection_id = ? AND 
%s = ?", fieldName), connectionId, scopeId))
        if err != nil {
-               return nil, errors.Default.New("getting Scope error")
+               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, errors.Default.New("getting Scope error")
        }
        err = DecodeMapStruct(input.Body, &scope)
        if err != nil {
-               return nil, errors.Default.Wrap(err, "patch scope error")
+               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, errors.Default.Wrap(err, "patch scope error")
        }
        err = VerifyScope(&scope, c.validator)
        if err != nil {
-               return nil, errors.Default.Wrap(err, "Invalid scope")
+               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, errors.Default.Wrap(err, "Invalid scope")
        }
 
        err = c.db.Update(scope)
        if err != nil {
-               return nil, errors.Default.Wrap(err, "error on saving Scope")
+               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, errors.Default.Wrap(err, "error on saving 
Scope")
        }
-       return &scope, nil
+       return &plugin.ApiResourceOutput{Body: &scope, Status: http.StatusOK}, 
nil
 }
 
-func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScopeList(input 
*plugin.ApiResourceInput) ([]ScopeRes[Scope], errors.Error) {
+func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScopeList(input 
*plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
        connectionId, _ := extractFromReqParam(input.Params)
        if connectionId == 0 {
                return nil, errors.BadInput.New("invalid path params")
@@ -187,12 +193,12 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) 
GetScopeList(input *plugin.ApiResource
        }
        apiScopes := make([]ScopeRes[Scope], 0)
        for _, scope := range scopes {
-               apiScopes = append(apiScopes, ScopeRes[Scope]{Scope: *scope, 
TransformationRuleName: 
names[reflect.ValueOf(scope).Elem().FieldByName("TransformationRuleId").Uint()]})
+               apiScopes = append(apiScopes, ScopeRes[Scope]{*scope, 
names[reflect.ValueOf(scope).Elem().FieldByName("TransformationRuleId").Uint()]})
        }
-       return apiScopes, nil
+       return &plugin.ApiResourceOutput{Body: apiScopes, Status: 
http.StatusOK}, nil
 }
 
-func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScope(input 
*plugin.ApiResourceInput, fieldName string) (*ScopeRes[Scope], errors.Error) {
+func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScope(input 
*plugin.ApiResourceInput, fieldName string) (*plugin.ApiResourceOutput, 
errors.Error) {
        connectionId, scopeId := extractFromReqParam(input.Params)
        if connectionId == 0 || len(scopeId) == 0 || scopeId == "0" {
                return nil, errors.BadInput.New("invalid path params")
@@ -219,7 +225,8 @@ func (c *ScopeApiHelper[Conn, Scope, Tr]) GetScope(input 
*plugin.ApiResourceInpu
                        return nil, errors.NotFound.New("transformationRule not 
found")
                }
        }
-       return &ScopeRes[Scope]{Scope: scope, TransformationRuleName: 
reflect.ValueOf(rule).FieldByName("Name").String()}, nil
+       scopeRes := &ScopeRes[Scope]{scope, 
reflect.ValueOf(rule).FieldByName("Name").String()}
+       return &plugin.ApiResourceOutput{Body: scopeRes, Status: 
http.StatusOK}, nil
 }
 
 func (c *ScopeApiHelper[Conn, Scope, Tr]) VerifyConnection(connId uint64) 
errors.Error {
@@ -322,3 +329,57 @@ func VerifyScope(scope interface{}, vld 
*validator.Validate) errors.Error {
        }
        return nil
 }
+
+// Implement MarshalJSON method to flatten all fields
+func (sr ScopeRes[T]) MarshalJSON() ([]byte, error) {
+       // Create an empty map to store flattened fields and values
+       flatMap, err := flattenStruct(sr)
+       if err != nil {
+               return nil, err
+       }
+       // Encode the flattened map to JSON
+       result, err := json.Marshal(flatMap)
+       if err != nil {
+               return nil, err
+       }
+
+       return result, nil
+}
+
+// A helper function to flatten nested structs
+func flattenStruct(s interface{}) (map[string]interface{}, error) {
+       flatMap := make(map[string]interface{})
+
+       // Use reflection to get all fields of the nested struct type
+       fields := reflect.TypeOf(s).NumField()
+
+       // Traverse all fields of the nested struct and add them to flatMap
+       for i := 0; i < fields; i++ {
+               field := reflect.TypeOf(s).Field(i)
+               fieldValue := reflect.ValueOf(s).Field(i)
+               if strings.Contains(field.Tag.Get("swaggerignore"), "true") {
+                       continue
+               }
+               if fieldValue.IsZero() && 
strings.Contains(field.Tag.Get("json"), "omitempty") {
+                       continue
+               }
+               // If the field is a nested struct, recursively flatten its 
fields
+               if field.Type.Kind() == reflect.Struct && 
strings.Contains(field.Tag.Get("mapstructure"), "squash") {
+                       nestedFields, err := 
flattenStruct(fieldValue.Interface())
+                       if err != nil {
+                               return nil, err
+                       }
+                       for k, v := range nestedFields {
+                               flatMap[lowerCaseFirst(k)] = v
+                       }
+               } else {
+                       // If the field is not a nested struct, add its name 
and value to flatMap
+                       flatMap[lowerCaseFirst(field.Name)] = 
fieldValue.Interface()
+               }
+       }
+       return flatMap, nil
+}
+
+func lowerCaseFirst(name string) string {
+       return strings.ToLower(string(name[0])) + name[1:]
+}
diff --git a/backend/helpers/pluginhelper/api/scope_helper_test.go 
b/backend/helpers/pluginhelper/api/scope_helper_test.go
index a0e0e9afe..cc0657eea 100644
--- a/backend/helpers/pluginhelper/api/scope_helper_test.go
+++ b/backend/helpers/pluginhelper/api/scope_helper_test.go
@@ -38,7 +38,7 @@ type TestModel struct {
        Name string `gorm:"primaryKey;type:BIGINT  NOT NULL"`
 }
 
-type GithubRepo struct {
+type TestRepo struct {
        ConnectionId         uint64     `json:"connectionId" gorm:"primaryKey" 
mapstructure:"connectionId,omitempty"`
        GithubId             int        `json:"githubId" gorm:"primaryKey" 
mapstructure:"githubId"`
        Name                 string     `json:"name" gorm:"type:varchar(255)" 
mapstructure:"name,omitempty"`
@@ -55,11 +55,11 @@ type GithubRepo struct {
        common.NoPKModel     `json:"-" mapstructure:"-"`
 }
 
-func (GithubRepo) TableName() string {
+func (TestRepo) TableName() string {
        return "_tool_github_repos"
 }
 
-type GithubConnection struct {
+type TestConnection struct {
        common.Model
        Name             string `gorm:"type:varchar(100);uniqueIndex" 
json:"name" validate:"required"`
        Endpoint         string `mapstructure:"endpoint" env:"GITHUB_ENDPOINT" 
validate:"required"`
@@ -68,7 +68,7 @@ type GithubConnection struct {
        Token            string `mapstructure:"token" env:"GITHUB_AUTH" 
validate:"required" encrypt:"yes"`
 }
 
-func (GithubConnection) TableName() string {
+func (TestConnection) TableName() string {
        return "_tool_github_connections"
 }
 
@@ -113,7 +113,7 @@ func TestVerifyScope(t *testing.T) {
        }
 }
 
-type GithubTransformationRule struct {
+type TestTransformationRule struct {
        common.Model         `mapstructure:"-"`
        Name                 string            `mapstructure:"name" json:"name" 
gorm:"type:varchar(255);index:idx_name_github,unique" validate:"required"`
        PrType               string            `mapstructure:"prType,omitempty" 
json:"prType" gorm:"type:varchar(255)"`
@@ -130,11 +130,11 @@ type GithubTransformationRule struct {
        Refdiff              datatypes.JSONMap 
`mapstructure:"refdiff,omitempty" json:"refdiff" swaggertype:"object" 
format:"json"`
 }
 
-func (GithubTransformationRule) TableName() string {
+func (TestTransformationRule) TableName() string {
        return "_tool_github_transformation_rules"
 }
 
-func TestSetGitlabProjectFields(t *testing.T) {
+func TestSetScopeFields(t *testing.T) {
        // create a struct
        var p struct {
                ConnectionId uint64 `json:"connectionId" 
mapstructure:"connectionId" gorm:"primaryKey"`
@@ -286,8 +286,49 @@ func TestScopeApiHelper_Put(t *testing.T) {
                        }}}}
 
        // create a mock ScopeApiHelper with a mock database connection
-       apiHelper := &ScopeApiHelper[GithubConnection, GithubRepo, 
GithubTransformationRule]{db: mockDal, connHelper: connHelper}
+       apiHelper := &ScopeApiHelper[TestConnection, TestRepo, 
TestTransformationRule]{db: mockDal, connHelper: connHelper}
        // test a successful call to Put
        _, err := apiHelper.Put(input)
        assert.NoError(t, err)
 }
+
+func TestFlattenStruct(t *testing.T) {
+       type InnerStruct struct {
+               Foo int
+               Bar string
+       }
+
+       type OuterStruct struct {
+               Baz       bool
+               Qux       float64
+               Inner     InnerStruct `mapstructure:",squash"`
+               OtherProp string
+       }
+
+       input := OuterStruct{
+               Baz: true,
+               Qux: 3.14,
+               Inner: InnerStruct{
+                       Foo: 42,
+                       Bar: "hello",
+               },
+               OtherProp: "world",
+       }
+
+       expectedOutput := map[string]interface{}{
+               "baz":       true,
+               "qux":       3.14,
+               "foo":       42,
+               "bar":       "hello",
+               "otherProp": "world",
+       }
+
+       output, err := flattenStruct(input)
+       if err != nil {
+               t.Errorf("flattenStruct returned an error: %v", err)
+       }
+
+       if !reflect.DeepEqual(output, expectedOutput) {
+               t.Errorf("flattenStruct returned incorrect output.\nExpected: 
%v\nActual:   %v", expectedOutput, output)
+       }
+}
diff --git a/backend/plugins/github/api/scope.go 
b/backend/plugins/github/api/scope.go
index e4b2d4bfe..d9ba2499a 100644
--- a/backend/plugins/github/api/scope.go
+++ b/backend/plugins/github/api/scope.go
@@ -20,9 +20,14 @@ package api
 import (
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/plugin"
-       "net/http"
+       "github.com/apache/incubator-devlake/plugins/github/models"
 )
 
+type ScopeRes struct {
+       models.GithubRepo
+       TransformationRuleName string `json:"transformationRuleName,omitempty"`
+}
+
 // PutScope create or update github repo
 // @Summary create or update github repo
 // @Description Create or update github repo
@@ -35,11 +40,7 @@ import (
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/github/connections/{connectionId}/scopes [PUT]
 func PutScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       repos, err := scopeHelper.Put(input)
-       if err != nil {
-               return nil, errors.Default.Wrap(err, "error on saving 
GithubRepo")
-       }
-       return &plugin.ApiResourceOutput{Body: repos, Status: http.StatusOK}, 
nil
+       return scopeHelper.Put(input)
 }
 
 // UpdateScope patch to github repo
@@ -48,18 +49,14 @@ func PutScope(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, errors
 // @Tags plugins/github
 // @Accept application/json
 // @Param connectionId path int true "connection ID"
-// @Param repoId path int true "repo ID"
+// @Param scopeId path int true "scope ID"
 // @Param scope body models.GithubRepo true "json"
 // @Success 200  {object} models.GithubRepo
 // @Failure 400  {object} shared.ApiBody "Bad Request"
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/github/connections/{connectionId}/scopes/{scopeId} [PATCH]
 func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       repo, err := scopeHelper.Update(input, "github_id")
-       if err != nil {
-               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, err
-       }
-       return &plugin.ApiResourceOutput{Body: repo, Status: http.StatusOK}, nil
+       return scopeHelper.Update(input, "github_id")
 }
 
 // GetScopeList get Github repos
@@ -69,16 +66,12 @@ func UpdateScope(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, err
 // @Param connectionId path int true "connection ID"
 // @Param pageSize query int false "page size, default 50"
 // @Param page query int false "page size, default 1"
-// @Success 200  {object} []apiRepo
+// @Success 200  {object} []ScopeRes
 // @Failure 400  {object} shared.ApiBody "Bad Request"
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/github/connections/{connectionId}/scopes/ [GET]
 func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       apiScopes, err := scopeHelper.GetScopeList(input)
-       if err != nil {
-               return nil, err
-       }
-       return &plugin.ApiResourceOutput{Body: apiScopes, Status: 
http.StatusOK}, nil
+       return scopeHelper.GetScopeList(input)
 }
 
 // GetScope get one Github repo
@@ -86,15 +79,11 @@ func GetScopeList(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, er
 // @Description get one Github repo
 // @Tags plugins/github
 // @Param connectionId path int true "connection ID"
-// @Param repoId path int true "repo ID"
-// @Success 200  {object} apiRepo
+// @Param scopeId path int true "scope ID"
+// @Success 200  {object} ScopeRes
 // @Failure 400  {object} shared.ApiBody "Bad Request"
 // @Failure 500  {object} shared.ApiBody "Internal Error"
-// @Router /plugins/github/connections/{connectionId}/scopes/{id} [GET]
+// @Router /plugins/github/connections/{connectionId}/scopes/{scopeId} [GET]
 func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       apiScope, err := scopeHelper.GetScope(input, "github_id")
-       if err != nil {
-               return nil, err
-       }
-       return &plugin.ApiResourceOutput{Body: apiScope, Status: 
http.StatusOK}, nil
+       return scopeHelper.GetScope(input, "github_id")
 }
diff --git a/backend/plugins/github/models/repo.go 
b/backend/plugins/github/models/repo.go
index 9eda5e118..045437180 100644
--- a/backend/plugins/github/models/repo.go
+++ b/backend/plugins/github/models/repo.go
@@ -36,7 +36,7 @@ type GithubRepo struct {
        CloneUrl             string     `json:"cloneUrl" 
gorm:"type:varchar(255)" mapstructure:"cloneUrl,omitempty"`
        CreatedDate          *time.Time `json:"createdDate" mapstructure:"-"`
        UpdatedDate          *time.Time `json:"updatedDate" mapstructure:"-"`
-       common.NoPKModel     `json:"-" mapstructure:"-"`
+       common.NoPKModel     `json:"-" mapstructure:",squash"`
 }
 
 func (GithubRepo) TableName() string {
diff --git a/backend/plugins/gitlab/api/remote.go 
b/backend/plugins/gitlab/api/remote.go
index eff56d13a..a0aadcb96 100644
--- a/backend/plugins/gitlab/api/remote.go
+++ b/backend/plugins/gitlab/api/remote.go
@@ -400,3 +400,9 @@ func GetQueryForSearchProject(search string, page int, 
perPage int) (url.Values,
 
        return query, nil
 }
+
+func extractParam(params map[string]string) (uint64, uint64) {
+       connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
+       projectId, _ := strconv.ParseUint(params["projectId"], 10, 64)
+       return connectionId, projectId
+}
diff --git a/backend/plugins/gitlab/api/scope.go 
b/backend/plugins/gitlab/api/scope.go
index e41c729ab..9f3da5b67 100644
--- a/backend/plugins/gitlab/api/scope.go
+++ b/backend/plugins/gitlab/api/scope.go
@@ -18,16 +18,12 @@ limitations under the License.
 package api
 
 import (
-       "github.com/apache/incubator-devlake/core/dal"
        "github.com/apache/incubator-devlake/core/errors"
        "github.com/apache/incubator-devlake/core/plugin"
-       "github.com/apache/incubator-devlake/helpers/pluginhelper/api"
        "github.com/apache/incubator-devlake/plugins/gitlab/models"
-       "net/http"
-       "strconv"
 )
 
-type apiProject struct {
+type ScopeRes struct {
        models.GitlabProject
        TransformationRuleName string `json:"transformationRuleName,omitempty"`
 }
@@ -44,11 +40,7 @@ type apiProject struct {
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/gitlab/connections/{connectionId}/scopes [PUT]
 func PutScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       repos, err := scopeHelper.Put(input)
-       if err != nil {
-               return nil, errors.Default.Wrap(err, "error on saving 
GithubRepo")
-       }
-       return &plugin.ApiResourceOutput{Body: repos, Status: http.StatusOK}, 
nil
+       return scopeHelper.Put(input)
 }
 
 // UpdateScope patch to gitlab project
@@ -64,11 +56,7 @@ func PutScope(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, errors
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/gitlab/connections/{connectionId}/scopes/{projectId} 
[PATCH]
 func UpdateScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       repo, err := scopeHelper.Update(input, "gitlab_id")
-       if err != nil {
-               return &plugin.ApiResourceOutput{Body: nil, Status: 
http.StatusInternalServerError}, err
-       }
-       return &plugin.ApiResourceOutput{Body: repo, Status: http.StatusOK}, nil
+       return scopeHelper.Update(input, "gitlab_id")
 }
 
 // GetScopeList get Gitlab projects
@@ -76,43 +64,12 @@ func UpdateScope(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, err
 // @Description get Gitlab projects
 // @Tags plugins/gitlab
 // @Param connectionId path int false "connection ID"
-// @Success 200  {object} []apiProject
+// @Success 200  {object} []ScopeRes
 // @Failure 400  {object} shared.ApiBody "Bad Request"
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/gitlab/connections/{connectionId}/scopes/ [GET]
 func GetScopeList(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       var projects []models.GitlabProject
-       connectionId, _ := extractParam(input.Params)
-       if connectionId == 0 {
-               return nil, errors.BadInput.New("invalid path params")
-       }
-       limit, offset := api.GetLimitOffset(input.Query, "pageSize", "page")
-       err := basicRes.GetDal().All(&projects, dal.Where("connection_id = ?", 
connectionId), dal.Limit(limit), dal.Offset(offset))
-       if err != nil {
-               return nil, err
-       }
-       var ruleIds []uint64
-       for _, proj := range projects {
-               if proj.TransformationRuleId > 0 {
-                       ruleIds = append(ruleIds, proj.TransformationRuleId)
-               }
-       }
-       var rules []models.GitlabTransformationRule
-       if len(ruleIds) > 0 {
-               err = basicRes.GetDal().All(&rules, dal.Where("id IN (?)", 
ruleIds))
-               if err != nil {
-                       return nil, err
-               }
-       }
-       names := make(map[uint64]string)
-       for _, rule := range rules {
-               names[rule.ID] = rule.Name
-       }
-       var apiProjects []apiProject
-       for _, proj := range projects {
-               apiProjects = append(apiProjects, apiProject{proj, 
names[proj.TransformationRuleId]})
-       }
-       return &plugin.ApiResourceOutput{Body: apiProjects, Status: 
http.StatusOK}, nil
+       return scopeHelper.GetScopeList(input)
 }
 
 // GetScope get one Gitlab project
@@ -123,36 +80,10 @@ func GetScopeList(input *plugin.ApiResourceInput) 
(*plugin.ApiResourceOutput, er
 // @Param projectId path int false "project ID"
 // @Param pageSize query int false "page size, default 50"
 // @Param page query int false "page size, default 1"
-// @Success 200  {object} apiProject
+// @Success 200  {object} ScopeRes
 // @Failure 400  {object} shared.ApiBody "Bad Request"
 // @Failure 500  {object} shared.ApiBody "Internal Error"
 // @Router /plugins/gitlab/connections/{connectionId}/scopes/{projectId} [GET]
 func GetScope(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, 
errors.Error) {
-       var project models.GitlabProject
-       connectionId, projectId := extractParam(input.Params)
-       if connectionId*projectId == 0 {
-               return nil, errors.BadInput.New("invalid path params")
-       }
-       db := basicRes.GetDal()
-       err := db.First(&project, dal.Where("connection_id = ? AND gitlab_id = 
?", connectionId, projectId))
-       if db.IsErrorNotFound(err) {
-               return nil, errors.NotFound.New("record not found")
-       }
-       if err != nil {
-               return nil, err
-       }
-       var rule models.GitlabTransformationRule
-       if project.TransformationRuleId > 0 {
-               err = basicRes.GetDal().First(&rule, dal.Where("id = ?", 
project.TransformationRuleId))
-               if err != nil {
-                       return nil, err
-               }
-       }
-       return &plugin.ApiResourceOutput{Body: apiProject{project, rule.Name}, 
Status: http.StatusOK}, nil
-}
-
-func extractParam(params map[string]string) (uint64, uint64) {
-       connectionId, _ := strconv.ParseUint(params["connectionId"], 10, 64)
-       projectId, _ := strconv.ParseUint(params["projectId"], 10, 64)
-       return connectionId, projectId
+       return scopeHelper.GetScope(input, "gitlab_id")
 }
diff --git a/backend/plugins/gitlab/models/project.go 
b/backend/plugins/gitlab/models/project.go
index 340dcd65e..91db090ff 100644
--- a/backend/plugins/gitlab/models/project.go
+++ b/backend/plugins/gitlab/models/project.go
@@ -24,9 +24,9 @@ import (
 )
 
 type GitlabProject struct {
-       ConnectionId            uint64 `json:"connectionId" 
mapstructure:"connectionId" gorm:"primaryKey"`
+       ConnectionId            uint64 `json:"connectionId" 
mapstructure:"connectionId" validate:"required" gorm:"primaryKey"`
        TransformationRuleId    uint64 `json:"transformationRuleId,omitempty" 
mapstructure:"transformationRuleId"`
-       GitlabId                int    `json:"gitlabId" mapstructure:"gitlabId" 
gorm:"primaryKey"`
+       GitlabId                int    `json:"gitlabId" mapstructure:"gitlabId" 
validate:"required" gorm:"primaryKey"`
        Name                    string `json:"name" mapstructure:"name" 
gorm:"type:varchar(255)"`
        Description             string `json:"description" 
mapstructure:"description"`
        DefaultBranch           string `json:"defaultBranch" 
mapstructure:"defaultBranch" gorm:"type:varchar(255)"`
@@ -42,7 +42,7 @@ type GitlabProject struct {
 
        CreatedDate      time.Time  `json:"createdDate" mapstructure:"-"`
        UpdatedDate      *time.Time `json:"updatedDate" mapstructure:"-"`
-       common.NoPKModel `json:"-" mapstructure:"-"`
+       common.NoPKModel `json:"-" mapstructure:",squash"`
 }
 
 func (GitlabProject) TableName() string {

Reply via email to