diff --git a/engine/filters.go b/engine/filters.go index b2e865dad..52adcb9e2 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -225,6 +225,7 @@ func (fltr *Filter) Compile() (err error) { var ( cdrQueryFilterTypes = utils.NewStringSet([]string{ utils.MetaString, utils.MetaNotString, + utils.MetaContains, utils.MetaNotContains, utils.MetaGreaterThan, utils.MetaGreaterOrEqual, utils.MetaLessThan, utils.MetaLessOrEqual, utils.MetaExists, utils.MetaNotExists, @@ -237,6 +238,7 @@ var ( supportedFiltersType utils.StringSet = utils.NewStringSet([]string{ utils.MetaString, utils.MetaNotString, + utils.MetaContains, utils.MetaNotContains, utils.MetaPrefix, utils.MetaNotPrefix, utils.MetaSuffix, utils.MetaNotSuffix, utils.MetaCronExp, utils.MetaNotCronExp, @@ -255,6 +257,7 @@ var ( needsFieldName utils.StringSet = utils.NewStringSet([]string{ utils.MetaString, utils.MetaNotString, + utils.MetaContains, utils.MetaNotContains, utils.MetaPrefix, utils.MetaNotPrefix, utils.MetaSuffix, utils.MetaNotSuffix, utils.MetaCronExp, utils.MetaNotCronExp, @@ -273,6 +276,7 @@ var ( needsValues utils.StringSet = utils.NewStringSet([]string{ utils.MetaString, utils.MetaNotString, + utils.MetaContains, utils.MetaNotContains, utils.MetaPrefix, utils.MetaNotPrefix, utils.MetaSuffix, utils.MetaNotSuffix, utils.MetaCronExp, utils.MetaNotCronExp, @@ -390,6 +394,8 @@ func (fltr *FilterRule) Pass(ctx *context.Context, dDP utils.DataProvider) (resu switch fltr.Type { case utils.MetaString, utils.MetaNotString: result, err = fltr.passString(dDP) + case utils.MetaContains, utils.MetaNotContains: + result, err = fltr.passContains(dDP) case utils.MetaEmpty, utils.MetaNotEmpty: result, err = fltr.passEmpty(dDP) case utils.MetaExists, utils.MetaNotExists: @@ -447,6 +453,26 @@ func (fltr *FilterRule) passString(dDP utils.DataProvider) (bool, error) { return false, nil } +func (fltr *FilterRule) passContains(dDP utils.DataProvider) (bool, error) { + strVal, err := fltr.rsrElement.ParseDataProvider(dDP) + if err != nil { + if err == utils.ErrNotFound { + return false, nil + } + return false, err + } + for _, val := range fltr.rsrValues { + sval, err := val.ParseDataProvider(dDP) + if err != nil { + continue + } + if strings.Contains(strVal, sval) { + return true, nil + } + } + return false, nil +} + func (fltr *FilterRule) passExists(dDP utils.DataProvider) (bool, error) { path, err := fltr.rsrElement.CompileDynRule(dDP) if err != nil { diff --git a/engine/filters_test.go b/engine/filters_test.go index dae11d12d..594fa73af 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -229,6 +229,41 @@ func TestFilterPassGreaterThan(t *testing.T) { } } +func TestFilterPassContains(t *testing.T) { + rF, err := NewFilterRule(utils.MetaContains, "~Subject", []string{"Any"}) + if err != nil { + t.Error(err) + } + eV := utils.MapStorage{} + eV.Set([]string{"Subject"}, "SubAnyAcc") + + if pass, err := rF.passContains(eV); err != nil { + t.Error(err) + } else if !pass { + t.Error("not passing") + } + + eV.Set([]string{"Subject"}, "1001") + if pass, err := rF.passContains(eV); err != nil { + t.Error(err) + } else if pass { + t.Error("passes") + } + rF, err = NewFilterRule(utils.MetaContains, "~Resource", []string{"Prf"}) + if err != nil { + t.Error(err) + } + + eV.Set([]string{"Resource"}, "ResPrf1") + + if pass, err := rF.Pass(context.TODO(), eV); err != nil { + t.Error(err) + } else if !pass { + t.Error("not passing") + } + +} + func TestFilterpassEqualTo(t *testing.T) { rf, err := NewFilterRule(utils.MetaEqual, "~ASR", []string{"40"}) if err != nil { diff --git a/utils/consts.go b/utils/consts.go index a619a4c83..22be4a16f 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1054,6 +1054,7 @@ const ( const ( MetaNot = "*not" MetaString = "*string" + MetaContains = "*contains" MetaPrefix = "*prefix" MetaSuffix = "*suffix" MetaBoth = "*both" @@ -1078,6 +1079,7 @@ const ( MetaNever = "*never" MetaNotString = "*notstring" + MetaNotContains = "*notcontains" MetaNotPrefix = "*notprefix" MetaNotSuffix = "*notsuffix" MetaNotEmpty = "*notempty"