From a86045b1caa1e031a11a469530722d795e402fb4 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Thu, 12 Nov 2015 15:01:43 +0200 Subject: [PATCH] weight for user profile fixes #219 --- .../mysql/create_tariffplan_tables.sql | 1 + .../postgres/create_tariffplan_tables.sql | 1 + data/tariffplans/prepaid1centpsec/Users.csv | 38 +++++++------- data/tariffplans/tutorial/Users.csv | 38 +++++++------- engine/loader_csv_test.go | 8 +-- engine/model_converters.go | 5 +- engine/model_helpers.go | 1 + engine/models.go | 15 +++--- engine/users.go | 50 +++++++++++-------- engine/users_test.go | 32 +++++++++++- utils/apitpdata.go | 1 + 11 files changed, 115 insertions(+), 75 deletions(-) diff --git a/data/storage/mysql/create_tariffplan_tables.sql b/data/storage/mysql/create_tariffplan_tables.sql index facb3f7b9..1c4e6c940 100644 --- a/data/storage/mysql/create_tariffplan_tables.sql +++ b/data/storage/mysql/create_tariffplan_tables.sql @@ -354,6 +354,7 @@ CREATE TABLE tp_users ( `masked` BOOLEAN NOT NULL, `attribute_name` varchar(64) NOT NULL, `attribute_value` varchar(64) NOT NULL, + `weight` DECIMAL(8,2) NOT NULL, `created_at` TIMESTAMP, PRIMARY KEY (`id`), KEY `tpid` (`tpid`) diff --git a/data/storage/postgres/create_tariffplan_tables.sql b/data/storage/postgres/create_tariffplan_tables.sql index 0c2600dc4..af915a093 100644 --- a/data/storage/postgres/create_tariffplan_tables.sql +++ b/data/storage/postgres/create_tariffplan_tables.sql @@ -349,6 +349,7 @@ CREATE TABLE tp_users ( masked BOOLEAN NOT NULL, attribute_name VARCHAR(64) NOT NULL, attribute_value VARCHAR(64) NOT NULL, + weight NUMERIC(8,2) NOT NULL, created_at TIMESTAMP ); CREATE INDEX tpusers_tpid_idx ON tp_users (tpid); diff --git a/data/tariffplans/prepaid1centpsec/Users.csv b/data/tariffplans/prepaid1centpsec/Users.csv index 7c2ca95ed..006652ff9 100644 --- a/data/tariffplans/prepaid1centpsec/Users.csv +++ b/data/tariffplans/prepaid1centpsec/Users.csv @@ -1,19 +1,19 @@ -#Tenant[0],UserName[1],Maksed[2],AttributeName[3],AttributeValue[4] -cgrates.org,1001,,SysUserName,danb -cgrates.org,1001,,SysPassword,hisPass321 -cgrates.org,1001,,Cli,+4986517174963 -cgrates.org,1001,,Account,1001 -cgrates.org,1001,,Subject,1001 -cgrates.org,1001,,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e -cgrates.org,1001,,ReqType,*prepaid -cgrates.org,1002,,SysUserName,rif -cgrates.org,1002,,RifAttr,RifVal -cgrates.org,1002,,Account,1002 -cgrates.org,1002,,Subject,1002 -cgrates.org,1002,,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5 -cgrates.org,1004,,SysUserName,danb4 -cgrates.org,1004,,SysPassword,hisPass321 -cgrates.org,1004,,Cli,+4986517174964 -cgrates.org,1004,,Account,1004 -cgrates.org,1004,,Subject,1004 -cgrates.org,1004,,ReqType,*rated +#Tenant[0],UserName[1],Maksed[2],AttributeName[3],AttributeValue[4],Weight[5] +cgrates.org,1001,,SysUserName,danb,10 +cgrates.org,1001,,SysPassword,hisPass321,10 +cgrates.org,1001,,Cli,+4986517174963,10 +cgrates.org,1001,,Account,1001,10 +cgrates.org,1001,,Subject,1001,10 +cgrates.org,1001,,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e,10 +cgrates.org,1001,,ReqType,*prepaid,10 +cgrates.org,1002,,SysUserName,rif,10 +cgrates.org,1002,,RifAttr,RifVal,10 +cgrates.org,1002,,Account,1002,10 +cgrates.org,1002,,Subject,1002,10 +cgrates.org,1002,,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5,10 +cgrates.org,1004,,SysUserName,danb4,10 +cgrates.org,1004,,SysPassword,hisPass321,10 +cgrates.org,1004,,Cli,+4986517174964,10 +cgrates.org,1004,,Account,1004,10 +cgrates.org,1004,,Subject,1004,10 +cgrates.org,1004,,ReqType,*rated,10 diff --git a/data/tariffplans/tutorial/Users.csv b/data/tariffplans/tutorial/Users.csv index 24cc9575e..be6f1614a 100644 --- a/data/tariffplans/tutorial/Users.csv +++ b/data/tariffplans/tutorial/Users.csv @@ -1,19 +1,19 @@ -#Tenant[0],UserName[1],Masked[2],AttributeName[3],AttributeValue[4] -cgrates.org,1001,,SysUserName,danb -cgrates.org,1001,,SysPassword,hisPass321 -cgrates.org,1001,,Cli,+4986517174963 -cgrates.org,1001,,Account,1001 -cgrates.org,1001,,Subject,1001 -cgrates.org,1001,,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e -cgrates.org,1001,,ReqType,*prepaid -cgrates.org,1002,,SysUserName,rif -cgrates.org,1002,,RifAttr,RifVal -cgrates.org,1002,,Account,1002 -cgrates.org,1002,,Subject,1002 -cgrates.org,1002,,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5 -cgrates.org,1004,,SysUserName,danb4 -cgrates.org,1004,,SysPassword,hisPass321 -cgrates.org,1004,,Cli,+4986517174964 -cgrates.org,1004,,Account,1004 -cgrates.org,1004,,Subject,1004 -cgrates.org,1004,,ReqType,*rated +#Tenant[0],UserName[1],Masked[2],AttributeName[3],AttributeValue[4],Weight[5] +cgrates.org,1001,,SysUserName,danb,10 +cgrates.org,1001,,SysPassword,hisPass321,10 +cgrates.org,1001,,Cli,+4986517174963,10 +cgrates.org,1001,,Account,1001,10 +cgrates.org,1001,,Subject,1001,10 +cgrates.org,1001,,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e,10 +cgrates.org,1001,,ReqType,*prepaid,10 +cgrates.org,1002,,SysUserName,rif,10 +cgrates.org,1002,,RifAttr,RifVal,10 +cgrates.org,1002,,Account,1002,10 +cgrates.org,1002,,Subject,1002,10 +cgrates.org,1002,,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5,10 +cgrates.org,1004,,SysUserName,danb4,10 +cgrates.org,1004,,SysPassword,hisPass321,10 +cgrates.org,1004,,Cli,+4986517174964,10 +cgrates.org,1004,,Account,1004,10 +cgrates.org,1004,,Subject,1004,10 +cgrates.org,1004,,ReqType,*rated,10 diff --git a/engine/loader_csv_test.go b/engine/loader_csv_test.go index 86520b32d..9154b72e2 100644 --- a/engine/loader_csv_test.go +++ b/engine/loader_csv_test.go @@ -223,10 +223,10 @@ CDRST2,,,,ACD,,,,,,,,,,,,,,,,,,,, ` users = ` #Tenant[0],UserName[1],AttributeName[2],AttributeValue[3] -cgrates.org,rif,false,test0,val0 -cgrates.org,rif,,test1,val1 -cgrates.org,dan,,another,value -cgrates.org,mas,true,another,value +cgrates.org,rif,false,test0,val0,10 +cgrates.org,rif,,test1,val1,10 +cgrates.org,dan,,another,value,10 +cgrates.org,mas,true,another,value,10 ` aliases = ` #Direction[0],Tenant[1],Category[2],Account[3],Subject[4],DestinationId[5],Group[6],Alias[7],Weight[8] diff --git a/engine/model_converters.go b/engine/model_converters.go index 5dace97df..7a0eb694d 100644 --- a/engine/model_converters.go +++ b/engine/model_converters.go @@ -177,7 +177,7 @@ func APItoModelAction(as *utils.TPActions) (result []TpAction) { DestinationTags: a.DestinationIds, RatingSubject: a.RatingSubject, Categories: a.Categories, - SharedGroups: a.SharedGroups, + SharedGroups: a.SharedGroups, BalanceWeight: a.BalanceWeight, ExtraParameters: a.ExtraParameters, Weight: a.Weight, @@ -230,7 +230,7 @@ func APItoModelActionTrigger(ats *utils.TPActionTriggers) (result []TpActionTrig BalanceTimingTags: at.BalanceTimingTags, BalanceRatingSubject: at.BalanceRatingSubject, BalanceCategories: at.BalanceCategories, - BalanceSharedGroups: at.BalanceSharedGroups, + BalanceSharedGroups: at.BalanceSharedGroups, BalanceDisabled: at.BalanceDisabled, MinQueuedItems: at.MinQueuedItems, ActionsTag: at.ActionsId, @@ -393,6 +393,7 @@ func APItoModelUsers(attr *utils.TPUsers) (result []TpUser) { UserName: attr.UserName, AttributeName: p.AttrName, AttributeValue: p.AttrValue, + Weight: attr.Weight, }) } if len(attr.Profile) == 0 { diff --git a/engine/model_helpers.go b/engine/model_helpers.go index ddc117d33..9897f69a1 100644 --- a/engine/model_helpers.go +++ b/engine/model_helpers.go @@ -730,6 +730,7 @@ func (tps TpUsers) GetUsers() (map[string]*utils.TPUsers, error) { user = &utils.TPUsers{ Tenant: tp.Tenant, UserName: tp.UserName, + Weight: tp.Weight, } users[tp.GetId()] = user } diff --git a/engine/models.go b/engine/models.go index 59aff1737..99aa63ddb 100644 --- a/engine/models.go +++ b/engine/models.go @@ -162,7 +162,7 @@ type TpAction struct { Categories string `index:"6" re:""` DestinationTags string `index:"7" re:"\*any|\w+\s*"` RatingSubject string `index:"8" re:"\w+\s*"` - SharedGroups string `index:"9" re:"[0-9A-Za-z_;]*"` + SharedGroups string `index:"9" re:"[0-9A-Za-z_;]*"` ExpiryTime string `index:"10" re:"\*\w+\s*|\+\d+[smh]\s*|\d+\s*"` TimingTags string `index:"11" re:"[0-9A-Za-z_;]*|\*any"` Units float64 `index:"12" re:"\d+\s*"` @@ -197,7 +197,7 @@ type TpActionTrigger struct { BalanceCategories string `index:"9" re:""` BalanceDestinationTags string `index:"10" re:"\w+|\*any"` BalanceRatingSubject string `index:"11" re:"\w+|\*any"` - BalanceSharedGroups string `index:"12" re:"\w+|\*any"` + BalanceSharedGroups string `index:"12" re:"\w+|\*any"` BalanceExpiryTime string `index:"13" re:"\*\w+\s*|\+\d+[smh]\s*|\d+\s*"` BalanceTimingTags string `index:"14" re:"[0-9A-Za-z_;]*|\*any"` BalanceWeight float64 `index:"15" re:"\d+\.?\d*"` @@ -331,11 +331,12 @@ func (t TpCdrstat) TableName() string { type TpUser struct { Id int64 Tpid string - Tenant string `index:"0" re:""` - UserName string `index:"1" re:""` - Masked bool `index:"2" re:""` - AttributeName string `index:"3" re:""` - AttributeValue string `index:"4" re:""` + Tenant string `index:"0" re:""` + UserName string `index:"1" re:""` + Masked bool `index:"2" re:""` + AttributeName string `index:"3" re:""` + AttributeValue string `index:"4" re:""` + Weight float64 `index:"5" re:""` } func (tu *TpUser) GetId() string { diff --git a/engine/users.go b/engine/users.go index fbc2ab744..ee4e241fb 100644 --- a/engine/users.go +++ b/engine/users.go @@ -15,6 +15,7 @@ type UserProfile struct { UserName string Masked bool Profile map[string]string + Weight float64 ponder int } @@ -28,8 +29,9 @@ func (ups UserProfiles) Swap(i, j int) { ups[i], ups[j] = ups[j], ups[i] } -func (ups UserProfiles) Less(j, i int) bool { // get higher ponder in front - return ups[i].ponder < ups[j].ponder +func (ups UserProfiles) Less(j, i int) bool { // get higher Weight and ponder in front + return ups[i].Weight < ups[j].Weight || + (ups[i].Weight == ups[j].Weight && ups[i].ponder < ups[j].ponder) } func (ups UserProfiles) Sort() { @@ -60,9 +62,14 @@ type UserService interface { ReloadUsers(string, *string) error } +type prop struct { + masked bool + weight float64 +} + type UserMap struct { table map[string]map[string]string - masked map[string]bool + properties map[string]*prop index map[string]map[string]bool indexKeys []string accountingDb AccountingStorage @@ -81,7 +88,7 @@ func NewUserMap(accountingDb AccountingStorage, indexes []string) (*UserMap, err func newUserMap(accountingDb AccountingStorage, indexes []string) *UserMap { return &UserMap{ table: make(map[string]map[string]string), - masked: make(map[string]bool), + properties: make(map[string]*prop), index: make(map[string]map[string]bool), indexKeys: indexes, accountingDb: accountingDb, @@ -94,24 +101,22 @@ func (um *UserMap) ReloadUsers(in string, reply *string) error { // backup old data oldTable := um.table oldIndex := um.index - oldMaksed := um.masked + oldProperties := um.properties um.table = make(map[string]map[string]string) um.index = make(map[string]map[string]bool) - um.masked = make(map[string]bool) + um.properties = make(map[string]*prop) // load from db if ups, err := um.accountingDb.GetUsers(); err == nil { for _, up := range ups { um.table[up.GetId()] = up.Profile - if up.Masked { - um.masked[up.GetId()] = true - } + um.properties[up.GetId()] = &prop{weight: up.Weight, masked: up.Masked} } } else { // restore old data before return um.table = oldTable um.index = oldIndex - um.masked = oldMaksed + um.properties = oldProperties *reply = err.Error() return err @@ -124,7 +129,7 @@ func (um *UserMap) ReloadUsers(in string, reply *string) error { utils.Logger.Err(fmt.Sprintf("Error adding %v indexes to user profile service: %v", um.indexKeys, err)) um.table = oldTable um.index = oldIndex - um.masked = oldMaksed + um.properties = oldProperties *reply = err.Error() return err @@ -142,9 +147,7 @@ func (um *UserMap) SetUser(up UserProfile, reply *string) error { return err } um.table[up.GetId()] = up.Profile - if up.Masked { - um.masked[up.GetId()] = true - } + um.properties[up.GetId()] = &prop{weight: up.Weight, masked: up.Masked} um.addIndex(&up, um.indexKeys) *reply = utils.OK return nil @@ -158,7 +161,7 @@ func (um *UserMap) RemoveUser(up UserProfile, reply *string) error { return err } delete(um.table, up.GetId()) - delete(um.masked, up.GetId()) + delete(um.properties, up.GetId()) um.deleteIndex(&up) *reply = utils.OK return nil @@ -172,7 +175,7 @@ func (um *UserMap) UpdateUser(up UserProfile, reply *string) error { *reply = utils.ErrNotFound.Error() return utils.ErrNotFound } - masked := um.masked[up.GetId()] + properties := um.properties[up.GetId()] if m == nil { m = make(map[string]string) } @@ -183,7 +186,8 @@ func (um *UserMap) UpdateUser(up UserProfile, reply *string) error { oldUp := &UserProfile{ Tenant: up.Tenant, UserName: up.UserName, - Masked: masked, + Masked: properties.masked, + Weight: properties.weight, Profile: oldM, } for key, value := range up.Profile { @@ -193,6 +197,7 @@ func (um *UserMap) UpdateUser(up UserProfile, reply *string) error { Tenant: up.Tenant, UserName: up.UserName, Masked: up.Masked, + Weight: up.Weight, Profile: m, } if err := um.accountingDb.SetUser(finalUp); err != nil { @@ -200,9 +205,7 @@ func (um *UserMap) UpdateUser(up UserProfile, reply *string) error { return err } um.table[up.GetId()] = m - if up.Masked == false { - delete(um.masked, up.GetId()) - } + um.properties[up.GetId()] = &prop{weight: up.Weight, masked: up.Masked} um.deleteIndex(oldUp) um.addIndex(finalUp, um.indexKeys) *reply = utils.OK @@ -247,7 +250,7 @@ func (um *UserMap) GetUsers(up UserProfile, results *UserProfiles) error { candidates := make(UserProfiles, 0) // It should not return nil in case of no users but [] for key, values := range table { // skip masked if not asked for - if up.Masked == false && um.masked[key] == true { + if up.Masked == false && um.properties[key] != nil && um.properties[key].masked == true { continue } ponder := 0 @@ -283,7 +286,10 @@ func (um *UserMap) GetUsers(up UserProfile, results *UserProfiles) error { // all filters passed, add to candidates nup := &UserProfile{ Profile: make(map[string]string), - Masked: um.masked[key], + } + if um.properties[key] != nil { + nup.Masked = um.properties[key].masked + nup.Weight = um.properties[key].weight } nup.SetId(key) nup.ponder = ponder diff --git a/engine/users_test.go b/engine/users_test.go index fff0fffa1..0862d96fe 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -17,8 +17,19 @@ var testMap = UserMap{ "test:masked": map[string]string{"t": "v"}, }, index: make(map[string]map[string]bool), - masked: map[string]bool{ - "test:masked": true, + properties: map[string]*prop{ + "test:masked": &prop{masked: true}, + }, +} + +var testMap2 = UserMap{ + table: map[string]map[string]string{ + "an:u1": map[string]string{"a": "b", "c": "d"}, + "an:u2": map[string]string{"a": "b"}, + }, + index: make(map[string]map[string]bool), + properties: map[string]*prop{ + "an:u2": &prop{weight: 10}, }, } @@ -304,6 +315,23 @@ func TestUsersGetMissingIdTwoSort(t *testing.T) { } } +func TestUsersGetMissingIdTwoSortWeight(t *testing.T) { + up := UserProfile{ + Profile: map[string]string{ + "a": "b", + "c": "d", + }, + } + results := UserProfiles{} + testMap2.GetUsers(up, &results) + if len(results) != 2 { + t.Error("error getting users: ", results) + } + if results[0].GetId() != "an:u2" { + t.Errorf("Error sorting profiles: %+v", results[0]) + } +} + func TestUsersAddIndex(t *testing.T) { var r string testMap.AddIndex([]string{"t"}, &r) diff --git a/utils/apitpdata.go b/utils/apitpdata.go index 8ff811f8c..565367c1f 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -345,6 +345,7 @@ type TPUsers struct { Masked bool UserName string Profile []*TPUserProfile + Weight float64 } type TPUserProfile struct {