mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
AttributeProfile add Blocker for multiple runs and add tests
This commit is contained in:
committed by
Dan Christian Bogos
parent
a6cac1de00
commit
dea8810abc
@@ -1,3 +1,3 @@
|
||||
#Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Weight
|
||||
cgrates.org,ATTR_1,*sessions;*cdrs,*string:Account:1007,2014-01-14T00:00:00Z,Account,*any,1001,false,10
|
||||
cgrates.org,ATTR_1,,,,Subject,*any,1001,true,
|
||||
#Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Blocker,Weight
|
||||
cgrates.org,ATTR_1,*sessions;*cdrs,*string:Account:1007,2014-01-14T00:00:00Z,Account,*any,1001,false,false,10
|
||||
cgrates.org,ATTR_1,,,,Subject,*any,1001,true,,
|
||||
|
||||
|
@@ -1,2 +1,2 @@
|
||||
#Tenant,ID,Context,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Weight
|
||||
cgrates.org,ATTR_ACNT_1001,*sessions,FLTR_ACCOUNT_1001,,OfficeGroup,*any,Marketing,true,10
|
||||
#Tenant,ID,Context,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Blocker,Weight
|
||||
cgrates.org,ATTR_ACNT_1001,*sessions,FLTR_ACCOUNT_1001,,OfficeGroup,*any,Marketing,true,false,10
|
||||
|
||||
|
@@ -1,3 +1,3 @@
|
||||
#,Tenant,ID,Context,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Weight
|
||||
cgrates.org,ALS1,con1,FLTR_1,2014-07-29T15:00:00Z,Field1,Initial1,Sub1,true,20
|
||||
cgrates.org,ALS1,,,,Field2,Initial2,Sub2,false,
|
||||
#,Tenant,ID,Context,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Blocker,Weight
|
||||
cgrates.org,ALS1,con1,FLTR_1,2014-07-29T15:00:00Z,Field1,Initial1,Sub1,true,false,20
|
||||
cgrates.org,ALS1,,,,Field2,Initial2,Sub2,false,,
|
||||
|
||||
|
@@ -1,15 +1,15 @@
|
||||
#Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Weight
|
||||
cgrates.org,ATTR_1001_SIMPLEAUTH,simpleauth,*string:Account:1001,,Password,*any,CGRateS.org,true,20
|
||||
cgrates.org,ATTR_1002_SIMPLEAUTH,simpleauth,*string:Account:1002,,Password,*any,CGRateS.org,true,20
|
||||
cgrates.org,ATTR_1003_SIMPLEAUTH,simpleauth,*string:Account:1003,,Password,*any,CGRateS.org,true,20
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,*sessions,*string:Account:1001,,Password,*any,CGRateS.org,true,10
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,,,,RequestType,*any,*prepaid,true,
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,,,,PaypalAccount,*any,cgrates@paypal.com,true,
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,,,,LCRProfile,*any,premium_cli,true,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,*sessions,*string:Account:1002,,Password,*any,CGRateS.org,true,10
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,RequestType,*any,*postpaid,true,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,PaypalAccount,*any,cgrates@paypal.com,true,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,LCRProfile,*any,premium_cli,true,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,ResourceAllocation,*any,"ResGroup1",true,
|
||||
#Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Blocker,Weight
|
||||
cgrates.org,ATTR_1001_SIMPLEAUTH,simpleauth,*string:Account:1001,,Password,*any,CGRateS.org,true,false,20
|
||||
cgrates.org,ATTR_1002_SIMPLEAUTH,simpleauth,*string:Account:1002,,Password,*any,CGRateS.org,true,false,20
|
||||
cgrates.org,ATTR_1003_SIMPLEAUTH,simpleauth,*string:Account:1003,,Password,*any,CGRateS.org,true,false,20
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,*sessions,*string:Account:1001,,Password,*any,CGRateS.org,true,false,10
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,,,,RequestType,*any,*prepaid,true,,
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,,,,PaypalAccount,*any,cgrates@paypal.com,true,,
|
||||
cgrates.org,ATTR_1001_SESSIONAUTH,,,,LCRProfile,*any,premium_cli,true,,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,*sessions,*string:Account:1002,,Password,*any,CGRateS.org,true,false,10
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,RequestType,*any,*postpaid,true,,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,PaypalAccount,*any,cgrates@paypal.com,true,,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,LCRProfile,*any,premium_cli,true,,
|
||||
cgrates.org,ATTR_1002_SESSIONAUTH,,,,ResourceAllocation,*any,"ResGroup1",true,,
|
||||
|
||||
|
||||
|
||||
|
@@ -125,7 +125,6 @@ func (dS *DispatcherService) authorize(method, tenant, apiKey string, evTime *ti
|
||||
return
|
||||
}
|
||||
var apiMethods string
|
||||
fmt.Printf("\nRPL EV : %+v\n", utils.ToJSON(rplyEv))
|
||||
if apiMethods, err = rplyEv.CGREvent.FieldAsString(utils.APIMethods); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ type AttrSProcessEventReply struct {
|
||||
MatchedProfiles []string
|
||||
AlteredFields []string
|
||||
CGREvent *utils.CGREvent
|
||||
blocker bool
|
||||
}
|
||||
|
||||
// Digest returns serialized version of alteredFields in AttrSProcessEventReply
|
||||
@@ -174,7 +175,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
|
||||
}
|
||||
rply = &AttrSProcessEventReply{
|
||||
MatchedProfiles: []string{attrPrf.ID},
|
||||
CGREvent: args.Clone()}
|
||||
CGREvent: args.Clone(),
|
||||
blocker: attrPrf.Blocker}
|
||||
for fldName, initialMp := range attrPrf.attributesIdx {
|
||||
initEvValIf, has := args.Event[fldName]
|
||||
if !has {
|
||||
@@ -255,6 +257,9 @@ func (alS *AttributeService) V1ProcessEvent(args *AttrArgsProcessEvent,
|
||||
}
|
||||
if apiRply == nil { // first reply
|
||||
apiRply = evRply
|
||||
if apiRply.blocker == true {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
if utils.IsSliceMember(apiRply.MatchedProfiles,
|
||||
@@ -269,6 +274,9 @@ func (alS *AttributeService) V1ProcessEvent(args *AttrArgsProcessEvent,
|
||||
}
|
||||
apiRply.AlteredFields = append(apiRply.AlteredFields, fldName)
|
||||
}
|
||||
if evRply.blocker == true {
|
||||
break
|
||||
}
|
||||
}
|
||||
*reply = *apiRply
|
||||
return
|
||||
|
||||
@@ -966,3 +966,232 @@ func TestAttributeProcessWithMultipleRuns4(t *testing.T) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttributeMultipleProcessWithBlocker(t *testing.T) {
|
||||
//refresh the DM
|
||||
if err := dmAtr.DataDB().Flush(""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
||||
t.Error(err)
|
||||
} else if test != true {
|
||||
t.Errorf("\nExpecting: true got :%+v", test)
|
||||
}
|
||||
attrPrf1 := &AttributeProfile{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: "ATTR_1",
|
||||
Contexts: []string{utils.MetaSessionS},
|
||||
FilterIDs: []string{"*string:InitialField:InitialValue"},
|
||||
ActivationInterval: &utils.ActivationInterval{
|
||||
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
},
|
||||
Attributes: []*Attribute{
|
||||
&Attribute{
|
||||
FieldName: "Field1",
|
||||
Initial: utils.META_ANY,
|
||||
Substitute: utils.NewRSRParsersMustCompile("Value1", true),
|
||||
Append: true,
|
||||
},
|
||||
},
|
||||
Weight: 10,
|
||||
}
|
||||
attrPrf2 := &AttributeProfile{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: "ATTR_2",
|
||||
Contexts: []string{utils.MetaSessionS},
|
||||
FilterIDs: []string{"*string:Field1:Value1"},
|
||||
ActivationInterval: &utils.ActivationInterval{
|
||||
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
},
|
||||
Attributes: []*Attribute{
|
||||
&Attribute{
|
||||
FieldName: "Field2",
|
||||
Initial: utils.META_ANY,
|
||||
Substitute: utils.NewRSRParsersMustCompile("Value2", true),
|
||||
Append: true,
|
||||
},
|
||||
},
|
||||
Blocker: true,
|
||||
Weight: 20,
|
||||
}
|
||||
attrPrf3 := &AttributeProfile{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: "ATTR_3",
|
||||
Contexts: []string{utils.MetaSessionS},
|
||||
FilterIDs: []string{"*string:Field2:Value2"},
|
||||
ActivationInterval: &utils.ActivationInterval{
|
||||
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
},
|
||||
Attributes: []*Attribute{
|
||||
&Attribute{
|
||||
FieldName: "Field3",
|
||||
Initial: utils.META_ANY,
|
||||
Substitute: utils.NewRSRParsersMustCompile("Value3", true),
|
||||
Append: true,
|
||||
},
|
||||
},
|
||||
Weight: 30,
|
||||
}
|
||||
// Add attribute in DM
|
||||
if err := dmAtr.SetAttributeProfile(attrPrf1, true); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err = dmAtr.SetAttributeProfile(attrPrf2, true); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
if err = dmAtr.SetAttributeProfile(attrPrf3, true); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
attrArgs := &AttrArgsProcessEvent{
|
||||
ProcessRuns: utils.IntPointer(4),
|
||||
CGREvent: utils.CGREvent{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: utils.GenUUID(),
|
||||
Context: utils.StringPointer(utils.MetaSessionS),
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
},
|
||||
},
|
||||
}
|
||||
eRply := &AttrSProcessEventReply{
|
||||
MatchedProfiles: []string{"ATTR_1", "ATTR_2"},
|
||||
AlteredFields: []string{"Field1", "Field2"},
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: utils.GenUUID(),
|
||||
Context: utils.StringPointer(utils.MetaSessionS),
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
"Field1": "Value1",
|
||||
"Field2": "Value2",
|
||||
},
|
||||
},
|
||||
}
|
||||
var reply AttrSProcessEventReply
|
||||
if err := attrService.V1ProcessEvent(attrArgs, &reply); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(eRply.MatchedProfiles, reply.MatchedProfiles) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.MatchedProfiles, reply.MatchedProfiles)
|
||||
}
|
||||
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
||||
}
|
||||
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttributeMultipleProcessWithBlocker2(t *testing.T) {
|
||||
//refresh the DM
|
||||
if err := dmAtr.DataDB().Flush(""); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if test, err := dmAtr.DataDB().IsDBEmpty(); err != nil {
|
||||
t.Error(err)
|
||||
} else if test != true {
|
||||
t.Errorf("\nExpecting: true got :%+v", test)
|
||||
}
|
||||
attrPrf1 := &AttributeProfile{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: "ATTR_1",
|
||||
Contexts: []string{utils.MetaSessionS},
|
||||
FilterIDs: []string{"*string:InitialField:InitialValue"},
|
||||
ActivationInterval: &utils.ActivationInterval{
|
||||
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
},
|
||||
Attributes: []*Attribute{
|
||||
&Attribute{
|
||||
FieldName: "Field1",
|
||||
Initial: utils.META_ANY,
|
||||
Substitute: utils.NewRSRParsersMustCompile("Value1", true),
|
||||
Append: true,
|
||||
},
|
||||
},
|
||||
Blocker: true,
|
||||
Weight: 10,
|
||||
}
|
||||
attrPrf2 := &AttributeProfile{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: "ATTR_2",
|
||||
Contexts: []string{utils.MetaSessionS},
|
||||
FilterIDs: []string{"*string:Field1:Value1"},
|
||||
ActivationInterval: &utils.ActivationInterval{
|
||||
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
},
|
||||
Attributes: []*Attribute{
|
||||
&Attribute{
|
||||
FieldName: "Field2",
|
||||
Initial: utils.META_ANY,
|
||||
Substitute: utils.NewRSRParsersMustCompile("Value2", true),
|
||||
Append: true,
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
}
|
||||
attrPrf3 := &AttributeProfile{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: "ATTR_3",
|
||||
Contexts: []string{utils.MetaSessionS},
|
||||
FilterIDs: []string{"*string:Field2:Value2"},
|
||||
ActivationInterval: &utils.ActivationInterval{
|
||||
ActivationTime: time.Date(2014, 7, 14, 14, 25, 0, 0, time.UTC),
|
||||
},
|
||||
Attributes: []*Attribute{
|
||||
&Attribute{
|
||||
FieldName: "Field3",
|
||||
Initial: utils.META_ANY,
|
||||
Substitute: utils.NewRSRParsersMustCompile("Value3", true),
|
||||
Append: true,
|
||||
},
|
||||
},
|
||||
Weight: 30,
|
||||
}
|
||||
// Add attribute in DM
|
||||
if err := dmAtr.SetAttributeProfile(attrPrf1, true); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err = dmAtr.SetAttributeProfile(attrPrf2, true); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
if err = dmAtr.SetAttributeProfile(attrPrf3, true); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
attrArgs := &AttrArgsProcessEvent{
|
||||
ProcessRuns: utils.IntPointer(4),
|
||||
CGREvent: utils.CGREvent{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: utils.GenUUID(),
|
||||
Context: utils.StringPointer(utils.MetaSessionS),
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
},
|
||||
},
|
||||
}
|
||||
eRply := &AttrSProcessEventReply{
|
||||
MatchedProfiles: []string{"ATTR_1"},
|
||||
AlteredFields: []string{"Field1"},
|
||||
CGREvent: &utils.CGREvent{
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
ID: utils.GenUUID(),
|
||||
Context: utils.StringPointer(utils.MetaSessionS),
|
||||
Event: map[string]interface{}{
|
||||
"InitialField": "InitialValue",
|
||||
"Field1": "Value1",
|
||||
},
|
||||
},
|
||||
}
|
||||
var reply AttrSProcessEventReply
|
||||
if err := attrService.V1ProcessEvent(attrArgs, &reply); err != nil {
|
||||
t.Errorf("Error: %+v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(eRply.MatchedProfiles, reply.MatchedProfiles) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.MatchedProfiles, reply.MatchedProfiles)
|
||||
}
|
||||
if !reflect.DeepEqual(eRply.AlteredFields, reply.AlteredFields) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.AlteredFields, reply.AlteredFields)
|
||||
}
|
||||
if !reflect.DeepEqual(eRply.CGREvent.Event, reply.CGREvent.Event) {
|
||||
t.Errorf("Expecting %+v, received: %+v", eRply.CGREvent.Event, reply.CGREvent.Event)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ type AttributeProfile struct {
|
||||
FilterIDs []string
|
||||
ActivationInterval *utils.ActivationInterval // Activation interval
|
||||
Attributes []*Attribute
|
||||
Blocker bool // blocker flag to stop processing on multiple runs
|
||||
Weight float64
|
||||
|
||||
attributesIdx map[string]map[interface{}]*Attribute // map[FieldName][InitialValue]*Attribute, used as event match index
|
||||
|
||||
@@ -299,9 +299,9 @@ cgrates.org,SPP_1,,,,,supplier1,FLTR_DST_DE,Account2,RPL_3,ResGroup3,Stat2,10,,,
|
||||
cgrates.org,SPP_1,,,,,supplier1,,,,ResGroup4,Stat3,10,,,
|
||||
`
|
||||
attributeProfiles = `
|
||||
#Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Weight
|
||||
cgrates.org,ALS1,con1,FLTR_1,2014-07-29T15:00:00Z,Field1,Initial1,Sub1,true,20
|
||||
cgrates.org,ALS1,con2;con3,,,Field2,Initial2,Sub2,false,
|
||||
#Tenant,ID,Contexts,FilterIDs,ActivationInterval,FieldName,Initial,Substitute,Append,Blocker,Weight
|
||||
cgrates.org,ALS1,con1,FLTR_1,2014-07-29T15:00:00Z,Field1,Initial1,Sub1,true,true,20
|
||||
cgrates.org,ALS1,con2;con3,,,Field2,Initial2,Sub2,false,,
|
||||
`
|
||||
chargerProfiles = `
|
||||
#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight
|
||||
@@ -1771,7 +1771,8 @@ func TestLoadAttributeProfiles(t *testing.T) {
|
||||
Append: false,
|
||||
},
|
||||
},
|
||||
Weight: 20,
|
||||
Blocker: true,
|
||||
Weight: 20,
|
||||
},
|
||||
}
|
||||
resKey := utils.TenantID{Tenant: "cgrates.org", ID: "ALS1"}
|
||||
@@ -1789,6 +1790,8 @@ func TestLoadAttributeProfiles(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].ActivationInterval, csvr.attributeProfiles[resKey].ActivationInterval)
|
||||
} else if !reflect.DeepEqual(eAttrProfiles[resKey].Attributes, csvr.attributeProfiles[resKey].Attributes) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].Attributes, csvr.attributeProfiles[resKey].Attributes)
|
||||
} else if !reflect.DeepEqual(eAttrProfiles[resKey].Blocker, csvr.attributeProfiles[resKey].Blocker) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eAttrProfiles[resKey].Blocker, csvr.attributeProfiles[resKey].Blocker)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2684,9 +2684,10 @@ func (tps TPAttributes) AsTPAttributes() (result []*utils.TPAttributeProfile) {
|
||||
th, found := mst[(&utils.TenantID{Tenant: tp.Tenant, ID: tp.ID}).TenantID()]
|
||||
if !found {
|
||||
th = &utils.TPAttributeProfile{
|
||||
TPid: tp.Tpid,
|
||||
Tenant: tp.Tenant,
|
||||
ID: tp.ID,
|
||||
TPid: tp.Tpid,
|
||||
Tenant: tp.Tenant,
|
||||
ID: tp.ID,
|
||||
Blocker: tp.Blocker,
|
||||
}
|
||||
}
|
||||
if tp.Weight != 0 {
|
||||
@@ -2756,6 +2757,7 @@ func APItoModelTPAttribute(th *utils.TPAttributeProfile) (mdls TPAttributes) {
|
||||
ID: th.ID,
|
||||
}
|
||||
if i == 0 {
|
||||
mdl.Blocker = th.Blocker
|
||||
if th.ActivationInterval != nil {
|
||||
if th.ActivationInterval.ActivationTime != "" {
|
||||
mdl.ActivationInterval = th.ActivationInterval.ActivationTime
|
||||
@@ -2794,6 +2796,7 @@ func APItoAttributeProfile(tpTH *utils.TPAttributeProfile, timezone string) (th
|
||||
Tenant: tpTH.Tenant,
|
||||
ID: tpTH.ID,
|
||||
Weight: tpTH.Weight,
|
||||
Blocker: tpTH.Blocker,
|
||||
FilterIDs: []string{},
|
||||
Contexts: []string{},
|
||||
}
|
||||
|
||||
@@ -555,7 +555,8 @@ type TPAttribute struct {
|
||||
Initial string `index:"6" re:""`
|
||||
Substitute string `index:"7" re:""`
|
||||
Append bool `index:"8" re:""`
|
||||
Weight float64 `index:"9" re:"\d+\.?\d*"`
|
||||
Blocker bool `index:"9" re:""`
|
||||
Weight float64 `index:"10" re:"\d+\.?\d*"`
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
|
||||
@@ -1423,6 +1423,7 @@ type TPAttributeProfile struct {
|
||||
ActivationInterval *TPActivationInterval // Time when this limit becomes active and expires
|
||||
Contexts []string // bind this TPAttribute to multiple context
|
||||
Attributes []*TPAttribute
|
||||
Blocker bool
|
||||
Weight float64
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user