Skip to content

Commit

Permalink
Add MarkDoneAction for reactions
Browse files Browse the repository at this point in the history
  • Loading branch information
CubicrootXYZ committed Apr 10, 2024
1 parent fd340df commit 5cbf684
Show file tree
Hide file tree
Showing 3 changed files with 203 additions and 0 deletions.
1 change: 1 addition & 0 deletions internal/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ func assembleMatrixConfig(config *Config, icalConnector ical.Service) *matrix.Co
cfg.ReactionActions = append(cfg.ReactionActions,
&reaction.DeleteEventAction{},
&reaction.AddTimeAction{},
&reaction.MarkDoneAction{},
)

cfg.BridgeServices = &matrix.BridgeServices{
Expand Down
82 changes: 82 additions & 0 deletions internal/connectors/matrix/actions/reaction/mark_done.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package reaction

import (
"github.com/CubicrootXYZ/gologger"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix"
matrixdb "github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/database"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/mautrixcl"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/messenger"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/database"
)

// MarkDoneAction takes cafe of delete requests via reactions.
type MarkDoneAction struct {
logger gologger.Logger
client mautrixcl.Client
messenger messenger.Messenger
matrixDB matrixdb.Service
db database.Service
}

// Configure is called on startup and sets all dependencies.
func (action *MarkDoneAction) Configure(logger gologger.Logger, client mautrixcl.Client, messenger messenger.Messenger, matrixDB matrixdb.Service, db database.Service, _ *matrix.BridgeServices) {
action.logger = logger
action.client = client
action.matrixDB = matrixDB
action.db = db
action.messenger = messenger
}

// Name of the action.
func (action *MarkDoneAction) Name() string {
return "Mark Event Done"
}

// GetDocu returns the documentation for the action.
func (action *MarkDoneAction) GetDocu() (title, explaination string, examples []string) {
return "Mark Event Done",
"React with a ✅ to mark the event as done.",
[]string{"✅"}
}

// Selector defines on which reactions this action should be called.
func (action *MarkDoneAction) Selector() []string {
return []string{"✅"}
}

// HandleEvent is where the reaction event and the related message get's send to if it matches the Selector.
func (action *MarkDoneAction) HandleEvent(event *matrix.ReactionEvent, reactionToMessage *matrixdb.MatrixMessage) {
l := action.logger.WithFields(
map[string]any{
"reaction": event.Content.RelatesTo.Key,
"room": reactionToMessage.RoomID,
"related_message": reactionToMessage.ID,
"user": event.Event.Sender,
},
)
if reactionToMessage.EventID == nil || reactionToMessage.Event == nil {
l.Infof("skipping because message does not relate to any event")
return
}

evt := reactionToMessage.Event
evt.Active = false

_, err := action.db.UpdateEvent(evt)
if err != nil {
l.Err(err)
_ = action.messenger.SendMessageAsync(messenger.PlainTextMessage(
"Whoopsie, can not update the event as requested.",
event.Room.RoomID,
))
return
}

err = action.messenger.DeleteMessageAsync(&messenger.Delete{
ExternalIdentifier: reactionToMessage.ID,
ChannelExternalIdentifier: reactionToMessage.Room.RoomID,
})
if err != nil {
l.Err(err)
}
}
120 changes: 120 additions & 0 deletions internal/connectors/matrix/actions/reaction/mark_done_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package reaction_test

import (
"errors"
"testing"

"github.com/CubicrootXYZ/gologger"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/actions/reaction"
matrixdb "github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/database"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/mautrixcl"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/messenger"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/connectors/matrix/tests"
"github.com/CubicrootXYZ/matrix-reminder-and-calendar-bot/internal/database"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

func TestMarkDoneAction(t *testing.T) {
action := &reaction.MarkDoneAction{}

assert.NotEmpty(t, action.Name())

title, desc, examples := action.GetDocu()
assert.NotEmpty(t, title)
assert.NotEmpty(t, desc)
assert.NotEmpty(t, examples)

assert.NotNil(t, action.Selector())
}

func TestMarkDoneAction_Selector(t *testing.T) {
action := &reaction.MarkDoneAction{}

examples := []string{}

_, _, examplesFromDocu := action.GetDocu()
examples = append(examples, examplesFromDocu...)

reactions := action.Selector()
for _, example := range examples {
matches := false
for _, reaction := range reactions {
if example == reaction {
matches = true
break
}
}
assert.Truef(t, matches, "%s is not part of reactions", example)
}
}

func TestMarkDoneAction_HandleEvent(t *testing.T) {
// Setup
ctrl := gomock.NewController(t)
defer ctrl.Finish()
db := database.NewMockService(ctrl)
matrixDB := matrixdb.NewMockService(ctrl)
client := mautrixcl.NewMockClient(ctrl)
msngr := messenger.NewMockMessenger(ctrl)

action := &reaction.MarkDoneAction{}
action.Configure(
gologger.New(gologger.LogLevelDebug, 0),
client,
msngr,
matrixDB,
db,
nil,
)

t.Run("success case", func(t *testing.T) {
msg := tests.TestMessage(
tests.WithTestEvent(),
)
evt := *msg.Event

// Expectations
evt.Active = false
db.EXPECT().UpdateEvent(&evt).Return(nil, nil)

msngr.EXPECT().DeleteMessageAsync(gomock.Any()).Return(nil)

// Execute
action.HandleEvent(tests.TestReactionEvent(
tests.ReactionWithKey("✅"),
), msg)
})

t.Run("update fails", func(t *testing.T) {
msg := tests.TestMessage(
tests.WithTestEvent(),
)
evt := *msg.Event

// Expectations
evt.Active = false
db.EXPECT().UpdateEvent(&evt).Return(nil, errors.New("test"))

msngr.EXPECT().SendMessageAsync(messenger.PlainTextMessage(
"Whoopsie, can not update the event as requested.",
"!room123",
)).Return(nil)

// Execute
action.HandleEvent(tests.TestReactionEvent(
tests.ReactionWithKey("✅"),
), msg)
})

t.Run("missing event in message", func(t *testing.T) {
msg := tests.TestMessage(
tests.WithoutEvent(),
)

// Execute
action.HandleEvent(tests.TestReactionEvent(
tests.ReactionWithKey("✅"),
), msg)
})
}

0 comments on commit 5cbf684

Please sign in to comment.