Feature & Fix for Notify (#7714)

* feat(notify): Add 'get-types' action for ConfigManager

The List interface is only open to administrators,
because we don't want anyone other than administrators
to see the details of the notify configuration.
To let general user to kown available notification channels,
add 'get-types' actions of ConfigManager.

* feat(notify): Check the availability of contact type before creating notification

Creating notification with unconfigured contact type will fail at
sending message. Now, prevent creation in advance.

* feat(notify): Add workwx for NotifyNormal/Important/Critical

* feat(notify): Add Notify about robot in notifyclient

* fix(notify): Init ParentContactType for SSubContact

1. ParentContactType of SSubContact with webconsole type is empty.
2. ParentContactType of others SSubContact is mobile.

* fix(notify): Unverify SSubContact when ParentContactType match

* fix(notify): When no data is initialized, exit directly
This commit is contained in:
Rain Zheng
2020-09-02 16:10:06 +08:00
committed by GitHub
parent 74c8c6bfe2
commit 1ed65ddd1a
7 changed files with 136 additions and 6 deletions
+50
View File
@@ -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 {
+9
View File
@@ -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")
+24 -6
View File
@@ -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
}
}