From 7a67a5b53ffb55282d9b1d14f3aae3baba24e761 Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 27 Mar 2024 14:14:17 +0800 Subject: [PATCH 1/9] add group support for collaboration --- .../repository/mongodb/collaboration_mode.go | 1 + .../service/collaboration_instance.go | 14 +++++++- .../service/collaboration_mode.go | 20 +++++++++++ .../collaboration/collaboration_mode.go | 15 +++++--- .../user/core/handler/user/user_group.go | 35 +++++++++++++------ .../core/service/permission/user_group.go | 25 +++++++++++++ pkg/shared/client/user/user_group.go | 10 ++++++ pkg/types/user.go | 8 +++++ pkg/types/user_group.go | 13 +++++++ 9 files changed, 126 insertions(+), 15 deletions(-) diff --git a/pkg/microservice/aslan/core/collaboration/repository/mongodb/collaboration_mode.go b/pkg/microservice/aslan/core/collaboration/repository/mongodb/collaboration_mode.go index dd2cbc7a23..dfb47d1c88 100644 --- a/pkg/microservice/aslan/core/collaboration/repository/mongodb/collaboration_mode.go +++ b/pkg/microservice/aslan/core/collaboration/repository/mongodb/collaboration_mode.go @@ -99,6 +99,7 @@ func (c *CollaborationModeColl) Update(username string, args *models.Collaborati "update_time": time.Now().Unix(), "update_by": username, "members": args.Members, + "member_info": args.MemberInfo, "workflows": args.Workflows, "recycle_day": args.RecycleDay, "revision": res.Revision + 1, diff --git a/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go b/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go index 4bd495d413..0102bdca15 100644 --- a/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go +++ b/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go @@ -18,6 +18,7 @@ package service import ( "fmt" + "github.com/koderover/zadig/v2/pkg/shared/client/user" "reflect" "time" @@ -296,9 +297,20 @@ func updateVisitTime(uid string, cis []*models.CollaborationInstance, logger *za } func GetCollaborationUpdate(projectName, uid, identityType, userName string, logger *zap.SugaredLogger) (*GetCollaborationUpdateResp, error) { + relatedGroups, err := user.New().GetUserGroupsByUid(uid) + if err != nil { + logger.Errorf("GetCollaborationUpdate error, err msg:%s", err) + return nil, err + } + members := []string{uid} + for _, group := range relatedGroups.GroupList { + members = append(members, group.ID) + } + + // user uid and related gids to get collaboration mode collaborations, err := mongodb.NewCollaborationModeColl().List(&mongodb.CollaborationModeListOptions{ Projects: []string{projectName}, - Members: []string{uid}, + Members: members, }) if err != nil { logger.Errorf("GetCollaborationUpdate error, err msg:%s", err) diff --git a/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go b/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go index 2638f42c12..7ca1af018b 100644 --- a/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go +++ b/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go @@ -17,14 +17,31 @@ limitations under the License. package service import ( + "fmt" "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" + "k8s.io/apimachinery/pkg/util/sets" "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/collaboration/repository/models" "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/collaboration/repository/mongodb" ) +func validateMemberInfo(collaborationMode *models.CollaborationMode) bool { + if len(collaborationMode.Members) != len(collaborationMode.MemberInfo) { + return false + } + memberSet := sets.NewString(collaborationMode.Members...) + memberInfoSet := sets.NewString() + for _, memberInfo := range collaborationMode.MemberInfo { + memberInfoSet.Insert(memberInfo.GetID()) + } + return memberSet.Equal(memberInfoSet) +} + func CreateCollaborationMode(userName string, collaborationMode *models.CollaborationMode, logger *zap.SugaredLogger) error { + if !validateMemberInfo(collaborationMode) { + return fmt.Errorf("members and member_info not match") + } err := mongodb.NewCollaborationModeColl().Create(userName, collaborationMode) if err != nil { logger.Errorf("CreateCollaborationMode error, err msg:%s", err) @@ -34,6 +51,9 @@ func CreateCollaborationMode(userName string, collaborationMode *models.Collabor } func UpdateCollaborationMode(userName string, collaborationMode *models.CollaborationMode, logger *zap.SugaredLogger) error { + if !validateMemberInfo(collaborationMode) { + return fmt.Errorf("members and member_info not match") + } err := mongodb.NewCollaborationModeColl().Update(userName, collaborationMode) if err != nil { logger.Errorf("UpdateCollaborationMode error, err msg:%s", err) diff --git a/pkg/microservice/aslan/core/common/service/collaboration/collaboration_mode.go b/pkg/microservice/aslan/core/common/service/collaboration/collaboration_mode.go index 6aa9c17ceb..dccdfe4b42 100644 --- a/pkg/microservice/aslan/core/common/service/collaboration/collaboration_mode.go +++ b/pkg/microservice/aslan/core/common/service/collaboration/collaboration_mode.go @@ -154,16 +154,23 @@ func setCollaborationModesWorkflowDisplayName(mode *models.CollaborationMode) { } func setMemberInfo(mode *models.CollaborationMode) { - if mode.MemberInfo != nil && len(mode.MemberInfo) > 0 { + if mode.MemberInfo != nil && len(mode.MemberInfo) == len(mode.Members) { return } - memberList := make([]*types.Identity, 0) + memberInfoMap := make(map[string]*types.Identity) + for _, member := range mode.MemberInfo { + memberInfoMap[member.UID] = member + } + for _, uid := range mode.Members { - memberList = append(memberList, &types.Identity{ + if _, ok := memberInfoMap[uid]; ok { + continue + } + mode.MemberInfo = append(mode.MemberInfo, &types.Identity{ IdentityType: "user", UID: uid, }) } - mode.MemberInfo = memberList + } diff --git a/pkg/microservice/user/core/handler/user/user_group.go b/pkg/microservice/user/core/handler/user/user_group.go index d56e3c4feb..5d8c6b8a12 100644 --- a/pkg/microservice/user/core/handler/user/user_group.go +++ b/pkg/microservice/user/core/handler/user/user_group.go @@ -70,6 +70,7 @@ type listUserGroupsReq struct { PageNum int `json:"page_num" form:"page_num"` PageSize int `json:"page_size" form:"page_size"` Name string `json:"name" form:"name"` + Uid string `json:"uid" form:"uid"` } type openAPIListUserGroupReq struct { @@ -132,16 +133,30 @@ func ListUserGroups(c *gin.Context) { return } - groupList, count, err := permission.ListUserGroups(query.Name, query.PageNum, query.PageSize, ctx.Logger) - - if err != nil { - ctx.Err = err - return - } - - ctx.Resp = &listUserGroupResp{ - GroupList: groupList, - Count: count, + if len(query.Uid) > 0 { + groupList, count, err := permission.ListUserGroupsByUid(query.Uid, ctx.Logger) + + if err != nil { + ctx.Err = err + return + } + + ctx.Resp = &listUserGroupResp{ + GroupList: groupList, + Count: count, + } + } else { + groupList, count, err := permission.ListUserGroups(query.Name, query.PageNum, query.PageSize, ctx.Logger) + + if err != nil { + ctx.Err = err + return + } + + ctx.Resp = &listUserGroupResp{ + GroupList: groupList, + Count: count, + } } } diff --git a/pkg/microservice/user/core/service/permission/user_group.go b/pkg/microservice/user/core/service/permission/user_group.go index 57e9cdfd30..db7dd1f462 100644 --- a/pkg/microservice/user/core/service/permission/user_group.go +++ b/pkg/microservice/user/core/service/permission/user_group.go @@ -132,6 +132,31 @@ type UserGroupResp struct { UserTotal int64 `json:"user_total"` } +func ListUserGroupsByUid(uid string, logger *zap.SugaredLogger) ([]*UserGroupResp, int64, error) { + groups, err := orm.ListUserGroupByUID(uid, repository.DB) + if err != nil { + logger.Errorf("failed to list user groups by uid: %s, error: %s", uid, err) + return nil, 0, err + } + + resp := make([]*UserGroupResp, 0) + for _, group := range groups { + respItem := &UserGroupResp{ + ID: group.GroupID, + Name: group.GroupName, + Description: group.Description, + } + if group.Type == int64(setting.RoleTypeSystem) { + respItem.Type = string(setting.ResourceTypeSystem) + } else { + respItem.Type = string(setting.ResourceTypeCustom) + } + resp = append(resp, respItem) + } + + return resp, int64(len(resp)), nil +} + func ListUserGroups(queryName string, pageNum, pageSize int, logger *zap.SugaredLogger) ([]*UserGroupResp, int64, error) { resp := make([]*UserGroupResp, 0) tx := repository.DB.Begin() diff --git a/pkg/shared/client/user/user_group.go b/pkg/shared/client/user/user_group.go index 0cf709259d..53bed156a3 100644 --- a/pkg/shared/client/user/user_group.go +++ b/pkg/shared/client/user/user_group.go @@ -35,3 +35,13 @@ func (c *Client) GetGroupDetailedInfo(groupID string) (*types.DetailedUserGroupR return resp, nil } + +func (c *Client) GetUserGroupsByUid(uid string) (*types.ListUserGroupResp, error) { + url := "/user-group" + resp := &types.ListUserGroupResp{} + queries := make(map[string]string) + queries["uid"] = uid + + _, err := c.Get(url, httpclient.SetQueryParams(queries), httpclient.SetResult(resp)) + return resp, err +} diff --git a/pkg/types/user.go b/pkg/types/user.go index 670d553faa..2a004b6bb1 100644 --- a/pkg/types/user.go +++ b/pkg/types/user.go @@ -79,3 +79,11 @@ type Identity struct { UID string `json:"uid,omitempty"` GID string `json:"gid,omitempty"` } + +func (id *Identity) GetID() string { + if id.IdentityType == "user" { + return id.UID + } else { + return id.GID + } +} diff --git a/pkg/types/user_group.go b/pkg/types/user_group.go index bcf4b15ac5..d214fc7832 100644 --- a/pkg/types/user_group.go +++ b/pkg/types/user_group.go @@ -27,3 +27,16 @@ type DetailedUserGroupResp struct { Type string `json:"type"` UIDs []string `json:"uids"` } + +type UserGroupResp struct { + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Type string `json:"type"` + UserTotal int64 `json:"user_total"` +} + +type ListUserGroupResp struct { + GroupList []*UserGroupResp `json:"group_list"` + Count int64 `json:"total"` +} From ab44f1b694570f7cc476b9b3392810164f5ee73d Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 27 Mar 2024 17:21:01 +0800 Subject: [PATCH 2/9] add group support for approval of release plan --- .../core/common/service/approval/approval.go | 4 + .../core/release_plan/service/approval.go | 81 +++++++++++++++---- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/pkg/microservice/aslan/core/common/service/approval/approval.go b/pkg/microservice/aslan/core/common/service/approval/approval.go index 155552936d..d2e257db6f 100644 --- a/pkg/microservice/aslan/core/common/service/approval/approval.go +++ b/pkg/microservice/aslan/core/common/service/approval/approval.go @@ -85,6 +85,10 @@ func (c *GlobalApproveManager) DoApproval(key, userName, userID, comment string, meetUser := false for _, user := range approvalData.ApproveUsers { + // for release plan approvals we need to + if user.Type == "group" { + continue + } if user.UserID != userID { continue } diff --git a/pkg/microservice/aslan/core/release_plan/service/approval.go b/pkg/microservice/aslan/core/release_plan/service/approval.go index 5dbefbf127..a07ad61dfe 100644 --- a/pkg/microservice/aslan/core/release_plan/service/approval.go +++ b/pkg/microservice/aslan/core/release_plan/service/approval.go @@ -21,6 +21,11 @@ import ( "context" _ "embed" "fmt" + "github.com/koderover/zadig/v2/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/v2/pkg/shared/client/user" + "github.com/koderover/zadig/v2/pkg/tool/mail" + "github.com/koderover/zadig/v2/pkg/types" + "k8s.io/apimachinery/pkg/util/sets" "net/url" "text/template" "time" @@ -35,12 +40,9 @@ import ( approvalservice "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/service/approval" dingservice "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/service/dingtalk" larkservice "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/common/service/lark" - "github.com/koderover/zadig/v2/pkg/shared/client/systemconfig" - "github.com/koderover/zadig/v2/pkg/shared/client/user" "github.com/koderover/zadig/v2/pkg/tool/dingtalk" "github.com/koderover/zadig/v2/pkg/tool/lark" "github.com/koderover/zadig/v2/pkg/tool/log" - "github.com/koderover/zadig/v2/pkg/tool/mail" ) //go:embed approval.html @@ -216,17 +218,20 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { } approval := plan.Approval.NativeApproval - go func() { - email, err := systemconfig.New().GetEmailHost() + var err error + mailNotifyInfo := "" + var email *systemconfig.Email + for { + email, err = systemconfig.New().GetEmailHost() if err != nil { log.Errorf("CreateNativeApproval GetEmailHost error, error msg:%s", err) - return + break } t, err := template.New("approval").Parse(string(approvalHTML)) if err != nil { log.Errorf("CreateNativeApproval template parse error, error msg:%s", err) - return + break } var buf bytes.Buffer err = t.Execute(&buf, struct { @@ -244,14 +249,60 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { }) if err != nil { log.Errorf("CreateNativeApproval template execute error, error msg:%s", err) - return + break + } + mailNotifyInfo = buf.String() + break + } + + // change [group + user] approvals to user approvals + approvalUsers := make([]*models.User, 0) + userSet := sets.NewString() + userMap := make(map[string]*types.UserInfo) + for _, u := range approval.ApproveUsers { + if u.Type == "user" || u.Type == "" { + userSet.Insert(u.UserID) + approvalUsers = append(approvalUsers, u) } - for _, u := range approval.ApproveUsers { - info, err := user.New().GetUserByID(u.UserID) + } + for _, u := range approval.ApproveUsers { + if u.Type == "group" { + groupInfo, err := user.New().GetGroupDetailedInfo(u.GroupID) if err != nil { - log.Warnf("CreateNativeApproval GetUserByUid error, error msg:%s", err) + log.Warnf("CreateNativeApproval GetGroupDetailedInfo error, error msg:%s", err) continue } + userSet.Insert(groupInfo.UIDs...) + for _, uid := range groupInfo.UIDs { + if userSet.Has(uid) { + continue + } + userDetailedInfo, err := user.New().GetUserByID(uid) + if err != nil { + log.Errorf("failed to find user %s, error: %s", uid, err) + continue + } + userMap[uid] = userDetailedInfo + approvalUsers = append(approvalUsers, &models.User{ + Type: "user", + UserID: uid, + UserName: userDetailedInfo.Name, + }) + } + } + } + + if email != nil { + for _, uid := range userSet.List() { + info, ok := userMap[uid] + if !ok { + info, err = user.New().GetUserByID(uid) + if err != nil { + log.Warnf("CreateNativeApproval GetUserByUid error, error msg:%s", err) + continue + } + } + if info.Email == "" { log.Warnf("CreateNativeApproval user %s email is empty", info.Name) continue @@ -264,19 +315,19 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { UserName: email.UserName, Password: email.Password, Port: email.Port, - Body: buf.String(), + Body: mailNotifyInfo, }) if err != nil { log.Errorf("CreateNativeApproval SendEmail error, error msg:%s", err) continue } } - }() + } + approval.ApproveUsers = approvalUsers approveKey := uuid.New().String() approval.InstanceCode = approveKey - approveWithL := approval - approvalservice.GlobalApproveMap.SetApproval(approveKey, approveWithL) + approvalservice.GlobalApproveMap.SetApproval(approveKey, approval) return nil } From afdf0253819e1953defd9b3a708528524d327156 Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 27 Mar 2024 17:48:41 +0800 Subject: [PATCH 3/9] git st --- pkg/microservice/aslan/core/release_plan/service/approval.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/release_plan/service/approval.go b/pkg/microservice/aslan/core/release_plan/service/approval.go index a07ad61dfe..2ad462a4e2 100644 --- a/pkg/microservice/aslan/core/release_plan/service/approval.go +++ b/pkg/microservice/aslan/core/release_plan/service/approval.go @@ -272,11 +272,11 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { log.Warnf("CreateNativeApproval GetGroupDetailedInfo error, error msg:%s", err) continue } - userSet.Insert(groupInfo.UIDs...) for _, uid := range groupInfo.UIDs { if userSet.Has(uid) { continue } + userSet.Insert(uid) userDetailedInfo, err := user.New().GetUserByID(uid) if err != nil { log.Errorf("failed to find user %s, error: %s", uid, err) From 74b677224d73e325ff1b54e907ff23ac90687b6d Mon Sep 17 00:00:00 2001 From: allenshen Date: Wed, 27 Mar 2024 17:49:24 +0800 Subject: [PATCH 4/9] fix collaboration group config error --- pkg/microservice/aslan/core/release_plan/service/approval.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pkg/microservice/aslan/core/release_plan/service/approval.go b/pkg/microservice/aslan/core/release_plan/service/approval.go index 2ad462a4e2..dc0361efc6 100644 --- a/pkg/microservice/aslan/core/release_plan/service/approval.go +++ b/pkg/microservice/aslan/core/release_plan/service/approval.go @@ -324,10 +324,14 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { } } + originApprovalUser := approval.ApproveUsers approval.ApproveUsers = approvalUsers + approveKey := uuid.New().String() approval.InstanceCode = approveKey + approvalservice.GlobalApproveMap.SetApproval(approveKey, approval) + approval.ApproveUsers = originApprovalUser return nil } From 968a5bba0cef0acc6988f4a5153482e038c3c57a Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 28 Mar 2024 11:38:42 +0800 Subject: [PATCH 5/9] update native approval logic --- .../aslan/core/common/repository/models/workflow_v4.go | 9 +++++---- .../aslan/core/common/service/approval/approval.go | 3 --- .../aslan/core/release_plan/service/approval.go | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go index a4bf68b136..4e15809ef2 100644 --- a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go +++ b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go @@ -110,10 +110,11 @@ type Approval struct { } type NativeApproval struct { - Timeout int `bson:"timeout" yaml:"timeout" json:"timeout"` - ApproveUsers []*User `bson:"approve_users" yaml:"approve_users" json:"approve_users"` - NeededApprovers int `bson:"needed_approvers" yaml:"needed_approvers" json:"needed_approvers"` - RejectOrApprove config.ApproveOrReject `bson:"reject_or_approve" yaml:"-" json:"reject_or_approve"` + Timeout int `bson:"timeout" yaml:"timeout" json:"timeout"` + ApproveUsers []*User `bson:"approve_users" yaml:"approve_users" json:"approve_users"` + DetailedApproveUsers []*User `bson:"detailed_approve_users" yaml:"detailed_approve_users" json:"detailed_approve_users"` + NeededApprovers int `bson:"needed_approvers" yaml:"needed_approvers" json:"needed_approvers"` + RejectOrApprove config.ApproveOrReject `bson:"reject_or_approve" yaml:"-" json:"reject_or_approve"` // InstanceCode: native approval instance code, save for working after restart aslan InstanceCode string `bson:"instance_code" yaml:"instance_code" json:"instance_code"` } diff --git a/pkg/microservice/aslan/core/common/service/approval/approval.go b/pkg/microservice/aslan/core/common/service/approval/approval.go index d2e257db6f..9ab4c8dda9 100644 --- a/pkg/microservice/aslan/core/common/service/approval/approval.go +++ b/pkg/microservice/aslan/core/common/service/approval/approval.go @@ -86,9 +86,6 @@ func (c *GlobalApproveManager) DoApproval(key, userName, userID, comment string, meetUser := false for _, user := range approvalData.ApproveUsers { // for release plan approvals we need to - if user.Type == "group" { - continue - } if user.UserID != userID { continue } diff --git a/pkg/microservice/aslan/core/release_plan/service/approval.go b/pkg/microservice/aslan/core/release_plan/service/approval.go index dc0361efc6..abff96fa23 100644 --- a/pkg/microservice/aslan/core/release_plan/service/approval.go +++ b/pkg/microservice/aslan/core/release_plan/service/approval.go @@ -326,6 +326,7 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { originApprovalUser := approval.ApproveUsers approval.ApproveUsers = approvalUsers + approval.DetailedApproveUsers = approvalUsers approveKey := uuid.New().String() approval.InstanceCode = approveKey From 505e9dc39682c8fb494f75728f5999359413785c Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 28 Mar 2024 13:43:54 +0800 Subject: [PATCH 6/9] update native approval logic --- .../common/repository/models/workflow_v4.go | 2 +- .../core/release_plan/service/release_plan.go | 45 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go index 4e15809ef2..c358e239b0 100644 --- a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go +++ b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go @@ -112,7 +112,7 @@ type Approval struct { type NativeApproval struct { Timeout int `bson:"timeout" yaml:"timeout" json:"timeout"` ApproveUsers []*User `bson:"approve_users" yaml:"approve_users" json:"approve_users"` - DetailedApproveUsers []*User `bson:"detailed_approve_users" yaml:"detailed_approve_users" json:"detailed_approve_users"` + DetailedApproveUsers []*User `bson:"-" yaml:"detailed_approve_users" json:"detailed_approve_users"` NeededApprovers int `bson:"needed_approvers" yaml:"needed_approvers" json:"needed_approvers"` RejectOrApprove config.ApproveOrReject `bson:"reject_or_approve" yaml:"-" json:"reject_or_approve"` // InstanceCode: native approval instance code, save for working after restart aslan diff --git a/pkg/microservice/aslan/core/release_plan/service/release_plan.go b/pkg/microservice/aslan/core/release_plan/service/release_plan.go index be5d7b06f6..c0f6d034b7 100644 --- a/pkg/microservice/aslan/core/release_plan/service/release_plan.go +++ b/pkg/microservice/aslan/core/release_plan/service/release_plan.go @@ -18,6 +18,7 @@ package service import ( "context" + "k8s.io/apimachinery/pkg/util/sets" "time" "github.com/gin-gonic/gin" @@ -131,6 +132,50 @@ func ListReleasePlans(pageNum, pageSize int64) (*ListReleasePlanResp, error) { } func GetReleasePlan(id string) (*models.ReleasePlan, error) { + releasePlan, err := mongodb.NewReleasePlanColl().GetByID(context.Background(), id) + if err != nil { + return nil, errors.Wrap(err, "GetReleasePlan") + } + + // TODO write detailed approval data into DB + if releasePlan.Approval != nil && releasePlan.Approval.NativeApproval != nil { + approval := releasePlan.Approval.NativeApproval + approvalUsers := make([]*models.User, 0) + userSet := sets.NewString() + for _, u := range approval.ApproveUsers { + if u.Type == "user" || u.Type == "" { + userSet.Insert(u.UserID) + approvalUsers = append(approvalUsers, u) + } + } + for _, u := range approval.ApproveUsers { + if u.Type == "group" { + groupInfo, err := user.New().GetGroupDetailedInfo(u.GroupID) + if err != nil { + log.Warnf("CreateNativeApproval GetGroupDetailedInfo error, error msg:%s", err) + continue + } + for _, uid := range groupInfo.UIDs { + if userSet.Has(uid) { + continue + } + userSet.Insert(uid) + userDetailedInfo, err := user.New().GetUserByID(uid) + if err != nil { + log.Errorf("failed to find user %s, error: %s", uid, err) + continue + } + approvalUsers = append(approvalUsers, &models.User{ + Type: "user", + UserID: uid, + UserName: userDetailedInfo.Name, + }) + } + } + } + releasePlan.Approval.NativeApproval.DetailedApproveUsers = approvalUsers + } + return mongodb.NewReleasePlanColl().GetByID(context.Background(), id) } From dafc38986d46521932273b52ff17e8df794f6abf Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 28 Mar 2024 13:55:04 +0800 Subject: [PATCH 7/9] update native approval logic --- .../aslan/core/release_plan/service/release_plan.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/microservice/aslan/core/release_plan/service/release_plan.go b/pkg/microservice/aslan/core/release_plan/service/release_plan.go index c0f6d034b7..361a26e8bf 100644 --- a/pkg/microservice/aslan/core/release_plan/service/release_plan.go +++ b/pkg/microservice/aslan/core/release_plan/service/release_plan.go @@ -176,7 +176,7 @@ func GetReleasePlan(id string) (*models.ReleasePlan, error) { releasePlan.Approval.NativeApproval.DetailedApproveUsers = approvalUsers } - return mongodb.NewReleasePlanColl().GetByID(context.Background(), id) + return releasePlan, nil } func GetReleasePlanLogs(id string) ([]*models.ReleasePlanLog, error) { From d8f9cfa8ad4c24484d4e9449ff012944cf8d1fd2 Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 28 Mar 2024 15:35:52 +0800 Subject: [PATCH 8/9] optimize approver code --- .../common/repository/models/workflow_v4.go | 10 +- .../core/release_plan/service/approval.go | 114 ++++++++++-------- .../core/release_plan/service/release_plan.go | 45 ++----- 3 files changed, 78 insertions(+), 91 deletions(-) diff --git a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go index c358e239b0..eead3d7d15 100644 --- a/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go +++ b/pkg/microservice/aslan/core/common/repository/models/workflow_v4.go @@ -110,11 +110,11 @@ type Approval struct { } type NativeApproval struct { - Timeout int `bson:"timeout" yaml:"timeout" json:"timeout"` - ApproveUsers []*User `bson:"approve_users" yaml:"approve_users" json:"approve_users"` - DetailedApproveUsers []*User `bson:"-" yaml:"detailed_approve_users" json:"detailed_approve_users"` - NeededApprovers int `bson:"needed_approvers" yaml:"needed_approvers" json:"needed_approvers"` - RejectOrApprove config.ApproveOrReject `bson:"reject_or_approve" yaml:"-" json:"reject_or_approve"` + Timeout int `bson:"timeout" yaml:"timeout" json:"timeout"` + ApproveUsers []*User `bson:"approve_users" yaml:"approve_users" json:"approve_users"` + FloatApproveUsers []*User `bson:"-" yaml:"flat_approve_users" json:"flat_approve_users"` + NeededApprovers int `bson:"needed_approvers" yaml:"needed_approvers" json:"needed_approvers"` + RejectOrApprove config.ApproveOrReject `bson:"reject_or_approve" yaml:"-" json:"reject_or_approve"` // InstanceCode: native approval instance code, save for working after restart aslan InstanceCode string `bson:"instance_code" yaml:"instance_code" json:"instance_code"` } diff --git a/pkg/microservice/aslan/core/release_plan/service/approval.go b/pkg/microservice/aslan/core/release_plan/service/approval.go index abff96fa23..ad1d0a488f 100644 --- a/pkg/microservice/aslan/core/release_plan/service/approval.go +++ b/pkg/microservice/aslan/core/release_plan/service/approval.go @@ -212,53 +212,16 @@ func updateDingTalkApproval(ctx context.Context, approvalInfo *models.Approval) return nil } -func createNativeApproval(plan *models.ReleasePlan, url string) error { - if plan == nil || plan.Approval == nil || plan.Approval.NativeApproval == nil { - return errors.New("createNativeApproval: native approval data not found") - } - approval := plan.Approval.NativeApproval - - var err error - mailNotifyInfo := "" - var email *systemconfig.Email - for { - email, err = systemconfig.New().GetEmailHost() - if err != nil { - log.Errorf("CreateNativeApproval GetEmailHost error, error msg:%s", err) - break - } - - t, err := template.New("approval").Parse(string(approvalHTML)) - if err != nil { - log.Errorf("CreateNativeApproval template parse error, error msg:%s", err) - break - } - var buf bytes.Buffer - err = t.Execute(&buf, struct { - PlanName string - Manager string - Description string - TimeRange string - Url string - }{ - PlanName: plan.Name, - Manager: plan.Manager, - Description: plan.Description, - TimeRange: time.Unix(plan.StartTime, 0).Format("2006-01-02 15:04:05") + "-" + time.Unix(plan.EndTime, 0).Format("2006-01-02 15:04:05"), - Url: url, - }) - if err != nil { - log.Errorf("CreateNativeApproval template execute error, error msg:%s", err) - break - } - mailNotifyInfo = buf.String() - break - } - +func geneFlatNativeApprovalUsers(approval *models.NativeApproval) ([]*models.User, map[string]*types.UserInfo) { // change [group + user] approvals to user approvals approvalUsers := make([]*models.User, 0) userSet := sets.NewString() userMap := make(map[string]*types.UserInfo) + + if approval == nil { + return approvalUsers, userMap + } + for _, u := range approval.ApproveUsers { if u.Type == "user" || u.Type == "" { userSet.Insert(u.UserID) @@ -292,11 +255,65 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { } } - if email != nil { - for _, uid := range userSet.List() { - info, ok := userMap[uid] + return approvalUsers, userMap +} + +func createNativeApproval(plan *models.ReleasePlan, url string) error { + if plan == nil || plan.Approval == nil || plan.Approval.NativeApproval == nil { + return errors.New("createNativeApproval: native approval data not found") + } + approval := plan.Approval.NativeApproval + + approvalUsers, userMap := geneFlatNativeApprovalUsers(approval) + + // send email to all approval users if necessary + go func() { + var err error + mailNotifyInfo := "" + var email *systemconfig.Email + + for { + email, err = systemconfig.New().GetEmailHost() + if err != nil { + log.Errorf("CreateNativeApproval GetEmailHost error, error msg:%s", err) + break + } + + t, err := template.New("approval").Parse(string(approvalHTML)) + if err != nil { + log.Errorf("CreateNativeApproval template parse error, error msg:%s", err) + break + } + var buf bytes.Buffer + err = t.Execute(&buf, struct { + PlanName string + Manager string + Description string + TimeRange string + Url string + }{ + PlanName: plan.Name, + Manager: plan.Manager, + Description: plan.Description, + TimeRange: time.Unix(plan.StartTime, 0).Format("2006-01-02 15:04:05") + "-" + time.Unix(plan.EndTime, 0).Format("2006-01-02 15:04:05"), + Url: url, + }) + if err != nil { + log.Errorf("CreateNativeApproval template execute error, error msg:%s", err) + break + } + mailNotifyInfo = buf.String() + break + } + + if email == nil { + return + } + + for _, u := range approvalUsers { + info, ok := userMap[u.UserID] if !ok { - info, err = user.New().GetUserByID(uid) + info, err = user.New().GetUserByID(u.UserID) if err != nil { log.Warnf("CreateNativeApproval GetUserByUid error, error msg:%s", err) continue @@ -322,11 +339,10 @@ func createNativeApproval(plan *models.ReleasePlan, url string) error { continue } } - } + }() originApprovalUser := approval.ApproveUsers approval.ApproveUsers = approvalUsers - approval.DetailedApproveUsers = approvalUsers approveKey := uuid.New().String() approval.InstanceCode = approveKey diff --git a/pkg/microservice/aslan/core/release_plan/service/release_plan.go b/pkg/microservice/aslan/core/release_plan/service/release_plan.go index 361a26e8bf..c10b2a8057 100644 --- a/pkg/microservice/aslan/core/release_plan/service/release_plan.go +++ b/pkg/microservice/aslan/core/release_plan/service/release_plan.go @@ -18,7 +18,6 @@ package service import ( "context" - "k8s.io/apimachinery/pkg/util/sets" "time" "github.com/gin-gonic/gin" @@ -137,43 +136,11 @@ func GetReleasePlan(id string) (*models.ReleasePlan, error) { return nil, errors.Wrap(err, "GetReleasePlan") } - // TODO write detailed approval data into DB + // native approval users may be user or user groups + // convert to flat user when needed, this data is generated dynamically because group binding may be changed if releasePlan.Approval != nil && releasePlan.Approval.NativeApproval != nil { - approval := releasePlan.Approval.NativeApproval - approvalUsers := make([]*models.User, 0) - userSet := sets.NewString() - for _, u := range approval.ApproveUsers { - if u.Type == "user" || u.Type == "" { - userSet.Insert(u.UserID) - approvalUsers = append(approvalUsers, u) - } - } - for _, u := range approval.ApproveUsers { - if u.Type == "group" { - groupInfo, err := user.New().GetGroupDetailedInfo(u.GroupID) - if err != nil { - log.Warnf("CreateNativeApproval GetGroupDetailedInfo error, error msg:%s", err) - continue - } - for _, uid := range groupInfo.UIDs { - if userSet.Has(uid) { - continue - } - userSet.Insert(uid) - userDetailedInfo, err := user.New().GetUserByID(uid) - if err != nil { - log.Errorf("failed to find user %s, error: %s", uid, err) - continue - } - approvalUsers = append(approvalUsers, &models.User{ - Type: "user", - UserID: uid, - UserName: userDetailedInfo.Name, - }) - } - } - } - releasePlan.Approval.NativeApproval.DetailedApproveUsers = approvalUsers + flatNativeApprovalUsers, _ := geneFlatNativeApprovalUsers(releasePlan.Approval.NativeApproval) + releasePlan.Approval.NativeApproval.FloatApproveUsers = flatNativeApprovalUsers } return releasePlan, nil @@ -448,7 +415,11 @@ func ApproveReleasePlan(c *handler.Context, planID string, req *ApproveRequest) if !ok { // restore data after restart aslan log.Infof("updateNativeApproval: approval instance code %s not found, set it", plan.Approval.NativeApproval.InstanceCode) + approvalUsers, _ := geneFlatNativeApprovalUsers(plan.Approval.NativeApproval) + originApprovalUsers := plan.Approval.NativeApproval.ApproveUsers + plan.Approval.NativeApproval.ApproveUsers = approvalUsers approvalservice.GlobalApproveMap.SetApproval(plan.Approval.NativeApproval.InstanceCode, plan.Approval.NativeApproval) + plan.Approval.NativeApproval.ApproveUsers = originApprovalUsers } approval, err = approvalservice.GlobalApproveMap.DoApproval(approvalKey, c.UserName, c.UserID, req.Comment, req.Approve) From c2680ea9c554707285615a3b8e383607e7650b54 Mon Sep 17 00:00:00 2001 From: allenshen Date: Thu, 28 Mar 2024 16:06:06 +0800 Subject: [PATCH 9/9] optimize code --- .../collaboration/service/collaboration_instance.go | 2 +- .../core/collaboration/service/collaboration_mode.go | 1 + .../aslan/core/common/service/approval/approval.go | 1 - .../aslan/core/release_plan/service/approval.go | 10 +++++----- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go b/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go index 0102bdca15..87ee4d8dd9 100644 --- a/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go +++ b/pkg/microservice/aslan/core/collaboration/service/collaboration_instance.go @@ -18,7 +18,6 @@ package service import ( "fmt" - "github.com/koderover/zadig/v2/pkg/shared/client/user" "reflect" "time" @@ -37,6 +36,7 @@ import ( config2 "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/label/config" workflowservice "github.com/koderover/zadig/v2/pkg/microservice/aslan/core/workflow/service/workflow" "github.com/koderover/zadig/v2/pkg/setting" + "github.com/koderover/zadig/v2/pkg/shared/client/user" "github.com/koderover/zadig/v2/pkg/tool/log" ) diff --git a/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go b/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go index 7ca1af018b..740cfdc60e 100644 --- a/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go +++ b/pkg/microservice/aslan/core/collaboration/service/collaboration_mode.go @@ -18,6 +18,7 @@ package service import ( "fmt" + "go.mongodb.org/mongo-driver/mongo" "go.uber.org/zap" "k8s.io/apimachinery/pkg/util/sets" diff --git a/pkg/microservice/aslan/core/common/service/approval/approval.go b/pkg/microservice/aslan/core/common/service/approval/approval.go index 9ab4c8dda9..155552936d 100644 --- a/pkg/microservice/aslan/core/common/service/approval/approval.go +++ b/pkg/microservice/aslan/core/common/service/approval/approval.go @@ -85,7 +85,6 @@ func (c *GlobalApproveManager) DoApproval(key, userName, userID, comment string, meetUser := false for _, user := range approvalData.ApproveUsers { - // for release plan approvals we need to if user.UserID != userID { continue } diff --git a/pkg/microservice/aslan/core/release_plan/service/approval.go b/pkg/microservice/aslan/core/release_plan/service/approval.go index ad1d0a488f..981c1b5949 100644 --- a/pkg/microservice/aslan/core/release_plan/service/approval.go +++ b/pkg/microservice/aslan/core/release_plan/service/approval.go @@ -21,17 +21,17 @@ import ( "context" _ "embed" "fmt" - "github.com/koderover/zadig/v2/pkg/shared/client/systemconfig" - "github.com/koderover/zadig/v2/pkg/shared/client/user" - "github.com/koderover/zadig/v2/pkg/tool/mail" - "github.com/koderover/zadig/v2/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" "net/url" "text/template" "time" "github.com/google/uuid" + "github.com/koderover/zadig/v2/pkg/shared/client/systemconfig" + "github.com/koderover/zadig/v2/pkg/shared/client/user" + "github.com/koderover/zadig/v2/pkg/tool/mail" + "github.com/koderover/zadig/v2/pkg/types" "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/sets" configbase "github.com/koderover/zadig/v2/pkg/config" "github.com/koderover/zadig/v2/pkg/microservice/aslan/config"