From 9c98adfb7a38b1bf1c2ca250b969d79486aaf4d2 Mon Sep 17 00:00:00 2001 From: Abhinav Raut Date: Sat, 25 Jan 2025 15:43:57 +0530 Subject: [PATCH] fix[automation]: for contains operator do a substring match instead of per word match - feat: contact email as a field in automation rule fields. --- internal/automation/evaluator.go | 48 ++++++++++++++++------------ internal/automation/models/models.go | 1 + 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/internal/automation/evaluator.go b/internal/automation/evaluator.go index fee657b5..756270d6 100644 --- a/internal/automation/evaluator.go +++ b/internal/automation/evaluator.go @@ -39,7 +39,9 @@ func (e *Engine) evalConversationRules(rules []models.Rule, conversation cmodels if evaluateFinalResult(groupEvalResults, rule.GroupOperator) { e.lo.Debug("rule evaluation successful executing actions", "conversation_uuid", conversation.UUID) for _, action := range rule.Actions { - e.conversationStore.ApplyAction(action, conversation, umodels.User{}) + if err := e.conversationStore.ApplyAction(action, conversation, umodels.User{}); err != nil { + e.lo.Error("error applying action on conversation", "action", action, "conversation_uuid", conversation.UUID, "error", err) + } } if rule.ExecutionMode == models.ExecutionModeFirstMatch { e.lo.Debug("first match rule execution mode, breaking out of rule evaluation", "conversation_uuid", conversation.UUID) @@ -109,6 +111,8 @@ func (e *Engine) evaluateRule(rule models.RuleDetail, conversation cmodels.Conve // Extract the value from the conversation based on the rule's field switch rule.Field { + case models.ContactEmail: + valueToCompare = conversation.Contact.Email.String case models.ConversationSubject: valueToCompare = conversation.Subject.String case models.ConversationContent: @@ -165,31 +169,35 @@ func (e *Engine) evaluateRule(rule models.RuleDetail, conversation cmodels.Conve case models.RuleOperatorNotEqual: conditionMet = valueToCompare != rule.Value case models.RuleOperatorContains: - // Split the value to compare into words - words := strings.Fields(valueToCompare) - wordMap := make(map[string]struct{}, len(words)) - for _, word := range words { - wordMap[word] = struct{}{} - } - // Check if any of the rule values exist as complete words - for _, val := range ruleValues { - if _, exists := wordMap[val]; exists { + // Normalize input text by collapsing multiple spaces + normalizedInputText := strings.Join(strings.Fields(valueToCompare), " ") + conditionMet = false + + // Check each rule value against the normalized input + for _, ruleValue := range ruleValues { + // Normalize rule value by collapsing multiple spaces + normalizedRuleValue := strings.Join(strings.Fields(ruleValue), " ") + if strings.Contains( + strings.ToLower(normalizedInputText), + strings.ToLower(normalizedRuleValue), + ) { conditionMet = true break } } case models.RuleOperatorNotContains: - // Split the value to compare into words - words := strings.Fields(valueToCompare) - wordMap := make(map[string]struct{}, len(words)) - for _, word := range words { - wordMap[word] = struct{}{} - } - - // Check if none of the rule values exist as complete words + // Normalize input text by collapsing multiple spaces + normalizedInputText := strings.Join(strings.Fields(valueToCompare), " ") conditionMet = true - for _, val := range ruleValues { - if _, exists := wordMap[val]; exists { + + // Check each rule value against the normalized input + for _, ruleValue := range ruleValues { + // Normalize rule value by collapsing multiple spaces + normalizedRuleValue := strings.Join(strings.Fields(ruleValue), " ") + if strings.Contains( + strings.ToLower(normalizedInputText), + strings.ToLower(normalizedRuleValue), + ) { conditionMet = false break } diff --git a/internal/automation/models/models.go b/internal/automation/models/models.go index cb2e032e..27e188e9 100644 --- a/internal/automation/models/models.go +++ b/internal/automation/models/models.go @@ -41,6 +41,7 @@ const ( ConversationAssignedTeam = "assigned_team" ConversationHoursSinceCreated = "hours_since_created" ConversationHoursSinceResolved = "hours_since_resolved" + ContactEmail = "contact_email" ConversationInbox = "inbox" EventConversationUserAssigned = "conversation.user.assigned"