Skip to content

Commit

Permalink
Split add and remove action to seeperate places
Browse files Browse the repository at this point in the history
Update example
Some refactoring in matcher.go
  • Loading branch information
Steven Arnott committed Oct 24, 2024
1 parent 4e684ee commit 2e944ad
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 37 deletions.
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ test-coverage:
clean: validate
@echo "Running $@ tasks"
-rm -v ./flottbot*
-rm -v ./debug

## -rm -v ./debug #Not created

# ┌┐ ┬ ┬┬┬ ┌┬┐
# ├┴┐│ │││ ││
Expand Down
10 changes: 5 additions & 5 deletions config-example/rules/reaction.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: plus-one-reaction
name: question-reaction
active: true
reaction_match: ":+1:"
reactions_added: "question"
args:
# actions
actions: # this rule takes no actions, just collects and responds with whats laid out in the format_response section

actions: # no actions
# response
format_output: "Oh a reaction?" # message to send to your user when they say hello
format_output: ${_user.firstname} could you elaborate more on your request?

start_message_thread: true # start a thread with the response
direct_message_only: false # allow messaging inside channels
53 changes: 44 additions & 9 deletions core/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ RuleSearch:
// Only check active rules.
if rule.Active {
// Init some variables for use below
processedInput, hit := getProccessedInputAndHitValue(message.Input, rule.Respond, rule.Hear, message.Reaction, rule.ReactionMatch)
processedInput, hit := getProccessedInputAndHitValue(message, rule)
// Determine what service we are processing the rule for
switch message.Service {
case models.MsgServiceChat, models.MsgServiceCLI:
Expand All @@ -63,27 +63,62 @@ RuleSearch:
}

// getProccessedInputAndHitValue gets the processed input from the message input and the true/false if it was a successfully hit rule.
func getProccessedInputAndHitValue(messageInput, ruleRespondValue, ruleHearValue, messageReaction, ruleReactionMatch string) (string, bool) {
func getProccessedInputAndHitValue(message models.Message, rule models.Rule) (string, bool) {
processedInput, hit := "", false
if ruleRespondValue != "" {

ruleRespondValue := rule.Respond
ruleHearValue := rule.Hear

if rule.Respond != "" {
log.Debug().Msgf("Respond Rule %s", rule.Name)

messageInput := message.Input
processedInput, hit = utils.Match(ruleRespondValue, messageInput, true)
} else if ruleHearValue != "" { // Are we listening to everything?
} else if rule.Hear != "" { // Are we listening to everything?
log.Debug().Msgf("HearRule %s", rule.Name)

messageInput := message.Input
_, hit = utils.Match(ruleHearValue, messageInput, false)
} else if ruleReactionMatch != "" {
processedInput, hit = utils.Match(ruleReactionMatch, messageReaction, false)
} else if rule.ReactionsAdded != "" {
log.Debug().Msgf("ReactionAdded Rule %s", rule.Name)

messageReaction := message.ReactionAdded
processedInput, hit = utils.Match(rule.ReactionsAdded, messageReaction, false)
} else if rule.ReactionsRemoved != "" {
log.Debug().Msgf("ReactionRemoved Rule %s", rule.Name)

messageReaction := message.ReactionRemoved
processedInput, hit = utils.Match(rule.ReactionsRemoved, messageReaction, false)
}

return processedInput, hit
}

// isChatRule checks that the rule applies to chat.
func isValidChatRule(rule models.Rule) bool {
if rule.Respond != "" {
return true
}

if rule.Hear != "" {
return true
}

if rule.ReactionsAdded != "" || rule.ReactionsRemoved != "" {
return true
}

return false
}

// handleChatServiceRule handles the processing logic for a rule that came from either the chat application or CLI remote.
//
//nolint:gocyclo // refactor candidate
func handleChatServiceRule(outputMsgs chan<- models.Message, message models.Message, hitRule chan<- models.Rule, rule models.Rule, processedInput string, hit bool, bot *models.Bot) (bool, bool) {
match, stopSearch := false, false

if rule.Respond != "" || rule.Hear != "" || rule.ReactionMatch != "" {
// You can only use 'respond', 'hear', or 'reaction match'
if isValidChatRule(rule) {
// You can only use 'respond', 'hear', or 'reactions'
if rule.Respond != "" && rule.Hear != "" {
log.Debug().Msgf("rule %#q has both 'hear' and 'match' or 'respond' defined. please choose one or the other", rule.Name)
}
Expand Down Expand Up @@ -235,7 +270,7 @@ func isValidHitChatRule(message *models.Message, rule models.Rule, processedInpu
}

// If this wasn't a 'hear' rule, handle the args
if rule.Hear == "" && rule.ReactionMatch == "" {
if rule.Hear == "" && rule.ReactionsAdded == "" {
// Get all the args that the message sender supplied
args := utils.RuleArgTokenizer(processedInput)

Expand Down
39 changes: 28 additions & 11 deletions core/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -584,11 +584,13 @@ func TestUpdateReaction(t *testing.T) {

func Test_getProccessedInputAndHitValue(t *testing.T) {
type args struct {
messageInput string
ruleRespondValue string
ruleHearValue string
messageReaction string
ruleReactionMatch string
messageInput string
ruleRespondValue string
ruleHearValue string
messageReactionAdded string
messageReactionRemoved string
ruleReactionAdded string
ruleReactionRemoved string
}

tests := []struct {
Expand All @@ -597,16 +599,31 @@ func Test_getProccessedInputAndHitValue(t *testing.T) {
want string
want1 bool
}{
{"hit", args{"hello foo", "hello", "hello", "", ""}, "foo", true},
{"hit no hear value", args{"hello foo", "hello", "", "", ""}, "foo", true},
{"hit no respond value - drops args", args{"hello foo", "", "hello", "", ""}, "", true},
{"no match", args{"hello foo", "", "", "", ""}, "", false},
{"hit reaction", args{"", "", "", ":hello:", ":hello:"}, ":hello:", true},
{"hit", args{"hello foo", "hello", "hello", "", "", "", ""}, "foo", true},
{"hit no hear value", args{"hello foo", "hello", "", "", "", "", ""}, "foo", true},
{"hit no respond value - drops args", args{"hello foo", "", "hello", "", "", "", ""}, "", true},
{"no match", args{"hello foo", "", "", "", "", "", ""}, "", false},
{"hit reaction added", args{"", "", "", "hello", "", "hello", ""}, "hello", true},
{"hit reaction removed", args{"", "", "", "", "hello", "", "hello"}, "hello", true},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := getProccessedInputAndHitValue(tt.args.messageInput, tt.args.ruleRespondValue, tt.args.ruleHearValue, tt.args.messageReaction, tt.args.ruleReactionMatch)
rule := models.Rule{
Hear: tt.args.ruleHearValue,
Respond: tt.args.ruleRespondValue,
ReactionsAdded: tt.args.ruleReactionAdded,
ReactionsRemoved: tt.args.ruleReactionRemoved,
}

message := models.Message{
Input: tt.args.messageInput,
ReactionAdded: tt.args.messageReactionAdded,
ReactionRemoved: tt.args.messageReactionRemoved,
}

got, got1 := getProccessedInputAndHitValue(message, rule)

if got != tt.want {
t.Errorf("getProccessedInputAndHitValue() got = %v, want %v", got, tt.want)
}
Expand Down
4 changes: 2 additions & 2 deletions models/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ type Message struct {
ChannelName string
Input string
Output string
ReactionAction string
Reaction string
ReactionAdded string
ReactionRemoved string
Error string
Timestamp string
ThreadID string
Expand Down
3 changes: 2 additions & 1 deletion models/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ type Rule struct {
Name string `mapstructure:"name" binding:"required"`
Respond string `mapstructure:"respond" binding:"omitempty"`
Hear string `mapstructure:"hear" binding:"omitempty"`
ReactionMatch string `mapstructure:"reaction_match" binding:"omitempty"`
ReactionsAdded string `mapstructure:"reactions_added" binding:"omitempty"`
ReactionsRemoved string `mapstructure:"reactions_removed" binding:"omitempty"`
Schedule string `mapstructure:"schedule"`
Args []string `mapstructure:"args" binding:"required"`
DirectMessageOnly bool `mapstructure:"direct_message_only" binding:"required"`
Expand Down
17 changes: 9 additions & 8 deletions remote/slack/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,14 +449,15 @@ func populateMessage(message models.Message, msgType models.MessageType, channel
func populateReaction(message models.Message, msgType models.MessageType, channel, action, reaction, timeStamp, link string, user *slack.User, bot *models.Bot) models.Message {
switch msgType {
case models.MsgTypeDirect, models.MsgTypeChannel, models.MsgTypePrivateChannel:
message.ReactionAction = action
message.Reaction = reaction
message.Input = ""
message.Output = ""
message.Timestamp = timeStamp
message.SourceLink = link
message.Vars["_reaction.action"] = action
message.Vars["_reaction"] = reaction
switch action {
case "added":
message.ReactionAdded = reaction
case "removed":
message.ReactionRemoved = reaction
}

message.Vars["_reaction.added"] = message.ReactionAdded
message.Vars["_reaction.removed"] = message.ReactionRemoved

message = populateMessage(message, msgType, channel, "", timeStamp, "", link, false, user, bot)
default:
Expand Down

0 comments on commit 2e944ad

Please sign in to comment.