diff --git a/cmd/climc/shell/notifyv2/config.go b/cmd/climc/shell/notifyv2/config.go index 9a2e494a62..3db4eb8b9a 100644 --- a/cmd/climc/shell/notifyv2/config.go +++ b/cmd/climc/shell/notifyv2/config.go @@ -106,6 +106,18 @@ func init() { printObject(data) return nil }) + type ConfigGetTypesOptions struct { + Robot string `json:"robot" choices:"yes|no|only"` + } + R(&ConfigGetTypesOptions{}, "notify-config-get-types", "Get all Config types", func(s *mcclient.ClientSession, args *ConfigGetTypesOptions) error { + param := jsonutils.Marshal(args) + result, err := modules.NotifyConfig.PerformClassAction(s, "get-types", param) + if err != nil { + return err + } + printObject(result) + return nil + }) } func configIdFromType(s *mcclient.ClientSession, t string) (string, error) { diff --git a/pkg/apis/notify/config.go b/pkg/apis/notify/config.go index 86efdd7d38..c56f7b261c 100644 --- a/pkg/apis/notify/config.go +++ b/pkg/apis/notify/config.go @@ -68,3 +68,14 @@ type ConfigValidateOutput struct { IsValid bool `json:"is_valid"` Message string `json:"message"` } + +type ConfigManagerGetTypesInput struct { + // description: Filter about robot + // enum: no,yes,only + // example: yes + Robot string `json:"robot"` +} + +type ConfigManagerGetTypesOutput struct { + Types []string `json:"types"` +} diff --git a/pkg/cloudcommon/notifyclient/notify.go b/pkg/cloudcommon/notifyclient/notify.go index e29625ca4f..b96cb924d3 100644 --- a/pkg/cloudcommon/notifyclient/notify.go +++ b/pkg/cloudcommon/notifyclient/notify.go @@ -142,6 +142,7 @@ func NotifyNormal(recipientId []string, isGroup bool, event string, data jsonuti notify.NotifyByDingTalk, notify.NotifyByWebConsole, notify.NotifyByFeishu, + notify.NotifyByWorkwx, } { RawNotify(recipientId, isGroup, c, @@ -157,6 +158,7 @@ func NotifyImportant(recipientId []string, isGroup bool, event string, data json notify.NotifyByMobile, notify.NotifyByWebConsole, notify.NotifyByFeishu, + notify.NotifyByWorkwx, } { RawNotify(recipientId, isGroup, c, @@ -172,6 +174,7 @@ func NotifyCritical(recipientId []string, isGroup bool, event string, data jsonu notify.NotifyByMobile, notify.NotifyByWebConsole, notify.NotifyByFeishu, + notify.NotifyByWorkwx, } { RawNotify(recipientId, isGroup, c, @@ -180,6 +183,32 @@ func NotifyCritical(recipientId []string, isGroup bool, event string, data jsonu } } +// NotifyAllWithoutRobot will send messages via all contacnt type from exclude robot contact type such as dingtalk-robot. +func NotifyAllWithoutRobot(recipientId []string, isGroup bool, priority notify.TNotifyPriority, event string, data jsonutils.JSONObject) error { + return notifyRobot("no", recipientId, isGroup, priority, event, data) +} + +// NotifyRobot will send messages via all robot contact type such as dingtalk-robot. +func NotifyRobot(recipientId []string, isGroup bool, priority notify.TNotifyPriority, event string, data jsonutils.JSONObject) error { + return notifyRobot("only", recipientId, isGroup, priority, event, data) +} + +func notifyRobot(robot string, recipientId []string, isGroup bool, priority notify.TNotifyPriority, event string, data jsonutils.JSONObject) error { + s := auth.GetAdminSession(context.Background(), consts.GetRegion(), "") + params := jsonutils.NewDict() + params.Set("robot", jsonutils.NewString(robot)) + result, err := modules.NotifyConfig.PerformClassAction(s, "get-types", params) + if err != nil { + return err + } + jarray, _ := result.Get("types") + cTypes := jarray.(*jsonutils.JSONArray).GetStringArray() + for _, ct := range cTypes { + RawNotify(recipientId, isGroup, notify.TNotifyChannel(ct), priority, event, data) + } + return nil +} + func SystemNotify(priority notify.TNotifyPriority, event string, data jsonutils.JSONObject) { // userId Notify(notifyAdminUsers, false, priority, event, data) diff --git a/pkg/mcclient/modules/notify/consts.go b/pkg/mcclient/modules/notify/consts.go index e973c926e8..456be0640d 100644 --- a/pkg/mcclient/modules/notify/consts.go +++ b/pkg/mcclient/modules/notify/consts.go @@ -28,4 +28,5 @@ const ( NotifyByDingTalk = TNotifyChannel("dingtalk") NotifyByWebConsole = TNotifyChannel("webconsole") NotifyByFeishu = TNotifyChannel("feishu") + NotifyByWorkwx = TNotifyChannel("workwx") ) diff --git a/pkg/notify/models/config.go b/pkg/notify/models/config.go index 33fb20dd21..a8d0f202cf 100644 --- a/pkg/notify/models/config.go +++ b/pkg/notify/models/config.go @@ -17,6 +17,7 @@ package models import ( "context" "database/sql" + "strings" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -132,6 +133,55 @@ func (c *SConfig) PostUpdate(ctx context.Context, userCred mcclient.TokenCredent NotifyService.RestartService(ctx, configMap, c.Type) } +func (cm *SConfigManager) AllowPerformGetTypes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return true +} + +func (cm *SConfigManager) PerformGetTypes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ConfigManagerGetTypesInput) (api.ConfigManagerGetTypesOutput, error) { + output := api.ConfigManagerGetTypesOutput{} + allContactType, err := cm.allContactType() + if err != nil { + return output, err + } + var judge func(string) bool + switch input.Robot { + case "only": + judge = func(ctype string) bool { + return strings.Contains(ctype, "robot") + } + case "yes": + judge = func(ctype string) bool { + return true + } + default: + judge = func(ctype string) bool { + return !strings.Contains(ctype, "robot") + } + } + for _, ctype := range allContactType { + if judge(ctype) { + output.Types = append(output.Types, ctype) + } + } + return output, nil +} + +func (cm *SConfigManager) allContactType() ([]string, error) { + q := cm.Query("type") + allTypes := make([]struct { + Type string + }, 0, 3) + err := q.All(&allTypes) + if err != nil { + return nil, err + } + ret := make([]string, len(allTypes)) + for i := range ret { + ret[i] = allTypes[i].Type + } + return ret, nil +} + func (self *SConfigManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.ConfigListInput) (*sqlchemy.SQuery, error) { q, err := self.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneResourceListInput) if err != nil { diff --git a/pkg/notify/models/notification.go b/pkg/notify/models/notification.go index b10d1f0c66..97afc06ba2 100644 --- a/pkg/notify/models/notification.go +++ b/pkg/notify/models/notification.go @@ -24,6 +24,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/sets" + "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/notify" @@ -71,6 +72,14 @@ type SNotification struct { } func (nm *SNotificationManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NotificationCreateInput) (api.NotificationCreateInput, error) { + // check contact type enabled + allContactType, err := ConfigManager.allContactType() + if err != nil { + return input, err + } + if !utils.IsInStringArray(input.ContactType, allContactType) { + return input, httperrors.NewInputParameterError("Unconfigured contact type %q", input.ContactType) + } // check uids, rids and contacts if len(input.Receivers) == 0 && len(input.Contacts) == 0 { return input, httperrors.NewMissingParameterError("receivers | contacts") diff --git a/pkg/notify/models/receiver.go b/pkg/notify/models/receiver.go index 8a3d635b5e..20848373f8 100644 --- a/pkg/notify/models/receiver.go +++ b/pkg/notify/models/receiver.go @@ -119,6 +119,9 @@ func (rm *SReceiverManager) InitializeData() error { if err != nil { return errors.Wrap(err, "db.FetchModelObjects") } + if len(contacts) == 0 { + return nil + } // build uid map uids := make([]string, 0, 10) @@ -186,6 +189,7 @@ func (rm *SReceiverManager) InitializeData() error { webconsole = true subContact.Contact = uid } else { + subContact.ParentContactType = api.MOBILE subContact.Contact = contact.Contact } subContact.ReceiverID = uid @@ -338,11 +342,15 @@ func (r *SReceiver) setEnabledContactType(contactType string, enabled bool) { if sc, ok := r.subContactCache[contactType]; ok { sc.Enabled = tristate.NewFromBool(enabled) } else { - r.subContactCache[contactType] = &SSubContact{ + subContact := &SSubContact{ Type: contactType, ReceiverID: r.Id, Enabled: tristate.NewFromBool(enabled), } + if contactType != api.WEBCONSOLE { + subContact.ParentContactType = api.MOBILE + } + r.subContactCache[contactType] = subContact } } } @@ -369,10 +377,15 @@ func (r *SReceiver) MarkContactTypeVerified(contactType string) error { if sc, ok := r.subContactCache[contactType]; ok { sc.Verified = tristate.True } else { - r.subContactCache[contactType] = &SSubContact{ + subContact := &SSubContact{ + Type: contactType, ReceiverID: r.Id, - Verified: tristate.True, + Enabled: tristate.True, } + if contactType != api.WEBCONSOLE { + subContact.ParentContactType = api.MOBILE + } + r.subContactCache[contactType] = subContact } return nil } @@ -387,10 +400,15 @@ func (r *SReceiver) setVerifiedContactType(contactType string, enabled bool) { if sc, ok := r.subContactCache[contactType]; ok { sc.Verified = tristate.NewFromBool(enabled) } else { - r.subContactCache[contactType] = &SSubContact{ + subContact := &SSubContact{ + Type: contactType, ReceiverID: r.Id, Verified: tristate.NewFromBool(enabled), } + if contactType != api.WEBCONSOLE { + subContact.ParentContactType = api.MOBILE + } + r.subContactCache[contactType] = subContact } } } @@ -630,7 +648,7 @@ func (r *SReceiver) PreUpdate(ctx context.Context, userCred mcclient.TokenCreden if len(input.Email) != 0 && input.Email != r.Email { r.VerifiedEmail = tristate.False for _, c := range r.subContactCache { - if c.ParentContactType == input.Email { + if c.ParentContactType == api.EMAIL { c.Verified = tristate.False } } @@ -638,7 +656,7 @@ func (r *SReceiver) PreUpdate(ctx context.Context, userCred mcclient.TokenCreden if len(input.Mobile) != 0 && input.Mobile != r.Mobile { r.VerifiedMobile = tristate.False for _, c := range r.subContactCache { - if c.ParentContactType == input.Mobile { + if c.ParentContactType == api.MOBILE { c.Verified = tristate.False } }