diff --git a/engine/filters.go b/engine/filters.go index 8630883f3..9796bbb05 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -550,32 +550,22 @@ func (fltr *FilterRule) passRSR(dDP utils.DataProvider) (bool, error) { } func (fltr *FilterRule) passGreaterThan(dDP utils.DataProvider) (bool, error) { - path, err := fltr.rsrElement.CompileDynRule(dDP) - if err != nil { - return false, err - } - fldIf, err := utils.DPDynamicInterface(path, dDP) + fldStr, err := fltr.rsrElement.ParseDataProviderWithInterfaces(dDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - if fldStr, castStr := fldIf.(string); castStr { // attempt converting string since deserialization fails here (ie: time.Time fields) - fldIf = utils.StringToInterface(fldStr) - } + fldIf := utils.StringToInterface(fldStr) orEqual := fltr.Type == utils.MetaGreaterOrEqual || fltr.Type == utils.MetaLessThan for _, val := range fltr.rsrValues { - valPath, err := val.CompileDynRule(dDP) + sval, err := val.ParseDataProviderWithInterfaces(dDP) if err != nil { continue } - sval, err := utils.DPDynamicInterface(valPath, dDP) - if err != nil { - continue - } - if gte, err := utils.GreaterThan(fldIf, sval, orEqual); err != nil { + if gte, err := utils.GreaterThan(fldIf, utils.StringToInterface(sval), orEqual); err != nil { return false, err } else if (utils.MetaGreaterThan == fltr.Type || utils.MetaGreaterOrEqual == fltr.Type) && gte { return true, nil @@ -587,30 +577,20 @@ func (fltr *FilterRule) passGreaterThan(dDP utils.DataProvider) (bool, error) { } func (fltr *FilterRule) passEqualTo(dDP utils.DataProvider) (bool, error) { - path, err := fltr.rsrElement.CompileDynRule(dDP) - if err != nil { - return false, err - } - fldIf, err := utils.DPDynamicInterface(path, dDP) + fldStr, err := fltr.rsrElement.ParseDataProviderWithInterfaces(dDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - if fldStr, castStr := fldIf.(string); castStr { // attempt converting string since deserialization fails here (ie: time.Time fields) - fldIf = utils.StringToInterface(fldStr) - } + fldIf := utils.StringToInterface(fldStr) for _, val := range fltr.rsrValues { - valPath, err := val.CompileDynRule(dDP) - if err != nil { - return false, err - } - sval, err := utils.DPDynamicInterface(valPath, dDP) + sval, err := val.ParseDataProviderWithInterfaces(dDP) if err != nil { continue } - if eq, err := utils.EqualTo(fldIf, sval); err != nil { + if eq, err := utils.EqualTo(fldIf, utils.StringToInterface(sval)); err != nil { return false, err } else if eq { return true, nil @@ -663,49 +643,42 @@ func (fltr *FilterRule) passAPIBan(dDP utils.DataProvider) (bool, error) { return dm.GetAPIBan(strVal, config.CgrConfig().APIBanCfg().Keys, fltr.Values[0] != utils.MetaAll, true, true) } +func parseTime(rsr *config.RSRParser, dDp utils.DataProvider) (_ time.Time, err error) { + var str string + if str, err = rsr.ParseDataProvider(dDp); err != nil { + return + } + return utils.ParseTimeDetectLayout(str, config.CgrConfig().GeneralCfg().DefaultTimezone) +} + func (fltr *FilterRule) passActivationInterval(dDp utils.DataProvider) (bool, error) { - strVal, err := fltr.rsrElement.ParseDataProvider(dDp) + timeVal, err := parseTime(fltr.rsrElement, dDp) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - timeStrVal, err := utils.ParseTimeDetectLayout(strVal, config.CgrConfig().GeneralCfg().DefaultTimezone) - if err != nil { - return false, err - } + if len(fltr.rsrValues) == 2 { - val2, err := fltr.rsrValues[1].CompileDynRule(dDp) - if err != nil { - return false, err - } - endTime, err := utils.ParseTimeDetectLayout(val2, config.CgrConfig().GeneralCfg().DefaultTimezone) + endTime, err := parseTime(fltr.rsrValues[1], dDp) if err != nil { return false, err } if fltr.rsrValues[0] == nil { - return timeStrVal.Before(endTime), nil + return timeVal.Before(endTime), nil } - val1, err := fltr.rsrValues[0].CompileDynRule(dDp) + startTime, err := parseTime(fltr.rsrValues[0], dDp) if err != nil { return false, err } - startTime, err := utils.ParseTimeDetectLayout(val1, config.CgrConfig().GeneralCfg().DefaultTimezone) - if err != nil { - return false, err - } - return startTime.Before(timeStrVal) && timeStrVal.Before(endTime), nil + return startTime.Before(timeVal) && timeVal.Before(endTime), nil } - val1, err := fltr.rsrValues[0].CompileDynRule(dDp) + startTime, err := parseTime(fltr.rsrValues[0], dDp) if err != nil { return false, err } - startTime, err := utils.ParseTimeDetectLayout(val1, config.CgrConfig().GeneralCfg().DefaultTimezone) - if err != nil { - return false, err - } - return startTime.Before(timeStrVal), nil + return startTime.Before(timeVal), nil } func verifyInlineFilterS(fltrs []string) (err error) { diff --git a/engine/filters_test.go b/engine/filters_test.go index 24da506f9..1a4663602 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -1059,6 +1059,26 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) { } else if pass { t.Errorf("Expecting: %+v, received: %+v", false, pass) } + + pEv = utils.MapStorage{utils.MetaReq: utils.MapStorage{utils.AccountField: "sip:12345678901234567@abcdefg"}} + if pass, err := filterS.Pass("cgrates.org", + []string{"*regex:~*req.Account:.{29,}"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if !pass { + t.Errorf("Expecting: %+v, received: %+v", true, pass) + } + if pass, err := filterS.Pass("cgrates.org", + []string{"*regex:~*req.Account:^.{28}$"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if pass { + t.Errorf("Expecting: %+v, received: %+v", false, pass) + } + if pass, err := filterS.Pass("cgrates.org", + []string{"*gte:~*req.Account{*len}:29"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if !pass { + t.Errorf("Expecting: %+v, received: %+v", true, pass) + } } func TestPassFiltersForEventWithEmptyFilter(t *testing.T) { @@ -2199,7 +2219,7 @@ func TestFiltersPassGreaterThanErrIncomparable(t *testing.T) { } dtP := utils.MapStorage{ utils.MetaReq: map[string]interface{}{ - utils.MetaUsage: "10", + utils.Usage: nil, }, } diff --git a/packages/debian/changelog b/packages/debian/changelog index c5a023691..81a6c79ce 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -165,6 +165,8 @@ cgrates (0.11.0~dev) UNRELEASED; urgency=medium * [StatS] AverageCallCost and TotalCallCost now returns error for negative Cost field * [SessionS] The sessions are no longer terminated on shutdown if the replication_conns are set * [FilterS] Added *regex filter + * [RSRParsers] Added *len dataconverter + -- DanB Wed, 19 Feb 2020 13:25:52 +0200 cgrates (0.10.0) UNRELEASED; urgency=medium diff --git a/utils/consts.go b/utils/consts.go index a679acb80..312064756 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -772,6 +772,7 @@ const ( MetaIP2Hex = "*ip2hex" MetaString2Hex = "*string2hex" MetaUnixTime = "*unixtime" + MetaLen = "*len" MetaSIPURIMethod = "*sipuri_method" MetaSIPURIHost = "*sipuri_host" MetaSIPURIUser = "*sipuri_user" diff --git a/utils/dataconverter.go b/utils/dataconverter.go index e88bcd9e5..2139a3bda 100644 --- a/utils/dataconverter.go +++ b/utils/dataconverter.go @@ -20,6 +20,7 @@ package utils import ( "encoding/hex" + "encoding/json" "fmt" "math/rand" "net" @@ -87,6 +88,8 @@ func NewDataConverter(params string) (conv DataConverter, err error) { return new(SIPURIMethodConverter), nil case params == MetaUnixTime: return new(UnixTimeConverter), nil + case params == MetaLen: + return new(LengthConverter), nil case strings.HasPrefix(params, MetaLibPhoneNumber): if len(params) == len(MetaLibPhoneNumber) { return NewPhoneNumberConverter(EmptyString) @@ -446,3 +449,19 @@ func (rC *RandomConverter) Convert(in interface{}) ( } } } + +// LengthConverter converts the interface in the unix time +type LengthConverter struct{} + +// Convert implements DataConverter interface +func (LengthConverter) Convert(in interface{}) (out interface{}, err error) { + src := IfaceAsString(in) + if strings.HasPrefix(src, IdxStart) && + strings.HasSuffix(src, IdxEnd) { // it has a similar structure to a json marshaled slice + var slice []interface{} + if err := json.Unmarshal([]byte(src), &slice); err == nil { // no error when unmarshal safe to asume that this is a slice + return len(slice), nil + } + } + return len(src), nil +}