1
0

Subscriptions and notifications for namespaces, tasks and lists (#786)

Co-authored-by: kolaente <k@knt.li>
Reviewed-on: https://kolaente.dev/vikunja/api/pulls/786
Co-authored-by: konrad <konrad@kola-entertainments.de>
Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
konrad
2021-02-14 19:18:14 +00:00
parent 618b464ca3
commit e7875ecb3b
25 changed files with 1714 additions and 23 deletions

View File

@ -17,9 +17,14 @@
package models
import (
"encoding/json"
"code.vikunja.io/api/pkg/db"
"code.vikunja.io/api/pkg/events"
"code.vikunja.io/api/pkg/log"
"code.vikunja.io/api/pkg/metrics"
"code.vikunja.io/api/pkg/modules/keyvalue"
"code.vikunja.io/api/pkg/notifications"
"github.com/ThreeDotsLabs/watermill/message"
)
@ -33,6 +38,10 @@ func RegisterListeners() {
events.RegisterListener((&TaskDeletedEvent{}).Name(), &DecreaseTaskCounter{})
events.RegisterListener((&TeamDeletedEvent{}).Name(), &DecreaseTeamCounter{})
events.RegisterListener((&TeamCreatedEvent{}).Name(), &IncreaseTeamCounter{})
events.RegisterListener((&TaskCommentCreatedEvent{}).Name(), &SendTaskCommentNotification{})
events.RegisterListener((&TaskAssigneeCreatedEvent{}).Name(), &SendTaskAssignedNotification{})
events.RegisterListener((&TaskDeletedEvent{}).Name(), &SendTaskDeletedNotification{})
events.RegisterListener((&ListCreatedEvent{}).Name(), &SendListCreatedNotification{})
}
//////
@ -66,6 +75,143 @@ func (s *DecreaseTaskCounter) Handle(payload message.Payload) (err error) {
return keyvalue.DecrBy(metrics.TaskCountKey, 1)
}
// SendTaskCommentNotification represents a listener
type SendTaskCommentNotification struct {
}
// Name defines the name for the SendTaskCommentNotification listener
func (s *SendTaskCommentNotification) Name() string {
return "send.task.comment.notification"
}
// Handle is executed when the event SendTaskCommentNotification listens on is fired
func (s *SendTaskCommentNotification) Handle(payload message.Payload) (err error) {
event := &TaskCommentCreatedEvent{}
err = json.Unmarshal(payload, event)
if err != nil {
return err
}
sess := db.NewSession()
defer sess.Close()
subscribers, err := getSubscribersForEntity(sess, SubscriptionEntityTask, event.Task.ID)
if err != nil {
return err
}
log.Debugf("Sending task comment notifications to %d subscribers for task %d", len(subscribers), event.Task.ID)
for _, subscriber := range subscribers {
if subscriber.UserID == event.Doer.ID {
continue
}
n := &TaskCommentNotification{
Doer: event.Doer,
Task: event.Task,
Comment: event.Comment,
}
err = notifications.Notify(subscriber.User, n)
if err != nil {
return
}
}
return
}
// SendTaskAssignedNotification represents a listener
type SendTaskAssignedNotification struct {
}
// Name defines the name for the SendTaskAssignedNotification listener
func (s *SendTaskAssignedNotification) Name() string {
return "send.task.assigned.notification"
}
// Handle is executed when the event SendTaskAssignedNotification listens on is fired
func (s *SendTaskAssignedNotification) Handle(payload message.Payload) (err error) {
event := &TaskAssigneeCreatedEvent{}
err = json.Unmarshal(payload, event)
if err != nil {
return err
}
sess := db.NewSession()
defer sess.Close()
subscribers, err := getSubscribersForEntity(sess, SubscriptionEntityTask, event.Task.ID)
if err != nil {
return err
}
log.Debugf("Sending task assigned notifications to %d subscribers for task %d", len(subscribers), event.Task.ID)
for _, subscriber := range subscribers {
if subscriber.UserID == event.Doer.ID {
continue
}
n := &TaskAssignedNotification{
Doer: event.Doer,
Task: event.Task,
Assignee: event.Assignee,
}
err = notifications.Notify(subscriber.User, n)
if err != nil {
return
}
}
return nil
}
// SendTaskDeletedNotification represents a listener
type SendTaskDeletedNotification struct {
}
// Name defines the name for the SendTaskDeletedNotification listener
func (s *SendTaskDeletedNotification) Name() string {
return "send.task.deleted.notification"
}
// Handle is executed when the event SendTaskDeletedNotification listens on is fired
func (s *SendTaskDeletedNotification) Handle(payload message.Payload) (err error) {
event := &TaskDeletedEvent{}
err = json.Unmarshal(payload, event)
if err != nil {
return err
}
sess := db.NewSession()
defer sess.Close()
subscribers, err := getSubscribersForEntity(sess, SubscriptionEntityTask, event.Task.ID)
if err != nil {
return err
}
log.Debugf("Sending task deleted notifications to %d subscribers for task %d", len(subscribers), event.Task.ID)
for _, subscriber := range subscribers {
if subscriber.UserID == event.Doer.ID {
continue
}
n := &TaskDeletedNotification{
Doer: event.Doer,
Task: event.Task,
}
err = notifications.Notify(subscriber.User, n)
if err != nil {
return
}
}
return nil
}
///////
// List Event Listeners
@ -91,6 +237,51 @@ func (s *DecreaseListCounter) Handle(payload message.Payload) (err error) {
return keyvalue.DecrBy(metrics.ListCountKey, 1)
}
// SendListCreatedNotification represents a listener
type SendListCreatedNotification struct {
}
// Name defines the name for the SendListCreatedNotification listener
func (s *SendListCreatedNotification) Name() string {
return "send.list.created.notification"
}
// Handle is executed when the event SendListCreatedNotification listens on is fired
func (s *SendListCreatedNotification) Handle(payload message.Payload) (err error) {
event := &ListCreatedEvent{}
err = json.Unmarshal(payload, event)
if err != nil {
return err
}
sess := db.NewSession()
defer sess.Close()
subscribers, err := getSubscribersForEntity(sess, SubscriptionEntityList, event.List.ID)
if err != nil {
return err
}
log.Debugf("Sending list created notifications to %d subscribers for list %d", len(subscribers), event.List.ID)
for _, subscriber := range subscribers {
if subscriber.UserID == event.Doer.ID {
continue
}
n := &ListCreatedNotification{
Doer: event.Doer,
List: event.List,
}
err = notifications.Notify(subscriber.User, n)
if err != nil {
return
}
}
return nil
}
//////
// Namespace events