focalboard/server/services/notify/notifymentions/mentions_backend.go

144 lines
3.4 KiB
Go
Raw Normal View History

2021-09-13 21:36:36 +02:00
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package notifymentions
import (
"fmt"
"sync"
2021-09-13 21:36:36 +02:00
2021-10-27 03:11:19 +02:00
"github.com/mattermost/focalboard/server/model"
2021-09-13 21:36:36 +02:00
"github.com/mattermost/focalboard/server/services/notify"
"github.com/mattermost/focalboard/server/services/permissions"
2021-09-13 21:36:36 +02:00
"github.com/wiggin77/merror"
"github.com/mattermost/mattermost-server/v6/shared/mlog"
)
const (
backendName = "notifyMentions"
)
type MentionListener interface {
OnMention(userID string, evt notify.BlockChangeEvent)
}
// Backend provides the notification backend for @mentions.
2021-09-13 21:36:36 +02:00
type Backend struct {
delivery MentionDelivery
permissions permissions.PermissionsService
logger *mlog.Logger
mux sync.RWMutex
listeners []MentionListener
2021-09-13 21:36:36 +02:00
}
func New(delivery MentionDelivery, permissions permissions.PermissionsService, logger *mlog.Logger) *Backend {
2021-09-13 21:36:36 +02:00
return &Backend{
delivery: delivery,
permissions: permissions,
logger: logger,
2021-09-13 21:36:36 +02:00
}
}
func (b *Backend) Start() error {
return nil
}
func (b *Backend) ShutDown() error {
_ = b.logger.Flush()
return nil
}
func (b *Backend) Name() string {
return backendName
}
func (b *Backend) AddListener(l MentionListener) {
b.mux.Lock()
defer b.mux.Unlock()
b.listeners = append(b.listeners, l)
b.logger.Debug("Mention listener added.", mlog.Int("listener_count", len(b.listeners)))
}
func (b *Backend) RemoveListener(l MentionListener) {
b.mux.Lock()
defer b.mux.Unlock()
list := make([]MentionListener, 0, len(b.listeners))
for _, listener := range b.listeners {
if listener != l {
list = append(list, listener)
}
}
b.listeners = list
b.logger.Debug("Mention listener removed.", mlog.Int("listener_count", len(b.listeners)))
}
2021-09-13 21:36:36 +02:00
func (b *Backend) BlockChanged(evt notify.BlockChangeEvent) error {
if evt.Board == nil || evt.Card == nil {
return nil
}
if evt.Action == notify.Delete {
return nil
}
switch evt.BlockChanged.Type {
case model.TypeText, model.TypeComment, model.TypeImage:
default:
2021-09-13 21:36:36 +02:00
return nil
}
mentions := extractMentions(evt.BlockChanged)
if len(mentions) == 0 {
return nil
}
oldMentions := extractMentions(evt.BlockOld)
merr := merror.New()
b.mux.RLock()
listeners := make([]MentionListener, len(b.listeners))
copy(listeners, b.listeners)
b.mux.RUnlock()
2021-09-13 21:36:36 +02:00
for username := range mentions {
if _, exists := oldMentions[username]; exists {
// the mention already existed; no need to notify again
continue
}
extract := extractText(evt.BlockChanged.Title, username, newLimits())
userID, err := b.delivery.MentionDeliver(username, extract, evt)
2021-09-13 21:36:36 +02:00
if err != nil {
merr.Append(fmt.Errorf("cannot deliver notification for @%s: %w", username, err))
}
if userID == "" {
// was a `@` followed by something other than a username.
continue
}
b.logger.Debug("Mention notification delivered",
mlog.String("user", username),
mlog.Int("listener_count", len(listeners)),
)
for _, listener := range listeners {
safeCallListener(listener, userID, evt, b.logger)
}
2021-09-13 21:36:36 +02:00
}
return merr.ErrorOrNil()
}
func safeCallListener(listener MentionListener, userID string, evt notify.BlockChangeEvent, logger *mlog.Logger) {
// don't let panicky listeners stop notifications
defer func() {
if r := recover(); r != nil {
logger.Error("panic calling @mention notification listener", mlog.Any("err", r))
}
}()
listener.OnMention(userID, evt)
}