From bd94e4b035fb375778237b2370c257a71be6c95a Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Wed, 10 May 2023 12:26:00 +0200 Subject: [PATCH 1/2] Add `recipient.Key#CopyNonNil()` method --- internal/recipient/recipient.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/internal/recipient/recipient.go b/internal/recipient/recipient.go index 74b9421f..a636f244 100644 --- a/internal/recipient/recipient.go +++ b/internal/recipient/recipient.go @@ -33,6 +33,24 @@ func (r Key) MarshalText() (text []byte, err error) { } } +// CopyNonNil copies non-nil fields from the provided recipient.Key to the current one and +// returns the modified recipient key. +func (r Key) CopyNonNil(recipientKey Key) Key { + if !r.ContactID.Valid && recipientKey.ContactID.Valid { + r.ContactID = recipientKey.ContactID + } + + if !r.GroupID.Valid && recipientKey.GroupID.Valid { + r.GroupID = recipientKey.GroupID + } + + if !r.ScheduleID.Valid && recipientKey.ScheduleID.Valid { + r.ScheduleID = recipientKey.ScheduleID + } + + return r +} + func ToKey(r Recipient) Key { switch v := r.(type) { case *Contact: From 272efd52ac6d4dbc67946ff14f3a92e7f1d4d94b Mon Sep 17 00:00:00 2001 From: Yonas Habteab Date: Wed, 10 May 2023 12:26:31 +0200 Subject: [PATCH 2/2] Write also `schedule/contactgroup_id` for contact notified histories --- internal/listener/listener.go | 67 +++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/internal/listener/listener.go b/internal/listener/listener.go index 7397480b..8dcadb2a 100644 --- a/internal/listener/listener.go +++ b/internal/listener/listener.go @@ -399,6 +399,9 @@ func (l *Listener) ProcessEvent(w http.ResponseWriter, req *http.Request) { contactChannels := make(map[*recipient.Contact]map[string]struct{}) escalationRecipients := make(map[recipient.Key]bool) + groupsOrSchedules := make(map[*recipient.Contact]recipient.Key) + groupsOrSchedulesWithoutMembers := make(map[recipient.Recipient]bool) + for escalationID, state := range currentIncident.EscalationState { escalation := l.runtimeConfig.GetRuleEscalation(escalationID) if state.TriggeredAt.Time().IsZero() { @@ -447,7 +450,14 @@ func (l *Listener) ProcessEvent(w http.ResponseWriter, req *http.Request) { escalationRecipients[escalationRecipient.Key] = true if !managed || state.Role > incident.RoleRecipient { - for _, c := range escalationRecipient.Recipient.GetContactsAt(ev.Time) { + r := escalationRecipient.Recipient + _, isContact := r.(*recipient.Contact) + contacts := r.GetContactsAt(ev.Time) + for _, c := range contacts { + if !isContact { + groupsOrSchedules[c] = recipient.ToKey(r) + } + if contactChannels[c] == nil { contactChannels[c] = make(map[string]struct{}) } @@ -457,6 +467,10 @@ func (l *Listener) ProcessEvent(w http.ResponseWriter, req *http.Request) { contactChannels[c][c.DefaultChannel] = struct{}{} } } + + if !isContact && len(contacts) == 0 { + groupsOrSchedulesWithoutMembers[r] = true + } } } } @@ -469,25 +483,43 @@ func (l *Listener) ProcessEvent(w http.ResponseWriter, req *http.Request) { isEscalationRecipient := escalationRecipients[recipientKey] if !isEscalationRecipient && (!managed || state.Role > incident.RoleRecipient) { - for _, contact := range r.GetContactsAt(ev.Time) { + _, isContact := r.(*recipient.Contact) + contacts := r.GetContactsAt(ev.Time) + for _, contact := range contacts { + if !isContact { + groupsOrSchedules[contact] = recipient.ToKey(r) + } + if contactChannels[contact] == nil { contactChannels[contact] = make(map[string]struct{}) } contactChannels[contact][contact.DefaultChannel] = struct{}{} } + + if !isContact && len(contacts) == 0 { + groupsOrSchedulesWithoutMembers[r] = true + } } } for contact, channels := range contactChannels { + rk := recipient.ToKey(contact) + hr := &incident.HistoryRow{ + EventID: utils.ToDBInt(ev.ID), + Time: types.UnixMilli(ev.Time), + Type: incident.Notified, + CausedByIncidentHistoryID: causedByIncidentHistoryId, + } + + groupOrSchedule := groupsOrSchedules[contact] + if groupsOrSchedules != nil { + rk = rk.CopyNonNil(groupOrSchedule) + } + + hr.Key = rk + for chType := range channels { - hr := &incident.HistoryRow{ - Key: recipient.ToKey(contact), - EventID: utils.ToDBInt(ev.ID), - Time: types.UnixMilli(time.Now()), - Type: incident.Notified, - ChannelType: utils.ToDBString(chType), - CausedByIncidentHistoryID: causedByIncidentHistoryId, - } + hr.ChannelType = utils.ToDBString(chType) l.logger.Infof("[%s %s] notify %q via %q", obj.DisplayName(), currentIncident.String(), contact.FullName, chType) @@ -516,6 +548,21 @@ func (l *Listener) ProcessEvent(w http.ResponseWriter, req *http.Request) { } } + for gs, _ := range groupsOrSchedulesWithoutMembers { + hr := &incident.HistoryRow{ + Key: recipient.ToKey(gs), + EventID: utils.ToDBInt(ev.ID), + Time: types.UnixMilli(ev.Time), + Type: incident.Notified, + CausedByIncidentHistoryID: causedByIncidentHistoryId, + } + + _, err = currentIncident.AddHistory(hr, false) + if err != nil { + l.logger.Errorln(err) + } + } + _, _ = fmt.Fprintln(w) }