fix(notify): add group_times for subscriber

This commit is contained in:
马鸿飞
2023-09-07 10:41:47 +08:00
parent a8626647a7
commit 7ff9c8bd7a
8 changed files with 107 additions and 58 deletions
+3 -2
View File
@@ -165,8 +165,9 @@ type SendParams struct {
DomainId string
RemoteTemplateParam SRemoteTemplateParam
GroupKey string
GroupTimes uint
ReceiverId string
// minutes
GroupTimes uint
ReceiverId string
}
type SRemoteTemplateParam struct {
+4
View File
@@ -57,6 +57,8 @@ type SubscriberCreateInput struct {
// description: scope
// enum: system,domain
Scope string
// minutes
GroupTimes *uint32
}
type SubscriberChangeInput struct {
@@ -72,6 +74,8 @@ type SubscriberChangeInput struct {
// description: Robot(Id or Name) which is required when the type is 'robot' will Subscribe TopicID
Robot string
// minutes
GroupTimes *uint32
}
type SubscriberListInput struct {
@@ -43,6 +43,8 @@ type SubscriberCreateOptions struct {
RoleScope string `help:"required if type is 'role'"`
Robot string `help:"required if type is 'robot'"`
Scope string `positional:"true"`
// minutes
GroupTimes int
}
func (sc *SubscriberCreateOptions) Params() (jsonutils.JSONObject, error) {
@@ -79,6 +81,8 @@ type SubscriberChangeOptions struct {
Role string
RoleScope string
Robot string
// minutes
GroupTimes *int
}
func (ssr *SubscriberChangeOptions) Params() (jsonutils.JSONObject, error) {
+47 -34
View File
@@ -163,7 +163,7 @@ func (n *SNotification) CustomizeCreate(ctx context.Context, userCred mcclient.T
return err
}
for i := range input.Receivers {
_, err := ReceiverNotificationManager.Create(ctx, userCred, input.Receivers[i], n.Id)
_, err := ReceiverNotificationManager.Create(ctx, userCred, input.Receivers[i], 0, n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.Create")
}
@@ -175,7 +175,7 @@ func (n *SNotification) CustomizeCreate(ctx context.Context, userCred mcclient.T
}
}
for i := range input.Robots {
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, input.Robots[i], n.Id)
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, input.Robots[i], 0, n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.CreateRobot")
}
@@ -214,36 +214,45 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
if topic == nil {
return output, nil
}
var receiverIds []string
receiverIds := make(map[string]uint32)
receiverIds1, err := SubscriberManager.getReceiversSent(ctx, topic.Id, input.ProjectDomainId, input.ProjectId)
if err != nil {
return output, errors.Wrap(err, "unable to get receive")
}
receiverIds = append(receiverIds, receiverIds1...)
for k, v := range receiverIds1 {
receiverIds[k] = v
}
// robot
var robots []string
robots := make(map[string]uint32)
_robots, err := SubscriberManager.robot(topic.Id, input.ProjectDomainId, input.ProjectId)
if err != nil {
if errors.Cause(err) != errors.ErrNotFound {
return output, errors.Wrapf(err, "unable fetch robot of subscription %q", topic.Id)
}
} else {
robots = append(robots, _robots...)
for robot, groupTime := range _robots {
robots[robot] = groupTime
}
}
var webhookRobots []string
realRobot := make(map[string]uint32)
if len(robots) > 0 {
robots = sets.NewString(robots...).UnsortedList()
rs, err := RobotManager.FetchByIdOrNames(ctx, robots...)
robotList := []string{}
for robot := range robots {
robotList = append(robotList, robot)
}
rs, err := RobotManager.FetchByIdOrNames(ctx, robotList...)
if err != nil {
return output, errors.Wrap(err, "unable to get robots")
}
robots, webhookRobots = make([]string, 0, len(rs)), make([]string, 0, 1)
webhookRobots = make([]string, 0, 1)
for i := range rs {
if rs[i].Type == api.ROBOT_TYPE_WEBHOOK {
webhookRobots = append(webhookRobots, rs[i].Id)
} else {
robots = append(robots, rs[i].Id)
realRobot[rs[i].Id] = robots[rs[i].Id]
}
}
}
@@ -252,26 +261,32 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
// append default receiver
if len(input.Event) == 0 {
receiverIds = append(receiverIds, input.ReceiverIds...)
for _, receiver := range input.ReceiverIds {
// receiverIds = append(receiverIds, api.SReceiverWithGroupTimes{ReceiverId: receiver})
if _, ok := receiverIds[receiver]; !ok {
receiverIds[receiver] = 0
}
}
}
// fillter non-existed receiver
receivers, err := ReceiverManager.FetchByIdOrNames(ctx, receiverIds...)
if err != nil {
return output, errors.Wrap(err, "unable to fetch receivers by ids")
receiverIdList := []string{}
for k, _ := range receiverIds {
receiverIdList = append(receiverIdList, k)
}
receivers, err := ReceiverManager.FetchByIdOrNames(ctx, receiverIdList...)
webconsoleContacts := sets.NewString()
idSet := sets.NewString()
for i := range receivers {
idSet.Insert(receivers[i].Id)
}
for _, re := range receiverIds {
if idSet.Has(re) {
continue
}
for re := range receiverIds {
webconsoleContacts.Insert(re)
}
receiverIds = idSet.UnsortedList()
realReceiverIds := make(map[string]uint32)
for _, id := range receiverIdList {
realReceiverIds[id] = receiverIds[id]
}
// create event
event, err := EventManager.CreateEvent(ctx, input.Event, topic.Id, message, string(input.Action), input.ResourceType, input.AdvanceDays)
if err != nil {
@@ -280,7 +295,7 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
if nm.needWebconsole([]STopic{*topic}) {
// webconsole
err = nm.create(ctx, userCred, api.WEBCONSOLE, receiverIds, webconsoleContacts.UnsortedList(), input.Priority, event.GetId(), topic.GetId(), topic.Type)
err = nm.create(ctx, userCred, api.WEBCONSOLE, realReceiverIds, webconsoleContacts.UnsortedList(), input.Priority, event.GetId(), topic.GetId(), topic.Type)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: api.WEBCONSOLE,
@@ -293,7 +308,7 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
if ct == api.MOBILE {
continue
}
err := nm.create(ctx, userCred, ct, receiverIds, nil, input.Priority, event.GetId(), topic.GetId(), topic.Type)
err := nm.create(ctx, userCred, ct, realReceiverIds, nil, input.Priority, event.GetId(), topic.GetId(), topic.Type)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: ct,
@@ -309,7 +324,7 @@ func (nm *SNotificationManager) PerformEventNotify(ctx context.Context, userCred
})
}
// robot
err = nm.createWithRobots(ctx, userCred, robots, input.Priority, event.GetId(), topic.Type)
err = nm.createWithRobots(ctx, userCred, realRobot, input.Priority, event.GetId(), topic.Type)
if err != nil {
output.FailedList = append(output.FailedList, api.FailedElem{
ContactType: api.ROBOT,
@@ -328,7 +343,7 @@ func (nm *SNotificationManager) needWebconsole(topics []STopic) bool {
return false
}
func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.TokenCredential, contactType string, receiverIds, contacts []string, priority, eventId, topicId string, topicType string) error {
func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.TokenCredential, contactType string, receiverIds map[string]uint32, contacts []string, priority, eventId, topicId string, topicType string) error {
if len(receiverIds)+len(contacts) == 0 {
return nil
}
@@ -346,8 +361,8 @@ func (nm *SNotificationManager) create(ctx context.Context, userCred mcclient.To
if err != nil {
return errors.Wrap(err, "unable to insert Notification")
}
for i := range receiverIds {
_, err := ReceiverNotificationManager.Create(ctx, userCred, receiverIds[i], n.Id)
for receiver := range receiverIds {
_, err := ReceiverNotificationManager.Create(ctx, userCred, receiver, receiverIds[receiver], n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.Create")
}
@@ -381,7 +396,7 @@ func (nm *SNotificationManager) createWithWebhookRobots(ctx context.Context, use
}
n.Id = db.DefaultUUIDGenerator()
for i := range webhookRobotIds {
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, webhookRobotIds[i], n.Id)
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, webhookRobotIds[i], 0, n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.CreateRobot")
}
@@ -398,7 +413,7 @@ func (nm *SNotificationManager) createWithWebhookRobots(ctx context.Context, use
return task.ScheduleRun(nil)
}
func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred mcclient.TokenCredential, robotIds []string, priority, eventId string, topicType string) error {
func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred mcclient.TokenCredential, robotIds map[string]uint32, priority, eventId string, topicType string) error {
if len(robotIds) == 0 {
return nil
}
@@ -411,7 +426,7 @@ func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred m
}
n.Id = db.DefaultUUIDGenerator()
for i := range robotIds {
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, robotIds[i], n.Id)
_, err := ReceiverNotificationManager.CreateRobot(ctx, userCred, i, robotIds[i], n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.CreateRobot")
}
@@ -430,7 +445,7 @@ func (nm *SNotificationManager) createWithRobots(ctx context.Context, userCred m
return nil
}
func (n *SNotification) Create(ctx context.Context, userCred mcclient.TokenCredential, receiverIds, contacts []string) error {
func (n *SNotification) Create(ctx context.Context, userCred mcclient.TokenCredential, receiverIds map[string]uint32, contacts []string) error {
if len(receiverIds)+len(contacts) == 0 {
return nil
}
@@ -440,8 +455,8 @@ func (n *SNotification) Create(ctx context.Context, userCred mcclient.TokenCrede
if err != nil {
return errors.Wrap(err, "unable to insert Notification")
}
for i := range receiverIds {
_, err := ReceiverNotificationManager.Create(ctx, userCred, receiverIds[i], n.Id)
for receiver := range receiverIds {
_, err := ReceiverNotificationManager.Create(ctx, userCred, receiver, receiverIds[receiver], n.Id)
if err != nil {
return errors.Wrap(err, "ReceiverNotificationManager.Create")
}
@@ -713,7 +728,6 @@ func (n *SNotification) GetTemplate(ctx context.Context, topicId, lang string, n
groupKeys = *topic.GroupKeys
}
out.GroupTimes = uint(topic.GroupTimes)
rtStr, aStr, resultStr := event.ResourceType(), string(event.Action()), string(event.Result())
msgObj, err := jsonutils.ParseString(no.Message)
if err != nil {
@@ -741,7 +755,6 @@ func (n *SNotification) GetTemplate(ctx context.Context, topicId, lang string, n
out.GroupKey += keyValue
}
}
out.GroupTimes = uint(topic.GroupTimes)
if lang == "" {
lang = getLangSuffix(ctx)
}
+6 -2
View File
@@ -67,6 +67,8 @@ type SReceiverNotification struct {
SendBy string `width:"128"`
Status string `width:"36" charset:"ascii"`
FailedReason string `width:"1024"`
// minutes
GroupTimes uint32
}
func (self *SReceiverNotificationManager) InitializeData() error {
@@ -81,10 +83,11 @@ func (self *SReceiverNotification) GetReceiver() (*SReceiver, error) {
return recv.(*SReceiver), nil
}
func (rnm *SReceiverNotificationManager) Create(ctx context.Context, userCred mcclient.TokenCredential, receiverID, notificationID string) (*SReceiverNotification, error) {
func (rnm *SReceiverNotificationManager) Create(ctx context.Context, userCred mcclient.TokenCredential, receiverID string, groupTimes uint32, notificationID string) (*SReceiverNotification, error) {
rn := &SReceiverNotification{
ReceiverID: receiverID,
NotificationID: notificationID,
GroupTimes: groupTimes,
ReceiverType: api.RECEIVER_TYPE_USER,
Status: api.RECEIVER_NOTIFICATION_RECEIVED,
SendBy: userCred.GetUserId(),
@@ -92,13 +95,14 @@ func (rnm *SReceiverNotificationManager) Create(ctx context.Context, userCred mc
return rn, rnm.TableSpec().Insert(ctx, rn)
}
func (rnm *SReceiverNotificationManager) CreateRobot(ctx context.Context, userCred mcclient.TokenCredential, RobotID, notificationID string) (*SReceiverNotification, error) {
func (rnm *SReceiverNotificationManager) CreateRobot(ctx context.Context, userCred mcclient.TokenCredential, RobotID string, groupTimes uint32, notificationID string) (*SReceiverNotification, error) {
rn := &SReceiverNotification{
ReceiverID: RobotID,
NotificationID: notificationID,
ReceiverType: api.RECEIVER_TYPE_ROBOT,
Status: api.RECEIVER_NOTIFICATION_RECEIVED,
SendBy: userCred.GetUserId(),
GroupTimes: groupTimes,
}
return rn, rnm.TableSpec().Insert(ctx, rn)
}
+41 -12
View File
@@ -89,6 +89,8 @@ type SSubscriber struct {
ResourceAttributionName string `width:"128" charset:"utf8" list:"user" create:"optional"`
Scope string `width:"128" charset:"ascii" nullable:"false" create:"required"`
DomainId string `width:"128" charset:"ascii" nullable:"false" create:"optional"`
// minutes
GroupTimes uint32 `nullable:"true" list:"user" update:"user"`
}
func (sm *SSubscriberManager) validateReceivers(ctx context.Context, receivers []string) ([]string, error) {
@@ -227,6 +229,11 @@ func (sm *SSubscriberManager) ValidateCreateData(ctx context.Context, userCred m
return input, httperrors.NewForbiddenError("repeated with existing subscribers")
}
}
if input.GroupTimes != nil {
if *input.GroupTimes < 0 {
return input, httperrors.NewInputParameterError("invalidate group_times %d", input.GroupTimes)
}
}
return input, nil
}
@@ -308,6 +315,16 @@ func (s *SSubscriber) PerformChange(ctx context.Context, userCred mcclient.Token
return nil, errors.Wrap(err, "unable to update subscriber")
}
}
if input.GroupTimes != nil {
_, err := db.Update(s, func() error {
s.GroupTimes = *input.GroupTimes
return nil
})
if err != nil {
return nil, errors.Wrap(err, "unable to update subscriber group_times")
}
}
return nil, nil
}
@@ -433,14 +450,15 @@ func (s *SSubscriber) roleIdentification(ctx context.Context) (api.Identificatio
return ret, nil
}
func (srm *SSubscriberManager) robot(tid, projectDomainId, projectId string) ([]string, error) {
func (srm *SSubscriberManager) robot(tid, projectDomainId, projectId string) (map[string]uint32, error) {
srs, err := srm.findSuitableOnes(tid, projectDomainId, projectId, api.SUBSCRIBER_TYPE_ROBOT)
if err != nil {
return nil, err
}
robotIds := make([]string, len(srs))
robotIds := make(map[string]uint32)
for i := range srs {
robotIds[i] = srs[i].Identification
// robotIds[i] = srs[i].Identification
robotIds[srs[i].Identification] = srs[i].GroupTimes
}
return robotIds, nil
}
@@ -474,30 +492,34 @@ func (srm *SSubscriberManager) findSuitableOnes(tid, projectDomainId, projectId
}
// TODO: Use cache to increase speed
func (srm *SSubscriberManager) getReceiversSent(ctx context.Context, tid string, projectDomainId string, projectId string) ([]string, error) {
func (srm *SSubscriberManager) getReceiversSent(ctx context.Context, tid string, projectDomainId string, projectId string) (map[string]uint32, error) {
srs, err := srm.findSuitableOnes(tid, projectDomainId, projectId, api.SUBSCRIBER_TYPE_RECEIVER, api.SUBSCRIBER_TYPE_ROLE)
if err != nil {
return nil, err
}
receivers := make([]string, 0, len(srs))
receivers := make(map[string]uint32)
roleMap := make(map[string][]string, 3)
receivermap := make(map[string]*[]string, 3)
receivermap := make(map[string]map[string]uint32, 3)
identificationMapToSub := make(map[string]SSubscriber)
for _, sr := range srs {
if sr.Type == api.SUBSCRIBER_TYPE_RECEIVER {
rIds, err := sr.getReceivers()
if err != nil {
return nil, errors.Wrap(err, "unable to get receivers")
}
receivers = append(receivers, rIds...)
for _, receiveId := range rIds {
// receivers = append(receivers, api.SReceiverWithGroupTimes{ReceiverId: receiveId, GroupTimes: sr.GroupTimes})
receivers[receiveId] = sr.GroupTimes
}
} else if sr.Type == api.SUBSCRIBER_TYPE_ROLE {
identificationMapToSub[sr.Identification] = sr
roleMap[sr.RoleScope] = append(roleMap[sr.RoleScope], sr.Identification)
receivermap[sr.RoleScope] = &[]string{}
receivermap[sr.RoleScope] = map[string]uint32{}
}
}
errgo, _ := errgroup.WithContext(ctx)
for _scope, _roles := range roleMap {
scope, roles := _scope, _roles
receivers := receivermap[scope]
errgo.Go(func() error {
query := jsonutils.NewDict()
query.Set("roles", jsonutils.NewStringArray(roles))
@@ -528,7 +550,9 @@ func (srm *SSubscriberManager) getReceiversSent(ctx context.Context, tid string,
if err != nil {
return errors.Wrap(err, "unable to get user.id from result of RoleAssignments.List")
}
*receivers = append(*receivers, id)
if _, ok := receivermap[scope][id]; !ok {
receivermap[scope][id] = identificationMapToSub[scope].GroupTimes
}
}
}
return nil
@@ -538,11 +562,16 @@ func (srm *SSubscriberManager) getReceiversSent(ctx context.Context, tid string,
if err != nil {
return nil, err
}
for _, res := range receivermap {
receivers = append(receivers, *res...)
for receive, time := range res {
if _, ok := receivers[receive]; !ok {
receivers[receive] = time
}
}
}
// de-duplication
return sets.NewString(receivers...).UnsortedList(), nil
return receivers, nil
}
func (sr *SSubscriber) getReceivers() ([]string, error) {
-8
View File
@@ -82,7 +82,6 @@ type STopic struct {
ContentCn string `length:"medium" nullable:"true" charset:"utf8" list:"user" update:"user" create:"optional"`
ContentEn string `length:"medium" nullable:"true" charset:"utf8" list:"user" update:"user" create:"optional"`
GroupKeys *api.STopicGroupKeys `nullable:"true" list:"user" update:"user"`
GroupTimes uint32 `nullable:"true" list:"user" update:"user"`
AdvanceDays []int `nullable:"true" charset:"utf8" list:"user" update:"user" create:"optional"`
WebconsoleDisable tristate.TriState
@@ -316,7 +315,6 @@ func (sm *STopicManager) InitializeData() error {
t.TitleEn = api.COMMON_TITLE_EN
groupKeys := []string{"action_display"}
t.GroupKeys = (*api.STopicGroupKeys)(&groupKeys)
t.GroupTimes = 60
case DefaultSystemExceptionEvent:
t.addResources(
notify.TOPIC_RESOURCE_HOST,
@@ -391,7 +389,6 @@ func (sm *STopicManager) InitializeData() error {
t.TitleEn = api.SYNC_ACCOUNT_STATUS_TITLE_EN
groupKeys := []string{"name"}
t.GroupKeys = (*api.STopicGroupKeys)(&groupKeys)
t.GroupTimes = 60
case DefaultNetOutOfSync:
t.addResources(
notify.TOPIC_RESOURCE_NET,
@@ -407,7 +404,6 @@ func (sm *STopicManager) InitializeData() error {
t.TitleEn = api.NET_OUT_OF_SYNC_TITLE_EN
groupKeys := []string{"service_name"}
t.GroupKeys = (*api.STopicGroupKeys)(&groupKeys)
t.GroupTimes = 60
case DefaultMysqlOutOfSync:
t.addResources(
notify.TOPIC_RESOURCE_DBINSTANCE,
@@ -423,7 +419,6 @@ func (sm *STopicManager) InitializeData() error {
t.TitleEn = api.MYSQL_OUT_OF_SYNC_TITLE_EN
groupKeys := []string{"ip"}
t.GroupKeys = (*api.STopicGroupKeys)(&groupKeys)
t.GroupTimes = 60
case DefaultServiceAbnormal:
t.addResources(
notify.TOPIC_RESOURCE_SERVICE,
@@ -439,7 +434,6 @@ func (sm *STopicManager) InitializeData() error {
t.TitleEn = api.SERVICE_ABNORMAL_TITLE_EN
groupKeys := []string{"service_name"}
t.GroupKeys = (*api.STopicGroupKeys)(&groupKeys)
t.GroupTimes = 60
case DefaultServerPanicked:
t.addResources(
notify.TOPIC_RESOURCE_SERVER,
@@ -455,7 +449,6 @@ func (sm *STopicManager) InitializeData() error {
t.TitleEn = api.SERVER_PANICKED_TITLE_EN
groupKeys := []string{"name"}
t.GroupKeys = (*api.STopicGroupKeys)(&groupKeys)
t.GroupTimes = 60
case DefaultPasswordExpire:
t.addResources(
notify.TOPIC_RESOURCE_USER,
@@ -518,7 +511,6 @@ func (sm *STopicManager) InitializeData() error {
topic.Results = t.Results
topic.WebconsoleDisable = t.WebconsoleDisable
topic.GroupKeys = t.GroupKeys
topic.GroupTimes = t.GroupTimes
if len(topic.AdvanceDays) == 0 {
topic.AdvanceDays = t.AdvanceDays
}
@@ -264,6 +264,7 @@ func (notificationSendTask *NotificationSendTask) batchSend(ctx context.Context,
params.Header = robot.Header
params.Body = robot.Body
params.MsgKey = robot.MsgKey
params.GroupTimes = uint(receivers[i].rNotificaion.GroupTimes)
err = driver.Send(ctx, params)
if err != nil {
fails = append(fails, FailedReceiverSpec{ReceiverSpec: receivers[i], Reason: err.Error()})
@@ -271,6 +272,7 @@ func (notificationSendTask *NotificationSendTask) batchSend(ctx context.Context,
} else if receivers[i].receiver.IsReceiver() {
receiver := receivers[i].receiver.(*models.SReceiver)
params.Receivers.Contact, _ = receiver.GetContact(notification.ContactType)
params.GroupTimes = uint(receivers[i].rNotificaion.GroupTimes)
driver := models.GetDriver(notification.ContactType)
if notification.ContactType == apis.EMAIL {
params.EmailMsg = apis.SEmailMessage{