194 строки
5.3 KiB
Go
194 строки
5.3 KiB
Go
package models
|
|
|
|
import (
|
|
"log"
|
|
"time"
|
|
|
|
"rsgit.ru/rsmon/rsmon/app/models/concerns"
|
|
"rsgit.ru/rsmon/rsmon/internal/workdays"
|
|
)
|
|
|
|
// Notification provides functionality.
|
|
type Notification struct {
|
|
concerns.Model
|
|
|
|
Name string `json:"name" gorm:"not null"`
|
|
AccountID int64 `gorm:"type:bigint REFERENCES accounts(id)" json:"account_id"`
|
|
Account *Account `json:"-"`
|
|
Enabled bool `gorm:"not null;default:true" json:"enabled"`
|
|
ContactIDs []int64 `gorm:"-:all" json:"contact_ids"`
|
|
Contacts []Contact `gorm:"many2many:notification_contacts;" json:"contacts,omitempty"`
|
|
GroupIDs []int64 `gorm:"-:all" json:"group_ids"`
|
|
Groups []Group `gorm:"many2many:notification_groups;" json:"-"`
|
|
AlertDelay *int64 `json:"alert_delay,omitempty"`
|
|
// RepeatAlert *int64 `json:"repeat_alert,omitempty"`
|
|
BeforeExpiration *int64 `json:"before_expiration,omitempty"`
|
|
|
|
NotifyDown bool `gorm:"default:true" json:"notify_down"`
|
|
NotifyRestore bool `gorm:"default:true" json:"notify_restore"`
|
|
|
|
NotifyWHOIS bool `gorm:"default:true" json:"notify_whois"`
|
|
NotifySSL bool `gorm:"default:true" json:"notify_ssl"`
|
|
|
|
NotifyDays *int `json:"notify_days"`
|
|
NotifyDayStart *int `json:"notify_day_start"`
|
|
NotifyDayEnd *int `json:"notify_day_end"`
|
|
NotifyHolidays bool `gorm:"default:true" json:"notify_holidays"`
|
|
|
|
Messages []Message `json:"-"`
|
|
|
|
concerns.Timestamped
|
|
Audited
|
|
}
|
|
|
|
const notificationDebug = false
|
|
|
|
// EnabledNow checks if the notification is enabled at the given time.
|
|
func (n *Notification) EnabledNow(tn *time.Time) bool {
|
|
weekday := int(tn.Weekday())
|
|
// делаем из 0-воскр 1-пн 6-сб вариант 0-пн 6-воскр
|
|
if weekday == 0 {
|
|
weekday = 7
|
|
}
|
|
weekday--
|
|
if notificationDebug {
|
|
log.Println("notification", n.ID, "check enabled now at", tn, "for day", weekday)
|
|
}
|
|
|
|
if !n.NotifyHolidays {
|
|
c := workdays.GetCalendar()
|
|
if !c.IsWorkday(*tn) {
|
|
if notificationDebug {
|
|
log.Println("notification", n.ID, "is not enabled on holiday", tn)
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
minusOneDay := false
|
|
notifyFromDay := true
|
|
|
|
if n.NotifyDayStart != nil && n.NotifyDayEnd != nil {
|
|
bod := BeginningOfDay(*tn)
|
|
secondsToday := int(tn.Sub(bod) / time.Second)
|
|
|
|
ds := *n.NotifyDayStart
|
|
de := *n.NotifyDayEnd
|
|
// вариант 9 утра - 2 часа ночи
|
|
if ds == de { //nolint:gocritic // complex condition chain
|
|
notifyFromDay = true
|
|
} else if ds > de {
|
|
// с 0 до DayEnd
|
|
if secondsToday < de { //nolint:gocritic // complex condition chain
|
|
minusOneDay = true
|
|
notifyFromDay = true
|
|
} else if secondsToday < ds {
|
|
// с DayEnd до DayStart
|
|
notifyFromDay = false
|
|
} else {
|
|
notifyFromDay = true
|
|
}
|
|
} else {
|
|
if secondsToday < ds { //nolint:gocritic // complex condition chain
|
|
// с 0 до DayStart
|
|
notifyFromDay = false
|
|
} else if secondsToday > de {
|
|
notifyFromDay = false
|
|
} else {
|
|
notifyFromDay = true
|
|
}
|
|
}
|
|
// log.Println(secondsToday)
|
|
}
|
|
|
|
if !notifyFromDay {
|
|
if notificationDebug {
|
|
log.Println("notification", n.ID, *n.NotifyDays, "is NOT enabled as notifyFromDay", tn)
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Если время 0-dayStart считаем что это прошлый день
|
|
if minusOneDay {
|
|
weekday--
|
|
if weekday < 0 {
|
|
weekday = 6
|
|
}
|
|
}
|
|
|
|
if n.NotifyDays != nil {
|
|
if !HasBit(*n.NotifyDays, uint(weekday)) {
|
|
if notificationDebug {
|
|
log.Println("notification", n.ID, *n.NotifyDays, "is NOT enabled on weekday", tn.Weekday(), weekday, tn)
|
|
}
|
|
return false
|
|
}
|
|
if notificationDebug {
|
|
log.Println("notification", n.ID, *n.NotifyDays, "is enabled on weekday", tn.Weekday(), weekday, tn)
|
|
}
|
|
}
|
|
|
|
if notificationDebug {
|
|
log.Println("notification", n.ID, *n.NotifyDays, "is enabled", tn)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// NotificationLoadIDs provides functionality.
|
|
func NotificationLoadIDs(notifications *[]Notification) {
|
|
for i, n := range *notifications { //nolint:gocritic // range copy is acceptable here
|
|
cids := make([]int64, len(n.Contacts))
|
|
for i, c := range n.Contacts { //nolint:gocritic // range copy is acceptable here
|
|
cids[i] = c.ID
|
|
}
|
|
(*notifications)[i].ContactIDs = cids
|
|
|
|
gids := make([]int64, len(n.Groups))
|
|
for j, g := range n.Groups { //nolint:gocritic // range copy is acceptable here
|
|
gids[j] = g.ID
|
|
}
|
|
(*notifications)[i].GroupIDs = gids
|
|
}
|
|
}
|
|
|
|
// PersistRelations provides functionality.
|
|
func (n *Notification) PersistRelations() error {
|
|
cts := make([]Contact, len(n.ContactIDs))
|
|
for i, c := range n.ContactIDs {
|
|
ct := Contact{}
|
|
ct.ID = c
|
|
cts[i] = ct
|
|
}
|
|
err := DB().Model(&n).Association("Contacts").Replace(cts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
grp := make([]Group, len(n.GroupIDs))
|
|
for i, g := range n.GroupIDs {
|
|
gr := Group{}
|
|
gr.ID = g
|
|
grp[i] = gr
|
|
}
|
|
err = DB().Model(&n).Association("Groups").Replace(grp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetContacts returns the contacts associated with this notification.
|
|
// Errors are logged and an empty slice is returned instead of panicking so
|
|
// that a single misconfigured notification cannot kill the scheduler goroutine
|
|
// that processes expiry alerts (see internal/notifier.RunExp).
|
|
func (n *Notification) GetContacts() []Contact {
|
|
contacts := make([]Contact, 0)
|
|
err := DB().Model(*n).Where("enabled = ?", true).Association("Contacts").Find(&contacts)
|
|
if err != nil {
|
|
log.Printf("notification %d: GetContacts failed: %v", n.ID, err)
|
|
return contacts
|
|
}
|
|
return contacts
|
|
}
|