Files
gochat/internal/automation/condition_validator.go
T
2026-06-04 15:44:48 +08:00

110 lines
3.6 KiB
Go

package automation
import "fmt"
// WhitelistedConditionAttributes defines the set of valid condition attributes.
// Reference: Chatwoot ConditionValidationService — validates condition keys against whitelisted attributes.
var WhitelistedConditionAttributes = map[string]bool{
// Conversation attributes
"status": true,
"priority": true,
"assignee_id": true,
"team_id": true,
"inbox_id": true,
"contact_id": true,
"channel_type": true,
"labels": true,
// Message/content attributes
"content": true,
"message_type": true,
"email": true,
// Country/locale attributes (Chatwoot extensions)
"country_code": true,
"browser_language": true,
}
// WhitelistedFilterOperators defines the set of valid filter operators.
// Reference: Chatwoot filter_operator enum
var WhitelistedFilterOperators = map[string]bool{
"equal": true,
"not_equal": true,
"contains": true,
"does_not_contain": true,
"is_present": true,
"is_not_present": true,
"attribute_changed": true,
}
// WhitelistedQueryOperators defines the set of valid query operators for combining conditions.
var WhitelistedQueryOperators = map[string]bool{
"and": true,
"or": true,
}
// WhitelistedActionTypes defines the set of valid automation action types.
// Reference: Chatwoot AutomationRule action_name enum
var WhitelistedActionTypes = map[string]bool{
"assign_agent": true,
"assign_team": true, // Chatwoot: assign conversation to a team
"change_status": true,
"add_label": true,
"remove_label": true,
"send_message": true,
"send_email_to_contact": true,
"mute_conversation": true,
"snooze_conversation": true, // Chatwoot: snooze until a specified time
"resolve_conversation": true, // Chatwoot: resolve immediately
}
// ValidateConditions checks that all conditions use valid attributes, filter operators,
// and query operators.
// Reference: Chatwoot ConditionValidationService — validates condition keys against whitelisted attributes
func ValidateConditions(conditions Conditions) error {
for i, c := range conditions {
// Validate attribute
if !WhitelistedConditionAttributes[c.Attribute] {
return fmt.Errorf("condition[%d]: invalid attribute '%s'", i, c.Attribute)
}
// Validate filter operator
if !WhitelistedFilterOperators[c.FilterOperator] {
return fmt.Errorf("condition[%d]: invalid filter_operator '%s'", i, c.FilterOperator)
}
// Validate query operator (defaults to "and" if empty)
if c.QueryOperator != "" {
if !WhitelistedQueryOperators[c.QueryOperator] {
return fmt.Errorf("condition[%d]: invalid query_operator '%s'", i, c.QueryOperator)
}
}
// Validate values — attribute_changed requires from/to values
if c.FilterOperator == "attribute_changed" {
if len(c.Values) == 0 {
return fmt.Errorf("condition[%d]: attribute_changed requires at least one value (to)", i)
}
}
// is_present / is_not_present should not need values
if c.FilterOperator == "is_present" || c.FilterOperator == "is_not_present" {
// Values are optional for presence checks — not enforced
} else if len(c.Values) == 0 {
return fmt.Errorf("condition[%d]: filter_operator '%s' requires at least one value", i, c.FilterOperator)
}
}
return nil
}
// ValidateActions checks that all actions use valid action types.
// Reference: Chatwoot AutomationRule action_name validation
func ValidateActions(actions Actions) error {
for i, a := range actions {
if !WhitelistedActionTypes[a.ActionName] {
return fmt.Errorf("action[%d]: invalid action_name '%s'", i, a.ActionName)
}
}
return nil
}