This is an automated email from the ASF dual-hosted git repository.
klesh 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 d58803baf refactor(zentao): add custom types OperatedBy and
StringFloat64 to simplify codes (#6188)
d58803baf is described below
commit d58803baff0ca5929b6e3b0d151e60ca95ea0291
Author: Lynwee <[email protected]>
AuthorDate: Sun Oct 8 14:39:23 2023 +0800
refactor(zentao): add custom types OperatedBy and StringFloat64 to simplify
codes (#6188)
* refactor(zentao): add custom types OperatedBy and StringFloat64 to
simplify codes
* fix(zentao): add Scan and Value interface for custom types
---
backend/core/models/common/string_float64.go | 85 ++++++++++++++++
backend/plugins/zentao/api/remote.go | 9 --
backend/plugins/zentao/models/project.go | 140 +++++++++++++++++----------
3 files changed, 176 insertions(+), 58 deletions(-)
diff --git a/backend/core/models/common/string_float64.go
b/backend/core/models/common/string_float64.go
new file mode 100644
index 000000000..a6c9c7402
--- /dev/null
+++ b/backend/core/models/common/string_float64.go
@@ -0,0 +1,85 @@
+/*
+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 common
+
+import (
+ "database/sql/driver"
+ "encoding/json"
+ "fmt"
+ "github.com/spf13/cast"
+)
+
+type StringFloat64 struct {
+ v float64
+ t string
+}
+
+func (f *StringFloat64) MarshalJSON() ([]byte, error) {
+ return json.Marshal(f.String())
+}
+
+func (f *StringFloat64) String() string {
+ if f.t == "string" {
+ return fmt.Sprintf("\"%v\"", f.v)
+ }
+ return fmt.Sprintf("%v", f.v)
+}
+
+func (f *StringFloat64) UnmarshalJSON(data []byte) error {
+ var i interface{}
+ if err := json.Unmarshal(data, &i); err != nil {
+ return err
+ }
+ switch i.(type) {
+ case float64:
+ f.t = "float64"
+ case string:
+ f.t = "string"
+ }
+ value, err := cast.ToFloat64E(i)
+ if err != nil {
+ return err
+ }
+ f.v = value
+ return nil
+}
+
+func (f *StringFloat64) Value() (driver.Value, error) {
+ if f == nil {
+ return nil, nil
+ }
+ return f.v, nil
+}
+
+func (f *StringFloat64) Scan(v interface{}) error {
+ switch value := v.(type) {
+ case float64:
+ *f = StringFloat64{
+ v: value,
+ t: "float64",
+ }
+ case string:
+ *f = StringFloat64{
+ v: cast.ToFloat64(value),
+ t: "string",
+ }
+ default:
+ return fmt.Errorf("%+v is an unknown type, with value: %v", v,
value)
+ }
+ return nil
+}
diff --git a/backend/plugins/zentao/api/remote.go
b/backend/plugins/zentao/api/remote.go
index 46965821f..7717eeb25 100644
--- a/backend/plugins/zentao/api/remote.go
+++ b/backend/plugins/zentao/api/remote.go
@@ -36,12 +36,6 @@ type ProjectResponse struct {
Values []models.ZentaoProject `json:"projects"`
}
-func (pr *ProjectResponse) ConvertFix() {
- for i := range pr.Values {
- pr.Values[i].ConvertFix()
- }
-}
-
func getGroup(basicRes context.BasicRes, gid string, queryData
*api.RemoteQueryData, connection models.ZentaoConnection)
([]api.BaseRemoteGroupResponse, errors.Error) {
return []api.BaseRemoteGroupResponse{
/*{
@@ -100,9 +94,6 @@ func RemoteScopes(input *plugin.ApiResourceInput)
(*plugin.ApiResourceOutput, er
logger.Error(err, "unmarshal projects
response")
return nil, err
}
-
- resBody.ConvertFix()
-
return resBody.Values, nil
})
}
diff --git a/backend/plugins/zentao/models/project.go
b/backend/plugins/zentao/models/project.go
index 3db2744f2..64dfed0b3 100644
--- a/backend/plugins/zentao/models/project.go
+++ b/backend/plugins/zentao/models/project.go
@@ -18,15 +18,98 @@ limitations under the License.
package models
import (
+ "database/sql/driver"
+ "encoding/json"
"fmt"
- "strconv"
-
"github.com/spf13/cast"
+ "strconv"
"github.com/apache/incubator-devlake/core/models/common"
"github.com/apache/incubator-devlake/core/plugin"
)
+type OperatedBy struct {
+ Raw interface{}
+ CoreOperatedBy
+}
+
+type CoreOperatedBy struct {
+ Type string
+ Account string
+ RealName string
+}
+
+func (by *OperatedBy) Value() (driver.Value, error) {
+ if by == nil {
+ return nil, nil
+ }
+ b, err := json.Marshal(by.CoreOperatedBy)
+ if err != nil {
+ return nil, err
+ }
+ return string(b), nil
+}
+
+func (by *OperatedBy) Scan(v interface{}) error {
+ switch value := v.(type) {
+ case string:
+ var coreOperatedBy CoreOperatedBy
+ if err := json.Unmarshal([]byte(value), &coreOperatedBy); err
!= nil {
+ return err
+ }
+ *by = OperatedBy{
+ Raw: nil,
+ CoreOperatedBy: coreOperatedBy,
+ }
+ default:
+ return fmt.Errorf("%+v is an unknown type, with value: %v", v,
value)
+ }
+ return nil
+}
+
+func (by *OperatedBy) MarshalJSON() ([]byte, error) {
+ if by == nil {
+ return json.Marshal(nil)
+ }
+ return json.Marshal(by.Raw)
+}
+
+func (by *OperatedBy) UnmarshalJSON(data []byte) error {
+ var i interface{}
+ if err := json.Unmarshal(data, &i); err != nil {
+ return err
+ }
+ by.Raw = i
+ switch i.(type) {
+ case string:
+ by.Type = "string"
+ by.Account = cast.ToString(by.Raw)
+ by.RealName = cast.ToString(by.Raw)
+ default:
+ by.Type = "struct"
+ type ByUser struct {
+ ID int `json:"id"`
+ Account string `json:"account"`
+ Avatar string `json:"avatar"`
+ RealName string `json:"realname"`
+ }
+ var byUser ByUser
+ if err := json.Unmarshal(data, &byUser); err != nil {
+ return err
+ }
+ by.Account = byUser.Account
+ by.RealName = byUser.RealName
+ }
+ return nil
+}
+
+func (by *OperatedBy) String() string {
+ if by == nil {
+ return "<nil>"
+ }
+ return by.Account
+}
+
type ZentaoProject struct {
common.Scope
Id int64 `json:"id" mapstructure:"id"
gorm:"primaryKey;type:BIGINT NOT NULL;autoIncrement:false"`
@@ -65,11 +148,9 @@ type ZentaoProject struct {
OpenedVersion string `json:"openedVersion"
mapstructure:"openedVersion"`
//LastEditedBy string `json:"lastEditedBy"
mapstructure:"lastEditedBy"`
LastEditedDate *common.Iso8601Time `json:"lastEditedDate"
mapstructure:"lastEditedDate"`
- ClosedBy string
- ClosedByRes interface{} `json:"closedBy"
mapstructure:"closedBy" gorm:"-"`
+ ClosedBy *OperatedBy `json:"closedBy"
mapstructure:"closedBy" gorm:"-"`
ClosedDate *common.Iso8601Time `json:"closedDate"
mapstructure:"closedDate"`
- CanceledBy string
- CanceledByRes interface{} `json:"canceledBy"
mapstructure:"canceledBy" gorm:"-"`
+ CanceledBy *OperatedBy `json:"canceledBy"
mapstructure:"canceledBy" gorm:"-"`
CanceledDate *common.Iso8601Time `json:"canceledDate"
mapstructure:"canceledDate"`
SuspendedDate *common.Iso8601Time `json:"suspendedDate"
mapstructure:"suspendedDate"`
PO string `json:"po" mapstructure:"po"`
@@ -89,11 +170,10 @@ type ZentaoProject struct {
TeamCount int `json:"teamCount" mapstructure:"teamCount"`
LeftTasks string `json:"leftTasks" mapstructure:"leftTasks"`
//TeamMembers []interface{} `json:"teamMembers" gorm:"-"`
- TotalEstimate float64 `json:"totalEstimate"
mapstructure:"totalEstimate"`
- TotalConsumed float64 `json:"totalConsumed"
mapstructure:"totalConsumed"`
- TotalLeft float64 `json:"totalLeft" mapstructure:"totalLeft"`
- Progress float64
- ProgressRes interface{} `json:"progress" mapstructure:"progress"
gorm:"-"`
+ TotalEstimate float64 `json:"totalEstimate"
mapstructure:"totalEstimate"`
+ TotalConsumed float64 `json:"totalConsumed"
mapstructure:"totalConsumed"`
+ TotalLeft float64 `json:"totalLeft"
mapstructure:"totalLeft"`
+ Progress *common.StringFloat64 `json:"progress"
mapstructure:"progress" gorm:"-"`
}
type PM struct {
@@ -116,44 +196,6 @@ type Hours struct {
HoursTotalReal float64 `json:"totalReal" mapstructure:"totalReal"`
}
-func (p *ZentaoProject) fixProgressField() {
- p.Progress = cast.ToFloat64(p.ProgressRes)
-}
-
-func (p *ZentaoProject) fixClosedByResField() {
- switch cb := p.ClosedByRes.(type) {
- case string:
- p.ClosedBy = cb
- default:
- if cb == nil {
- p.ClosedBy = ""
- } else {
- p.ClosedBy = fmt.Sprintf("%v", cb)
- }
- }
- p.ClosedByRes = p.ClosedBy
-}
-
-func (p *ZentaoProject) fixCanceledByResField() {
- switch cb := p.CanceledByRes.(type) {
- case string:
- p.CanceledBy = cb
- default:
- if cb == nil {
- p.CanceledBy = ""
- } else {
- p.CanceledBy = fmt.Sprintf("%v", cb)
- }
- }
- p.CanceledByRes = p.CanceledBy
-}
-
-func (p *ZentaoProject) ConvertFix() {
- p.fixProgressField()
- p.fixClosedByResField()
- p.fixCanceledByResField()
-}
-
func (p ZentaoProject) TableName() string {
return "_tool_zentao_projects"
}