From 30c327fc5f33f06486d599e199cc04cf5ddac316 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 14 Jul 2015 14:56:18 +0300 Subject: [PATCH 1/7] added stored cdr loader for user profile --- apier/v1/auth.go | 3 +++ apier/v1/debit.go | 4 +++ cmd/cgr-engine/cgr-engine.go | 2 +- engine/calldesc.go | 6 ++++- engine/storedcdr.go | 51 ++++++++++++++++++++++++++++++++++++ engine/storedcdr_test.go | 45 +++++++++++++++++++++++++++++++ utils/consts.go | 1 + 7 files changed, 110 insertions(+), 2 deletions(-) diff --git a/apier/v1/auth.go b/apier/v1/auth.go index 0b548da60..847917927 100644 --- a/apier/v1/auth.go +++ b/apier/v1/auth.go @@ -28,6 +28,9 @@ import ( // Returns MaxUsage (for calls in seconds), -1 for no limit func (self *ApierV1) GetMaxUsage(usageRecord engine.UsageRecord, maxUsage *float64) error { + if err := usageRecord.LoadUserProfile(); err != nil { + return err + } if usageRecord.TOR == "" { usageRecord.TOR = utils.VOICE } diff --git a/apier/v1/debit.go b/apier/v1/debit.go index 321dab63a..f70ea0572 100644 --- a/apier/v1/debit.go +++ b/apier/v1/debit.go @@ -27,6 +27,10 @@ func (self *ApierV1) DebitUsage(usageRecord engine.UsageRecord, reply *string) e if missing := utils.MissingStructFields(&usageRecord, []string{"Account", "Destination", "Usage"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } + if err := usageRecord.LoadUserProfile(); err != nil { + *reply = err.Error() + return err + } if usageRecord.TOR == "" { usageRecord.TOR = utils.VOICE } diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 88d700249..40d41de96 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -541,7 +541,7 @@ func main() { return } } - //engine.SetPubSub(users) + engine.SetUserService(users) }() wg.Wait() diff --git a/engine/calldesc.go b/engine/calldesc.go index 45d3c4289..417f3c0f6 100644 --- a/engine/calldesc.go +++ b/engine/calldesc.go @@ -68,7 +68,7 @@ var ( globalRoundingDecimals = 10 historyScribe history.Scribe pubSubServer PublisherSubscriber - //historyScribe, _ = history.NewMockScribe() + userService UserService ) // Exported method to set the storage getter. @@ -108,6 +108,10 @@ func SetPubSub(ps PublisherSubscriber) { pubSubServer = ps } +func SetUserService(us UserService) { + userService = us +} + func Publish(event CgrEvent) { if pubSubServer != nil { var s string diff --git a/engine/storedcdr.go b/engine/storedcdr.go index ad7c17e73..580fd1d73 100644 --- a/engine/storedcdr.go +++ b/engine/storedcdr.go @@ -20,6 +20,7 @@ package engine import ( "encoding/json" + "log" "math" "net/url" "strconv" @@ -681,3 +682,53 @@ func (self *UsageRecord) AsCallDescriptor() (*CallDescriptor, error) { TimeEnd: startTime.Add(usage), }, nil } + +func (self *UsageRecord) LoadUserProfile() error { + up := &UserProfile{ + Tenant: self.Tenant, + Profile: map[string]string{ + "TOR": self.TOR, + "ReqType": self.ReqType, + "Direction": self.Direction, + "Tenant": self.Tenant, + "Category": self.Category, + "Account": self.Account, + "Subject": self.SetupTime, + "Destination": self.Destination, + "SetupTime": self.SetupTime, + "AnswerTime": self.AnswerTime, + "Usage": self.Usage, + }, + } + // clean *user fields + if up.Tenant == utils.USERS { + up.Tenant = "" + } + for key, value := range up.Profile { + if value == utils.USERS { + delete(up.Profile, key) + } + } + log.Print("UP: ", up.Profile) + ups := make([]*UserProfile, 0) + if err := userService.GetUsers(*up, &ups); err != nil { + return err + } + if len(ups) > 0 { + up = ups[0] // take the first matched user profile + self.TOR = up.Profile["TOR"] + self.ReqType = up.Profile["ReqType"] + self.Direction = up.Profile["Direction"] + self.Tenant = up.Tenant + self.Category = up.Profile["Category"] + self.Account = up.Profile["Account"] + self.Subject = up.Profile["Subject"] + self.Destination = up.Profile["Destination"] + self.SetupTime = up.Profile["SetupTime"] + self.AnswerTime = up.Profile["AnswerTime"] + self.Usage = up.Profile["Usage"] + } else { + return utils.ErrNotFound + } + return nil +} diff --git a/engine/storedcdr_test.go b/engine/storedcdr_test.go index 3163f851a..d6602de14 100644 --- a/engine/storedcdr_test.go +++ b/engine/storedcdr_test.go @@ -549,3 +549,48 @@ func TestUsageReqAsCD(t *testing.T) { t.Errorf("Expected: %+v, received: %+v", eCD, cd) } } + +func TestStoredCDRGetUserProfile(t *testing.T) { + userService = &UserMap{ + table: map[string]map[string]string{ + "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13"}, + }, + index: make(map[string]map[string]bool), + } + + ur := &UsageRecord{ + TOR: utils.USERS, + ReqType: utils.USERS, + Direction: "*out", + Tenant: utils.USERS, + Category: "call", + Account: utils.USERS, + Subject: utils.USERS, + Destination: utils.USERS, + SetupTime: utils.USERS, + AnswerTime: utils.USERS, + Usage: "13", + } + if err := ur.LoadUserProfile(); err != nil { + t.Error("Error loading user profile: ", err) + } + expected := &UsageRecord{ + TOR: "04", + ReqType: "4", + Direction: "*out", + Tenant: "test1", + Category: "call", + Account: "rif", + Subject: "0726", + Destination: "+404", + SetupTime: "s4", + AnswerTime: "t4", + Usage: "13", + } + if !reflect.DeepEqual(ur, expected) { + t.Errorf("Expected: %+v got: %+v", expected, ur) + } +} diff --git a/utils/consts.go b/utils/consts.go index 1c69ac9b1..7300cfcc1 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -83,6 +83,7 @@ const ( ROUNDING_DOWN = "*down" ANY = "*any" ASAP = "*asap" + USERS = "*users" COMMENT_CHAR = '#' CSV_SEP = ',' FALLBACK_SEP = ';' From 0f7cc579f36b5b6822b1d3603826c0be2db8e0a3 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 14 Jul 2015 20:43:22 +0300 Subject: [PATCH 2/7] added struct to map converters --- utils/struct.go | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/utils/struct.go b/utils/struct.go index 46edb4e93..d98954552 100644 --- a/utils/struct.go +++ b/utils/struct.go @@ -61,7 +61,7 @@ func NonemptyStructFields(s interface{}) map[string]interface{} { } // Converts a struct to map -func StrucToMap(s interface{}) map[string]interface{} { +/*func StrucToMap(s interface{}) map[string]interface{} { mp := make(map[string]interface{}) for i := 0; i < reflect.ValueOf(s).Elem().NumField(); i++ { fld := reflect.ValueOf(s).Elem().Field(i) @@ -75,6 +75,46 @@ func StrucToMap(s interface{}) map[string]interface{} { } } return mp +}*/ + +// Converts a struct to map[string]interface{} +func ToMapMapStringInterface(in interface{}) (map[string]interface{}, error) { + out := make(map[string]interface{}) + + v := reflect.ValueOf(in) + if v.Kind() == reflect.Ptr { + v = v.Elem() + } + typ := reflect.TypeOf(in) + for i := 0; i < v.NumField(); i++ { + out[typ.Field(i).Name] = v.Field(i).Interface() + } + return out, nil +} + +// Converts a struct to map[string]string +func ToMapStringInterface(in interface{}) (map[string]string, error) { + out := make(map[string]string) + + v := reflect.ValueOf(in) + if v.Kind() == reflect.Ptr { + v = v.Elem() + in = v.Interface() + } + typ := reflect.TypeOf(in) + for i := 0; i < v.NumField(); i++ { + // gets us a StructField + typField := typ.Field(i) + field := v.Field(i) + switch field.Kind() { + case reflect.String: + val := field.String() + if val != "" { + out[typField.Name] = val + } + } + } + return out, nil } // Update struct with map fields, returns not matching map keys, s is a struct to be updated From e95b2be88db9947f12746e7e00bc64aa8cfba3e2 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 14 Jul 2015 21:23:21 +0300 Subject: [PATCH 3/7] simpler console command interface --- cmd/cgr-console/cgr-console.go | 4 +++- cmd/cgr-engine/cgr-engine.go | 2 +- console/account_add.go | 7 ++----- console/account_remove.go | 7 ++----- console/accountactions_set.go | 7 ++----- console/accounts.go | 7 ++----- console/action_execute.go | 7 ++----- console/active_sessions.go | 7 ++----- console/balance_debit.go | 7 ++----- console/balance_set.go | 7 ++----- console/cache_age.go | 7 ++----- console/cache_reload.go | 7 ++----- console/cache_stats.go | 7 ++----- console/callcost.go | 7 ++----- console/cdrs_export.go | 7 ++----- console/cdrs_rem.go | 7 ++----- console/cdrstats_metrics.go | 7 ++----- console/cdrstats_queue.go | 7 ++----- console/cdrstats_queue_triggers.go | 7 ++----- console/cdrstats_queueids.go | 7 ++----- console/cdrstats_reload.go | 7 ++----- console/cdrstats_reset.go | 7 ++----- console/command.go | 4 +++- console/command_executer.go | 10 +++++++--- console/cost.go | 7 ++----- console/datacost.go | 7 ++----- console/destination.go | 7 ++----- console/destination_set.go | 7 ++----- console/lcr.go | 7 ++----- console/load_tp_from_folder.go | 7 ++----- console/load_tp_from_stordb.go | 7 ++----- console/maxduration.go | 7 ++----- console/parse.go | 7 ++----- console/publish.go | 7 ++----- console/ratingprofile_set.go | 7 ++----- console/scheduler_reload.go | 7 ++----- console/sharedgroup.go | 7 ++----- console/status.go | 11 ++++------- console/subscribe.go | 7 ++----- console/subscribers.go | 7 ++----- console/triggeredaction_add.go | 7 ++----- console/unsubscribe.go | 7 ++----- console/user_addindex.go | 7 ++----- console/user_indexes.go | 11 ++++------- console/user_remove.go | 7 ++----- console/user_set.go | 7 ++----- console/user_update.go | 7 ++----- console/users.go | 7 ++----- engine/users.go | 25 +++++++++++++++++++++++++ 49 files changed, 131 insertions(+), 230 deletions(-) diff --git a/cmd/cgr-console/cgr-console.go b/cmd/cgr-console/cgr-console.go index cb3312c41..6301ce4e2 100644 --- a/cmd/cgr-console/cgr-console.go +++ b/cmd/cgr-console/cgr-console.go @@ -77,9 +77,11 @@ func executeCommand(command string) { } if cmd.RpcMethod() != "" { res := cmd.RpcResult() - param := cmd.RpcParams(true, false) + param := cmd.RpcParams(false) //log.Print(reflect.TypeOf(param)) switch param.(type) { + case *console.EmptyWrapper: + param = "" case *console.StringWrapper: param = param.(*console.StringWrapper).Item case *console.StringSliceWrapper: diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index 40d41de96..5b60033f2 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -541,7 +541,7 @@ func main() { return } } - engine.SetUserService(users) + engine.SetUserService(userServer) }() wg.Wait() diff --git a/console/account_add.go b/console/account_add.go index 660be2ff6..315caa1b6 100644 --- a/console/account_add.go +++ b/console/account_add.go @@ -45,14 +45,11 @@ func (self *CmdAddAccount) RpcMethod() string { return self.rpcMethod } -func (self *CmdAddAccount) RpcParams(ptr, reset bool) interface{} { +func (self *CmdAddAccount) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrSetAccount{Direction: utils.OUT} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdAddAccount) PostprocessRpcParams() error { diff --git a/console/account_remove.go b/console/account_remove.go index 22e516038..10380d32f 100644 --- a/console/account_remove.go +++ b/console/account_remove.go @@ -45,14 +45,11 @@ func (self *CmdRemoveAccount) RpcMethod() string { return self.rpcMethod } -func (self *CmdRemoveAccount) RpcParams(ptr, reset bool) interface{} { +func (self *CmdRemoveAccount) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrRemoveAccount{Direction: utils.OUT} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdRemoveAccount) PostprocessRpcParams() error { diff --git a/console/accountactions_set.go b/console/accountactions_set.go index 75b757c39..69e54bd10 100644 --- a/console/accountactions_set.go +++ b/console/accountactions_set.go @@ -45,14 +45,11 @@ func (self *CmdSetAccountActions) RpcMethod() string { return self.rpcMethod } -func (self *CmdSetAccountActions) RpcParams(ptr, reset bool) interface{} { +func (self *CmdSetAccountActions) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.TPAccountActions{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdSetAccountActions) PostprocessRpcParams() error { diff --git a/console/accounts.go b/console/accounts.go index a4e2f32eb..79fdf6beb 100644 --- a/console/accounts.go +++ b/console/accounts.go @@ -49,14 +49,11 @@ func (self *CmdGetAccounts) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetAccounts) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetAccounts) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrGetAccounts{Direction: "*out"} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetAccounts) PostprocessRpcParams() error { diff --git a/console/action_execute.go b/console/action_execute.go index f2f22da9c..15ee3838c 100644 --- a/console/action_execute.go +++ b/console/action_execute.go @@ -48,14 +48,11 @@ func (self *CmdExecuteAction) RpcMethod() string { return self.rpcMethod } -func (self *CmdExecuteAction) RpcParams(ptr, reset bool) interface{} { +func (self *CmdExecuteAction) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrExecuteAction{Direction: utils.OUT} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdExecuteAction) PostprocessRpcParams() error { diff --git a/console/active_sessions.go b/console/active_sessions.go index 87d4a941a..db3c16a3f 100644 --- a/console/active_sessions.go +++ b/console/active_sessions.go @@ -48,14 +48,11 @@ func (self *CmdActiveSessions) RpcMethod() string { return self.rpcMethod } -func (self *CmdActiveSessions) RpcParams(ptr, reset bool) interface{} { +func (self *CmdActiveSessions) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrGetSMASessions{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdActiveSessions) PostprocessRpcParams() error { diff --git a/console/balance_debit.go b/console/balance_debit.go index 1b1b5d79c..ab6f45ec8 100644 --- a/console/balance_debit.go +++ b/console/balance_debit.go @@ -48,14 +48,11 @@ func (self *CmdDebitBalance) RpcMethod() string { return self.rpcMethod } -func (self *CmdDebitBalance) RpcParams(ptr, reset bool) interface{} { +func (self *CmdDebitBalance) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.CallDescriptor{Direction: "*out"} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdDebitBalance) PostprocessRpcParams() error { diff --git a/console/balance_set.go b/console/balance_set.go index d012fb05a..89f6a70c5 100644 --- a/console/balance_set.go +++ b/console/balance_set.go @@ -48,14 +48,11 @@ func (self *CmdAddBalance) RpcMethod() string { return self.rpcMethod } -func (self *CmdAddBalance) RpcParams(ptr, reset bool) interface{} { +func (self *CmdAddBalance) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &v1.AttrAddBalance{BalanceType: utils.MONETARY, Overwrite: false} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdAddBalance) PostprocessRpcParams() error { diff --git a/console/cache_age.go b/console/cache_age.go index 3e0177e37..e1bc27bf2 100644 --- a/console/cache_age.go +++ b/console/cache_age.go @@ -45,14 +45,11 @@ func (self *CmdGetCacheAge) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetCacheAge) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetCacheAge) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetCacheAge) PostprocessRpcParams() error { diff --git a/console/cache_reload.go b/console/cache_reload.go index 555ffc86a..14547be0f 100644 --- a/console/cache_reload.go +++ b/console/cache_reload.go @@ -46,14 +46,11 @@ func (self *CmdReloadCache) RpcMethod() string { return self.rpcMethod } -func (self *CmdReloadCache) RpcParams(ptr, reset bool) interface{} { +func (self *CmdReloadCache) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.ApiReloadCache{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdReloadCache) PostprocessRpcParams() error { diff --git a/console/cache_stats.go b/console/cache_stats.go index f68d52a59..eef3be100 100644 --- a/console/cache_stats.go +++ b/console/cache_stats.go @@ -45,14 +45,11 @@ func (self *CmdGetCacheStats) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetCacheStats) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetCacheStats) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrCacheStats{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetCacheStats) PostprocessRpcParams() error { diff --git a/console/callcost.go b/console/callcost.go index 6093dc19a..694c770ca 100644 --- a/console/callcost.go +++ b/console/callcost.go @@ -49,14 +49,11 @@ func (self *CmdGetCostDetails) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetCostDetails) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetCostDetails) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrGetCallCost{RunId: utils.DEFAULT_RUNID} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetCostDetails) PostprocessRpcParams() error { diff --git a/console/cdrs_export.go b/console/cdrs_export.go index 7defe1451..194345f14 100644 --- a/console/cdrs_export.go +++ b/console/cdrs_export.go @@ -45,14 +45,11 @@ func (self *CmdExportCdrs) RpcMethod() string { return self.rpcMethod } -func (self *CmdExportCdrs) RpcParams(ptr, reset bool) interface{} { +func (self *CmdExportCdrs) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrExportCdrsToFile{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdExportCdrs) PostprocessRpcParams() error { diff --git a/console/cdrs_rem.go b/console/cdrs_rem.go index 5b3c097c4..628f2226c 100644 --- a/console/cdrs_rem.go +++ b/console/cdrs_rem.go @@ -45,14 +45,11 @@ func (self *CmdRemCdrs) RpcMethod() string { return self.rpcMethod } -func (self *CmdRemCdrs) RpcParams(ptr, reset bool) interface{} { +func (self *CmdRemCdrs) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrRemCdrs{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdRemCdrs) PostprocessRpcParams() error { diff --git a/console/cdrstats_metrics.go b/console/cdrstats_metrics.go index 9ae874cd9..4f94e25b8 100644 --- a/console/cdrstats_metrics.go +++ b/console/cdrstats_metrics.go @@ -45,14 +45,11 @@ func (self *CmdCdrStatsMetrics) RpcMethod() string { return self.rpcMethod } -func (self *CmdCdrStatsMetrics) RpcParams(ptr, reset bool) interface{} { +func (self *CmdCdrStatsMetrics) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &v1.AttrGetMetrics{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdCdrStatsMetrics) PostprocessRpcParams() error { diff --git a/console/cdrstats_queue.go b/console/cdrstats_queue.go index b58c4f7a9..f7db33737 100644 --- a/console/cdrstats_queue.go +++ b/console/cdrstats_queue.go @@ -44,14 +44,11 @@ func (self *CmdCdrStatsQueue) RpcMethod() string { return self.rpcMethod } -func (self *CmdCdrStatsQueue) RpcParams(ptr, reset bool) interface{} { +func (self *CmdCdrStatsQueue) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdCdrStatsQueue) PostprocessRpcParams() error { diff --git a/console/cdrstats_queue_triggers.go b/console/cdrstats_queue_triggers.go index 0218515a0..d9f5d3dfb 100644 --- a/console/cdrstats_queue_triggers.go +++ b/console/cdrstats_queue_triggers.go @@ -44,14 +44,11 @@ func (self *CmdCdrStatsQueueTriggers) RpcMethod() string { return self.rpcMethod } -func (self *CmdCdrStatsQueueTriggers) RpcParams(ptr, reset bool) interface{} { +func (self *CmdCdrStatsQueueTriggers) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdCdrStatsQueueTriggers) PostprocessRpcParams() error { diff --git a/console/cdrstats_queueids.go b/console/cdrstats_queueids.go index 288534c54..4427b0631 100644 --- a/console/cdrstats_queueids.go +++ b/console/cdrstats_queueids.go @@ -42,14 +42,11 @@ func (self *CmdCdrStatsQueueIds) RpcMethod() string { return self.rpcMethod } -func (self *CmdCdrStatsQueueIds) RpcParams(ptr, reset bool) interface{} { +func (self *CmdCdrStatsQueueIds) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdCdrStatsQueueIds) PostprocessRpcParams() error { diff --git a/console/cdrstats_reload.go b/console/cdrstats_reload.go index 29143a2ce..01c59923c 100644 --- a/console/cdrstats_reload.go +++ b/console/cdrstats_reload.go @@ -47,14 +47,11 @@ func (self *CmdCdrReloadQueues) RpcMethod() string { return self.rpcMethod } -func (self *CmdCdrReloadQueues) RpcParams(ptr, reset bool) interface{} { +func (self *CmdCdrReloadQueues) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrCDRStatsReloadQueues{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdCdrReloadQueues) PostprocessRpcParams() error { diff --git a/console/cdrstats_reset.go b/console/cdrstats_reset.go index d2f942ae1..bb847b34b 100644 --- a/console/cdrstats_reset.go +++ b/console/cdrstats_reset.go @@ -45,14 +45,11 @@ func (self *CmdCdrResetQueues) RpcMethod() string { return self.rpcMethod } -func (self *CmdCdrResetQueues) RpcParams(ptr, reset bool) interface{} { +func (self *CmdCdrResetQueues) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrCDRStatsReloadQueues{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdCdrResetQueues) PostprocessRpcParams() error { diff --git a/console/command.go b/console/command.go index d7d192ba2..feb801808 100644 --- a/console/command.go +++ b/console/command.go @@ -33,7 +33,7 @@ type Commander interface { FromArgs(args string, verbose bool) error // Load data from os arguments or flag.Args() Usage() string // usage message RpcMethod() string // Method which should be called remotely - RpcParams(bool, bool) interface{} // Parameters to send out on rpc + RpcParams(bool) interface{} // Parameters to send out on rpc PostprocessRpcParams() error // Corrects rpc parameters when needed RpcResult() interface{} // Only requirement is to have a String method to print on console ClientArgs() []string // for autocompletion @@ -88,3 +88,5 @@ type StringWrapper struct { type StringSliceWrapper struct { Items []string } + +type EmptyWrapper struct{} diff --git a/console/command_executer.go b/console/command_executer.go index 4d7e2595d..97620f3bb 100644 --- a/console/command_executer.go +++ b/console/command_executer.go @@ -40,13 +40,13 @@ type CommandExecuter struct { } func (ce *CommandExecuter) Usage() string { - jsn, _ := json.Marshal(ce.command.RpcParams(true, true)) + jsn, _ := json.Marshal(ce.command.RpcParams(true)) return fmt.Sprintf("\n\tUsage: %s %s \n", ce.command.Name(), FromJSON(jsn, ce.command.ClientArgs())) } // Parses command line args and builds CmdBalance value func (ce *CommandExecuter) FromArgs(args string, verbose bool) error { - params := ce.command.RpcParams(true, true) + params := ce.command.RpcParams(true) if err := json.Unmarshal(ToJSON(args), params); err != nil { return err } @@ -59,6 +59,10 @@ func (ce *CommandExecuter) FromArgs(args string, verbose bool) error { func (ce *CommandExecuter) clientArgs(iface interface{}) (args []string) { val := reflect.ValueOf(iface) + if val.Kind() == reflect.Ptr { + val = val.Elem() + iface = val.Interface() + } typ := reflect.TypeOf(iface) for i := 0; i < typ.NumField(); i++ { valField := val.Field(i) @@ -74,7 +78,7 @@ func (ce *CommandExecuter) clientArgs(iface interface{}) (args []string) { } func (ce *CommandExecuter) ClientArgs() (args []string) { - return ce.clientArgs(ce.command.RpcParams(false, true)) + return ce.clientArgs(ce.command.RpcParams(true)) } // To be overwritten by commands that do not need a rpc call diff --git a/console/cost.go b/console/cost.go index ab60d04bc..3e07a6e2e 100644 --- a/console/cost.go +++ b/console/cost.go @@ -47,14 +47,11 @@ func (self *CmdGetCost) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetCost) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetCost) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.CallDescriptor{Direction: "*out"} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetCost) PostprocessRpcParams() error { diff --git a/console/datacost.go b/console/datacost.go index 6df827e07..d9bf0a54a 100644 --- a/console/datacost.go +++ b/console/datacost.go @@ -51,14 +51,11 @@ func (self *CmdGetDataCost) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetDataCost) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetDataCost) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &v1.AttrGetDataCost{Direction: utils.OUT} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetDataCost) PostprocessRpcParams() error { diff --git a/console/destination.go b/console/destination.go index 9762081ba..1d80f1dee 100644 --- a/console/destination.go +++ b/console/destination.go @@ -45,14 +45,11 @@ func (self *CmdGetDestination) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetDestination) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetDestination) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetDestination) PostprocessRpcParams() error { diff --git a/console/destination_set.go b/console/destination_set.go index ed00b86b6..d6f045ebd 100644 --- a/console/destination_set.go +++ b/console/destination_set.go @@ -46,14 +46,11 @@ func (self *CmdSetDestination) RpcMethod() string { return self.rpcMethod } -func (self *CmdSetDestination) RpcParams(ptr, reset bool) interface{} { +func (self *CmdSetDestination) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrSetDestination{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdSetDestination) PostprocessRpcParams() error { diff --git a/console/lcr.go b/console/lcr.go index cbd2daeb4..711bcc9ef 100644 --- a/console/lcr.go +++ b/console/lcr.go @@ -48,14 +48,11 @@ func (self *CmdGetLcr) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetLcr) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetLcr) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.LcrRequest{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetLcr) PostprocessRpcParams() error { diff --git a/console/load_tp_from_folder.go b/console/load_tp_from_folder.go index 329e45318..c44220976 100644 --- a/console/load_tp_from_folder.go +++ b/console/load_tp_from_folder.go @@ -46,14 +46,11 @@ func (self *LoadTpFromFolder) RpcMethod() string { return self.rpcMethod } -func (self *LoadTpFromFolder) RpcParams(ptr, reset bool) interface{} { +func (self *LoadTpFromFolder) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.AttrLoadTpFromFolder{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *LoadTpFromFolder) PostprocessRpcParams() error { diff --git a/console/load_tp_from_stordb.go b/console/load_tp_from_stordb.go index 0d2af8714..5d2c7a998 100644 --- a/console/load_tp_from_stordb.go +++ b/console/load_tp_from_stordb.go @@ -46,14 +46,11 @@ func (self *LoadTpFromStorDb) RpcMethod() string { return self.rpcMethod } -func (self *LoadTpFromStorDb) RpcParams(ptr, reset bool) interface{} { +func (self *LoadTpFromStorDb) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &v1.AttrLoadTpFromStorDb{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *LoadTpFromStorDb) PostprocessRpcParams() error { diff --git a/console/maxduration.go b/console/maxduration.go index 2e04868de..b20d5f8e0 100644 --- a/console/maxduration.go +++ b/console/maxduration.go @@ -47,14 +47,11 @@ func (self *CmdGetMaxDuration) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetMaxDuration) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetMaxDuration) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.CallDescriptor{Direction: "*out"} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetMaxDuration) PostprocessRpcParams() error { diff --git a/console/parse.go b/console/parse.go index 558d024b4..f7c5ede56 100644 --- a/console/parse.go +++ b/console/parse.go @@ -49,14 +49,11 @@ func (self *CmdParse) RpcMethod() string { return "" } -func (self *CmdParse) RpcParams(ptr, reset bool) interface{} { +func (self *CmdParse) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &AttrParse{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdParse) RpcResult() interface{} { diff --git a/console/publish.go b/console/publish.go index 41797a178..c46c68a82 100644 --- a/console/publish.go +++ b/console/publish.go @@ -44,14 +44,11 @@ func (self *CmdPublish) RpcMethod() string { return self.rpcMethod } -func (self *CmdPublish) RpcParams(ptr, reset bool) interface{} { +func (self *CmdPublish) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.PublishInfo{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdPublish) PostprocessRpcParams() error { diff --git a/console/ratingprofile_set.go b/console/ratingprofile_set.go index 19c1597b8..0989bea58 100644 --- a/console/ratingprofile_set.go +++ b/console/ratingprofile_set.go @@ -46,14 +46,11 @@ func (self *CmdSetRatingProfile) RpcMethod() string { return self.rpcMethod } -func (self *CmdSetRatingProfile) RpcParams(ptr, reset bool) interface{} { +func (self *CmdSetRatingProfile) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &utils.TPRatingProfile{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdSetRatingProfile) PostprocessRpcParams() error { diff --git a/console/scheduler_reload.go b/console/scheduler_reload.go index b9fa8a11e..a5a1c687c 100644 --- a/console/scheduler_reload.go +++ b/console/scheduler_reload.go @@ -43,14 +43,11 @@ func (self *CmdReloadScheduler) RpcMethod() string { return self.rpcMethod } -func (self *CmdReloadScheduler) RpcParams(ptr, reset bool) interface{} { +func (self *CmdReloadScheduler) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdReloadScheduler) PostprocessRpcParams() error { diff --git a/console/sharedgroup.go b/console/sharedgroup.go index 5ed688fc0..32b64fc22 100644 --- a/console/sharedgroup.go +++ b/console/sharedgroup.go @@ -45,14 +45,11 @@ func (self *CmdGetSharedGroup) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetSharedGroup) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetSharedGroup) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetSharedGroup) PostprocessRpcParams() error { diff --git a/console/status.go b/console/status.go index efa15a8ce..191aa1966 100644 --- a/console/status.go +++ b/console/status.go @@ -30,7 +30,7 @@ func init() { type CmdStatus struct { name string rpcMethod string - rpcParams *StringWrapper + rpcParams *EmptyWrapper *CommandExecuter } @@ -42,14 +42,11 @@ func (self *CmdStatus) RpcMethod() string { return self.rpcMethod } -func (self *CmdStatus) RpcParams(ptr, reset bool) interface{} { +func (self *CmdStatus) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { - self.rpcParams = &StringWrapper{} + self.rpcParams = &EmptyWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdStatus) PostprocessRpcParams() error { diff --git a/console/subscribe.go b/console/subscribe.go index 25c8f3e42..cb71edabc 100644 --- a/console/subscribe.go +++ b/console/subscribe.go @@ -44,14 +44,11 @@ func (self *CmdSubscribe) RpcMethod() string { return self.rpcMethod } -func (self *CmdSubscribe) RpcParams(ptr, reset bool) interface{} { +func (self *CmdSubscribe) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.SubscribeInfo{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdSubscribe) PostprocessRpcParams() error { diff --git a/console/subscribers.go b/console/subscribers.go index 4a37d0496..505ec1c77 100644 --- a/console/subscribers.go +++ b/console/subscribers.go @@ -44,14 +44,11 @@ func (self *CmdShowSubscribers) RpcMethod() string { return self.rpcMethod } -func (self *CmdShowSubscribers) RpcParams(ptr, reset bool) interface{} { +func (self *CmdShowSubscribers) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdShowSubscribers) PostprocessRpcParams() error { diff --git a/console/triggeredaction_add.go b/console/triggeredaction_add.go index 122c40901..298782b6c 100644 --- a/console/triggeredaction_add.go +++ b/console/triggeredaction_add.go @@ -45,14 +45,11 @@ func (self *CmdAddTriggeredAction) RpcMethod() string { return self.rpcMethod } -func (self *CmdAddTriggeredAction) RpcParams(ptr, reset bool) interface{} { +func (self *CmdAddTriggeredAction) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &v1.AttrAddActionTrigger{BalanceDirection: "*out"} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdAddTriggeredAction) PostprocessRpcParams() error { diff --git a/console/unsubscribe.go b/console/unsubscribe.go index 806922388..0ebc534ea 100644 --- a/console/unsubscribe.go +++ b/console/unsubscribe.go @@ -44,14 +44,11 @@ func (self *CmdUnsubscribe) RpcMethod() string { return self.rpcMethod } -func (self *CmdUnsubscribe) RpcParams(ptr, reset bool) interface{} { +func (self *CmdUnsubscribe) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.SubscribeInfo{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdUnsubscribe) PostprocessRpcParams() error { diff --git a/console/user_addindex.go b/console/user_addindex.go index d0408340a..c0b660e93 100644 --- a/console/user_addindex.go +++ b/console/user_addindex.go @@ -43,14 +43,11 @@ func (self *CmdUserAddIndex) RpcMethod() string { return self.rpcMethod } -func (self *CmdUserAddIndex) RpcParams(ptr, reset bool) interface{} { +func (self *CmdUserAddIndex) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &StringSliceWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdUserAddIndex) PostprocessRpcParams() error { diff --git a/console/user_indexes.go b/console/user_indexes.go index 547e67381..6a713044a 100644 --- a/console/user_indexes.go +++ b/console/user_indexes.go @@ -31,7 +31,7 @@ func init() { type CmdUserShowIndexes struct { name string rpcMethod string - rpcParams *StringWrapper + rpcParams *EmptyWrapper *CommandExecuter } @@ -43,14 +43,11 @@ func (self *CmdUserShowIndexes) RpcMethod() string { return self.rpcMethod } -func (self *CmdUserShowIndexes) RpcParams(ptr, reset bool) interface{} { +func (self *CmdUserShowIndexes) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { - self.rpcParams = &StringWrapper{} + self.rpcParams = &EmptyWrapper{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdUserShowIndexes) PostprocessRpcParams() error { diff --git a/console/user_remove.go b/console/user_remove.go index 8e8658e81..f0a0a3aec 100644 --- a/console/user_remove.go +++ b/console/user_remove.go @@ -45,14 +45,11 @@ func (self *CmdUserRemove) RpcMethod() string { return self.rpcMethod } -func (self *CmdUserRemove) RpcParams(ptr, reset bool) interface{} { +func (self *CmdUserRemove) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.UserProfile{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdUserRemove) PostprocessRpcParams() error { diff --git a/console/user_set.go b/console/user_set.go index e531fe8e3..39cd8239f 100644 --- a/console/user_set.go +++ b/console/user_set.go @@ -45,14 +45,11 @@ func (self *CmdSetUser) RpcMethod() string { return self.rpcMethod } -func (self *CmdSetUser) RpcParams(ptr, reset bool) interface{} { +func (self *CmdSetUser) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.UserProfile{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdSetUser) PostprocessRpcParams() error { diff --git a/console/user_update.go b/console/user_update.go index 908b54376..ef80a4f27 100644 --- a/console/user_update.go +++ b/console/user_update.go @@ -45,14 +45,11 @@ func (self *CmdUpdateUser) RpcMethod() string { return self.rpcMethod } -func (self *CmdUpdateUser) RpcParams(ptr, reset bool) interface{} { +func (self *CmdUpdateUser) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.UserProfile{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdUpdateUser) PostprocessRpcParams() error { diff --git a/console/users.go b/console/users.go index 89492d7f0..28da13968 100644 --- a/console/users.go +++ b/console/users.go @@ -46,14 +46,11 @@ func (self *CmdGetUsers) RpcMethod() string { return self.rpcMethod } -func (self *CmdGetUsers) RpcParams(ptr, reset bool) interface{} { +func (self *CmdGetUsers) RpcParams(reset bool) interface{} { if reset || self.rpcParams == nil { self.rpcParams = &engine.UserProfile{} } - if ptr { - return self.rpcParams - } - return *self.rpcParams + return self.rpcParams } func (self *CmdGetUsers) PostprocessRpcParams() error { diff --git a/engine/users.go b/engine/users.go index 95f7a2d9d..35cd6a509 100644 --- a/engine/users.go +++ b/engine/users.go @@ -1,6 +1,7 @@ package engine import ( + "reflect" "strings" "github.com/cgrates/cgrates/utils" @@ -318,3 +319,27 @@ func (ps *ProxyUserService) AddIndex(indexes []string, reply *string) error { func (ps *ProxyUserService) GetIndexes(in string, reply *map[string][]string) error { return ps.Client.Call("UsersV1.AddIndex", in, reply) } + +func ToMapStringString(in interface{}) (map[string]string, error) { + out := make(map[string]string) + + v := reflect.ValueOf(in) + if v.Kind() == reflect.Ptr { + v = v.Elem() + in = v.Interface() + } + typ := reflect.TypeOf(in) + for i := 0; i < v.NumField(); i++ { + // gets us a StructField + field := typ.Field(i) + typField := v.Field(i) + switch typField.Kind() { + case reflect.String: + val := v.Field(i).String() + if val != "" { + out[field.Name] = val + } + } + } + return out, nil +} From c5b653ab63f5b1c605484dd80fd0707992523820 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 14 Jul 2015 22:31:27 +0300 Subject: [PATCH 4/7] moved LoadUserProfile to users and used reflect --- apier/v1/auth.go | 4 ++- apier/v1/cdrsv1.go | 6 ++++ apier/v1/debit.go | 4 ++- engine/storedcdr.go | 51 -------------------------------- engine/storedcdr_test.go | 45 ---------------------------- engine/users.go | 52 ++++++++++++++++++++------------- engine/users_test.go | 49 +++++++++++++++++++++++++++++++ utils/struct.go | 27 +++++++++++++---- utils/struct_test.go | 63 ++++++++++++++++++++++++++++++++++++++++ 9 files changed, 178 insertions(+), 123 deletions(-) create mode 100644 utils/struct_test.go diff --git a/apier/v1/auth.go b/apier/v1/auth.go index 847917927..d6d24500d 100644 --- a/apier/v1/auth.go +++ b/apier/v1/auth.go @@ -28,9 +28,11 @@ import ( // Returns MaxUsage (for calls in seconds), -1 for no limit func (self *ApierV1) GetMaxUsage(usageRecord engine.UsageRecord, maxUsage *float64) error { - if err := usageRecord.LoadUserProfile(); err != nil { + out, err := engine.LoadUserProfile(usageRecord) + if err != nil { return err } + usageRecord = out.(engine.UsageRecord) if usageRecord.TOR == "" { usageRecord.TOR = utils.VOICE } diff --git a/apier/v1/cdrsv1.go b/apier/v1/cdrsv1.go index afa46d850..142b04179 100644 --- a/apier/v1/cdrsv1.go +++ b/apier/v1/cdrsv1.go @@ -41,6 +41,12 @@ func (self *CdrsV1) ProcessCdr(cdr *engine.StoredCdr, reply *string) error { // Designed for external programs feeding CDRs to CGRateS func (self *CdrsV1) ProcessExternalCdr(cdr *engine.ExternalCdr, reply *string) error { + out, err := engine.LoadUserProfile(cdr) + if err != nil { + *reply = err.Error() + return err + } + *cdr = out.(engine.ExternalCdr) if err := self.CdrSrv.ProcessExternalCdr(cdr); err != nil { return utils.NewErrServerError(err) } diff --git a/apier/v1/debit.go b/apier/v1/debit.go index f70ea0572..f7334da90 100644 --- a/apier/v1/debit.go +++ b/apier/v1/debit.go @@ -27,10 +27,12 @@ func (self *ApierV1) DebitUsage(usageRecord engine.UsageRecord, reply *string) e if missing := utils.MissingStructFields(&usageRecord, []string{"Account", "Destination", "Usage"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - if err := usageRecord.LoadUserProfile(); err != nil { + out, err := engine.LoadUserProfile(usageRecord) + if err != nil { *reply = err.Error() return err } + usageRecord = out.(engine.UsageRecord) if usageRecord.TOR == "" { usageRecord.TOR = utils.VOICE } diff --git a/engine/storedcdr.go b/engine/storedcdr.go index 580fd1d73..ad7c17e73 100644 --- a/engine/storedcdr.go +++ b/engine/storedcdr.go @@ -20,7 +20,6 @@ package engine import ( "encoding/json" - "log" "math" "net/url" "strconv" @@ -682,53 +681,3 @@ func (self *UsageRecord) AsCallDescriptor() (*CallDescriptor, error) { TimeEnd: startTime.Add(usage), }, nil } - -func (self *UsageRecord) LoadUserProfile() error { - up := &UserProfile{ - Tenant: self.Tenant, - Profile: map[string]string{ - "TOR": self.TOR, - "ReqType": self.ReqType, - "Direction": self.Direction, - "Tenant": self.Tenant, - "Category": self.Category, - "Account": self.Account, - "Subject": self.SetupTime, - "Destination": self.Destination, - "SetupTime": self.SetupTime, - "AnswerTime": self.AnswerTime, - "Usage": self.Usage, - }, - } - // clean *user fields - if up.Tenant == utils.USERS { - up.Tenant = "" - } - for key, value := range up.Profile { - if value == utils.USERS { - delete(up.Profile, key) - } - } - log.Print("UP: ", up.Profile) - ups := make([]*UserProfile, 0) - if err := userService.GetUsers(*up, &ups); err != nil { - return err - } - if len(ups) > 0 { - up = ups[0] // take the first matched user profile - self.TOR = up.Profile["TOR"] - self.ReqType = up.Profile["ReqType"] - self.Direction = up.Profile["Direction"] - self.Tenant = up.Tenant - self.Category = up.Profile["Category"] - self.Account = up.Profile["Account"] - self.Subject = up.Profile["Subject"] - self.Destination = up.Profile["Destination"] - self.SetupTime = up.Profile["SetupTime"] - self.AnswerTime = up.Profile["AnswerTime"] - self.Usage = up.Profile["Usage"] - } else { - return utils.ErrNotFound - } - return nil -} diff --git a/engine/storedcdr_test.go b/engine/storedcdr_test.go index d6602de14..3163f851a 100644 --- a/engine/storedcdr_test.go +++ b/engine/storedcdr_test.go @@ -549,48 +549,3 @@ func TestUsageReqAsCD(t *testing.T) { t.Errorf("Expected: %+v, received: %+v", eCD, cd) } } - -func TestStoredCDRGetUserProfile(t *testing.T) { - userService = &UserMap{ - table: map[string]map[string]string{ - "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, - ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, - "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, - "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13"}, - }, - index: make(map[string]map[string]bool), - } - - ur := &UsageRecord{ - TOR: utils.USERS, - ReqType: utils.USERS, - Direction: "*out", - Tenant: utils.USERS, - Category: "call", - Account: utils.USERS, - Subject: utils.USERS, - Destination: utils.USERS, - SetupTime: utils.USERS, - AnswerTime: utils.USERS, - Usage: "13", - } - if err := ur.LoadUserProfile(); err != nil { - t.Error("Error loading user profile: ", err) - } - expected := &UsageRecord{ - TOR: "04", - ReqType: "4", - Direction: "*out", - Tenant: "test1", - Category: "call", - Account: "rif", - Subject: "0726", - Destination: "+404", - SetupTime: "s4", - AnswerTime: "t4", - Usage: "13", - } - if !reflect.DeepEqual(ur, expected) { - t.Errorf("Expected: %+v got: %+v", expected, ur) - } -} diff --git a/engine/users.go b/engine/users.go index 35cd6a509..4ec51a5a5 100644 --- a/engine/users.go +++ b/engine/users.go @@ -1,7 +1,6 @@ package engine import ( - "reflect" "strings" "github.com/cgrates/cgrates/utils" @@ -320,26 +319,39 @@ func (ps *ProxyUserService) GetIndexes(in string, reply *map[string][]string) er return ps.Client.Call("UsersV1.AddIndex", in, reply) } -func ToMapStringString(in interface{}) (map[string]string, error) { - out := make(map[string]string) - - v := reflect.ValueOf(in) - if v.Kind() == reflect.Ptr { - v = v.Elem() - in = v.Interface() +func LoadUserProfile(in interface{}) (interface{}, error) { + m, err := utils.ToMapStringString(in) + if err != nil { + return nil, err } - typ := reflect.TypeOf(in) - for i := 0; i < v.NumField(); i++ { - // gets us a StructField - field := typ.Field(i) - typField := v.Field(i) - switch typField.Kind() { - case reflect.String: - val := v.Field(i).String() - if val != "" { - out[field.Name] = val - } + + up := &UserProfile{ + Profile: make(map[string]string), + } + tenant := m["Tenant"] + if tenant != "" && tenant != utils.USERS { + up.Tenant = tenant + } + delete(m, "Tenant") + + // clean empty and *user fields + for key, val := range m { + if val != "" && val != utils.USERS { + up.Profile[key] = val } } - return out, nil + + //TODO: add extra fields + + ups := make([]*UserProfile, 0) + if err := userService.GetUsers(*up, &ups); err != nil { + return nil, err + } + if len(ups) > 0 { + up = ups[0] + m := up.Profile + m["Tenant"] = up.Tenant + return utils.FromMapStringString(m, in) + } + return nil, utils.ErrNotFound } diff --git a/engine/users_test.go b/engine/users_test.go index ad1dfec9d..c43b0b42b 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -1,6 +1,7 @@ package engine import ( + "reflect" "testing" "github.com/cgrates/cgrates/utils" @@ -501,3 +502,51 @@ func TestUsersAddUpdateRemoveIndexes(t *testing.T) { t.Error("error adding indexes: ", tm.index) } } + +func TestUsersStoredCDRGetLoadUserProfile(t *testing.T) { + userService = &UserMap{ + table: map[string]map[string]string{ + "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13"}, + }, + index: make(map[string]map[string]bool), + } + + ur := &UsageRecord{ + TOR: utils.USERS, + ReqType: utils.USERS, + Direction: "*out", + Tenant: "", + Category: "call", + Account: utils.USERS, + Subject: utils.USERS, + Destination: utils.USERS, + SetupTime: utils.USERS, + AnswerTime: utils.USERS, + Usage: "13", + } + + out, err := LoadUserProfile(ur) + if err != nil { + t.Error("Error loading user profile: ", err) + } + expected := &UsageRecord{ + TOR: "04", + ReqType: "4", + Direction: "*out", + Tenant: "test1", + Category: "call", + Account: "rif", + Subject: "0726", + Destination: "+404", + SetupTime: "s4", + AnswerTime: "t4", + Usage: "13", + } + *ur = out.(UsageRecord) + if !reflect.DeepEqual(ur, expected) { + t.Errorf("Expected: %+v got: %+v", expected, ur) + } +} diff --git a/utils/struct.go b/utils/struct.go index d98954552..4a29ddd6a 100644 --- a/utils/struct.go +++ b/utils/struct.go @@ -93,7 +93,7 @@ func ToMapMapStringInterface(in interface{}) (map[string]interface{}, error) { } // Converts a struct to map[string]string -func ToMapStringInterface(in interface{}) (map[string]string, error) { +func ToMapStringString(in interface{}) (map[string]string, error) { out := make(map[string]string) v := reflect.ValueOf(in) @@ -108,15 +108,32 @@ func ToMapStringInterface(in interface{}) (map[string]string, error) { field := v.Field(i) switch field.Kind() { case reflect.String: - val := field.String() - if val != "" { - out[typField.Name] = val - } + out[typField.Name] = field.String() } } return out, nil } +func FromMapStringString(m map[string]string, in interface{}) (interface{}, error) { + v := reflect.ValueOf(in) + if v.Kind() == reflect.Ptr { + v = v.Elem() + in = v.Interface() + } + st := reflect.TypeOf(in) + elem := reflect.New(st).Elem() + for fieldName, fieldValue := range m { + field := elem.FieldByName(fieldName) + if field.IsValid() { + + if field.Kind() == reflect.String { + field.SetString(fieldValue) + } + } + } + return elem.Interface(), nil +} + // Update struct with map fields, returns not matching map keys, s is a struct to be updated func UpdateStructWithStrMap(s interface{}, m map[string]string) []string { notMatched := []string{} diff --git a/utils/struct_test.go b/utils/struct_test.go new file mode 100644 index 000000000..9e6c38016 --- /dev/null +++ b/utils/struct_test.go @@ -0,0 +1,63 @@ +package utils + +import ( + "reflect" + "testing" +) + +func TestMapStruct(t *testing.T) { + type TestStruct struct { + Name string + Surname string + Address string + Other string + } + ts := &TestStruct{ + Name: "1", + Surname: "2", + Address: "3", + Other: "", + } + m, err := ToMapStringString(ts) + if err != nil { + t.Error("Error converting to map: ", err) + } + out, err := FromMapStringString(m, ts) + if err != nil { + t.Error("Error converting to struct: ", err) + } + nts := out.(TestStruct) + if !reflect.DeepEqual(ts, &nts) { + t.Log(m) + t.Errorf("Expected: %+v got: %+v", ts, nts) + } +} + +func TestMapStructAddStructs(t *testing.T) { + type TestStruct struct { + Name string + Surname string + Address string + Other string + } + ts := &TestStruct{ + Name: "1", + Surname: "2", + Address: "3", + Other: "", + } + m, err := ToMapStringString(ts) + if err != nil { + t.Error("Error converting to map: ", err) + } + m["Test"] = "4" + out, err := FromMapStringString(m, ts) + if err != nil { + t.Error("Error converting to struct: ", err) + } + nts := out.(TestStruct) + if !reflect.DeepEqual(ts, &nts) { + t.Log(m) + t.Errorf("Expected: %+v got: %+v", ts, nts) + } +} From af15347b7fbac9559be42284ae83f7ecc55329a3 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Tue, 14 Jul 2015 23:38:23 +0300 Subject: [PATCH 5/7] added user search ponders --- console/users.go | 2 +- engine/users.go | 54 +++++++++++++++++++++++++------ engine/users_test.go | 77 +++++++++++++++++++++++++++----------------- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/console/users.go b/console/users.go index 28da13968..e343297cd 100644 --- a/console/users.go +++ b/console/users.go @@ -58,6 +58,6 @@ func (self *CmdGetUsers) PostprocessRpcParams() error { } func (self *CmdGetUsers) RpcResult() interface{} { - s := []*engine.UserProfile{} + s := engine.UserProfiles{} return &s } diff --git a/engine/users.go b/engine/users.go index 4ec51a5a5..8684b9620 100644 --- a/engine/users.go +++ b/engine/users.go @@ -1,6 +1,7 @@ package engine import ( + "sort" "strings" "github.com/cgrates/cgrates/utils" @@ -11,6 +12,25 @@ type UserProfile struct { Tenant string UserName string Profile map[string]string + ponder int +} + +type UserProfiles []*UserProfile + +func (ups UserProfiles) Len() int { + return len(ups) +} + +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) Sort() { + sort.Sort(ups) } func (ud *UserProfile) GetId() string { @@ -31,7 +51,7 @@ type UserService interface { SetUser(UserProfile, *string) error RemoveUser(UserProfile, *string) error UpdateUser(UserProfile, *string) error - GetUsers(UserProfile, *[]*UserProfile) error + GetUsers(UserProfile, *UserProfiles) error AddIndex([]string, *string) error GetIndexes(string, *map[string][]string) error } @@ -123,7 +143,7 @@ func (um *UserMap) UpdateUser(up UserProfile, reply *string) error { return nil } -func (um *UserMap) GetUsers(up UserProfile, results *[]*UserProfile) error { +func (um *UserMap) GetUsers(up UserProfile, results *UserProfiles) error { table := um.table // no index indexUnionKeys := make(map[string]bool) @@ -156,20 +176,34 @@ func (um *UserMap) GetUsers(up UserProfile, results *[]*UserProfile) error { } } - var candidates []*UserProfile + var candidates UserProfiles for key, values := range table { - if up.Tenant != "" && !strings.HasPrefix(key, up.Tenant+utils.CONCATENATED_KEY_SEP) { + ponder := 0 + tableUP := &UserProfile{ + Profile: values, + } + tableUP.SetId(key) + if up.Tenant != "" && tableUP.Tenant != "" && up.Tenant != tableUP.Tenant { continue } - if up.UserName != "" && !strings.HasSuffix(key, utils.CONCATENATED_KEY_SEP+up.UserName) { + if tableUP.Tenant != "" { + ponder += 1 + } + if up.UserName != "" && tableUP.UserName != "" && up.UserName != tableUP.UserName { continue } + if tableUP.UserName != "" { + ponder += 1 + } valid := true for k, v := range up.Profile { - if values[k] != v { + if tableUP.Profile[k] != "" && tableUP.Profile[k] != v { valid = false break } + if tableUP.Profile[k] != "" { + ponder += 1 + } } if !valid { continue @@ -177,11 +211,13 @@ func (um *UserMap) GetUsers(up UserProfile, results *[]*UserProfile) error { // all filters passed, add to candidates nup := &UserProfile{Profile: make(map[string]string)} nup.SetId(key) - for k, v := range values { + nup.ponder = ponder + for k, v := range tableUP.Profile { nup.Profile[k] = v } candidates = append(candidates, nup) } + candidates.Sort() *results = candidates return nil } @@ -307,7 +343,7 @@ func (ps *ProxyUserService) UpdateUser(ud UserProfile, reply *string) error { return ps.Client.Call("UsersV1.UpdateUser", ud, reply) } -func (ps *ProxyUserService) GetUsers(ud UserProfile, users *[]*UserProfile) error { +func (ps *ProxyUserService) GetUsers(ud UserProfile, users *UserProfiles) error { return ps.Client.Call("UsersV1.GetUsers", ud, users) } @@ -343,7 +379,7 @@ func LoadUserProfile(in interface{}) (interface{}, error) { //TODO: add extra fields - ups := make([]*UserProfile, 0) + ups := UserProfiles{} if err := userService.GetUsers(*up, &ups); err != nil { return nil, err } diff --git a/engine/users_test.go b/engine/users_test.go index c43b0b42b..b519803b9 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -149,9 +149,9 @@ func TestUsersGetFull(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 1 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -164,9 +164,9 @@ func TestUsersGetTenant(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 0 { + if len(results) != 1 { t.Error("error getting users: ", results) } } @@ -179,9 +179,9 @@ func TestUsersGetUserName(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 0 { + if len(results) != 1 { t.Error("error getting users: ", results) } } @@ -194,9 +194,9 @@ func TestUsersGetNotFoundProfile(t *testing.T) { "o": "p", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 0 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -208,9 +208,9 @@ func TestUsersGetMissingTenant(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 2 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -222,9 +222,9 @@ func TestUsersGetMissingUserName(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 2 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -235,7 +235,7 @@ func TestUsersGetMissingId(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) if len(results) != 4 { t.Error("error getting users: ", results) @@ -249,13 +249,30 @@ func TestUsersGetMissingIdTwo(t *testing.T) { "x": "y", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 1 { + if len(results) != 4 { t.Error("error getting users: ", results) } } +func TestUsersGetMissingIdTwoSort(t *testing.T) { + up := UserProfile{ + Profile: map[string]string{ + "t": "v", + "x": "y", + }, + } + results := UserProfiles{} + testMap.GetUsers(up, &results) + if len(results) != 4 { + t.Error("error getting users: ", results) + } + if results[0].GetId() != "test1:user1" { + t.Errorf("Error sorting profiles: %+v", results[0]) + } +} + func TestUsersAddIndex(t *testing.T) { var r string testMap.AddIndex([]string{"t"}, &r) @@ -298,9 +315,9 @@ func TestUsersGetFullindex(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 1 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -316,9 +333,9 @@ func TestUsersGetTenantindex(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 0 { + if len(results) != 1 { t.Error("error getting users: ", results) } } @@ -334,9 +351,9 @@ func TestUsersGetUserNameindex(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 0 { + if len(results) != 1 { t.Error("error getting users: ", results) } } @@ -352,9 +369,9 @@ func TestUsersGetNotFoundProfileindex(t *testing.T) { "o": "p", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 0 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -369,9 +386,9 @@ func TestUsersGetMissingTenantindex(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 2 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -386,9 +403,9 @@ func TestUsersGetMissingUserNameindex(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 2 { + if len(results) != 3 { t.Error("error getting users: ", results) } } @@ -402,7 +419,7 @@ func TestUsersGetMissingIdindex(t *testing.T) { "t": "v", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) if len(results) != 4 { t.Error("error getting users: ", results) @@ -419,9 +436,9 @@ func TestUsersGetMissingIdTwoINdex(t *testing.T) { "x": "y", }, } - results := make([]*UserProfile, 0) + results := UserProfiles{} testMap.GetUsers(up, &results) - if len(results) != 1 { + if len(results) != 4 { t.Error("error getting users: ", results) } } From e015ef921359b5a6521fc4475a212164a2082099 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 15 Jul 2015 15:50:18 +0300 Subject: [PATCH 6/7] renamed tutorial users file --- data/tariffplans/tutorial/{User.csv => Users.csv} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename data/tariffplans/tutorial/{User.csv => Users.csv} (100%) diff --git a/data/tariffplans/tutorial/User.csv b/data/tariffplans/tutorial/Users.csv similarity index 100% rename from data/tariffplans/tutorial/User.csv rename to data/tariffplans/tutorial/Users.csv From 50cafb92d7e405a47ef88f2da758b5d3822dcbf7 Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 15 Jul 2015 17:27:06 +0300 Subject: [PATCH 7/7] added estra fields for user profile loading --- apier/v1/auth.go | 2 +- apier/v1/cdrsv1.go | 2 +- apier/v1/debit.go | 2 +- engine/users.go | 16 ++++++-- engine/users_test.go | 89 +++++++++++++++++++++++++++++++++++++++++++- utils/struct.go | 25 +++++++++++-- utils/struct_test.go | 28 +++++++++++++- 7 files changed, 152 insertions(+), 12 deletions(-) diff --git a/apier/v1/auth.go b/apier/v1/auth.go index d6d24500d..d0ef5e8b3 100644 --- a/apier/v1/auth.go +++ b/apier/v1/auth.go @@ -28,7 +28,7 @@ import ( // Returns MaxUsage (for calls in seconds), -1 for no limit func (self *ApierV1) GetMaxUsage(usageRecord engine.UsageRecord, maxUsage *float64) error { - out, err := engine.LoadUserProfile(usageRecord) + out, err := engine.LoadUserProfile(usageRecord, "") if err != nil { return err } diff --git a/apier/v1/cdrsv1.go b/apier/v1/cdrsv1.go index 142b04179..6cadcb9e2 100644 --- a/apier/v1/cdrsv1.go +++ b/apier/v1/cdrsv1.go @@ -41,7 +41,7 @@ func (self *CdrsV1) ProcessCdr(cdr *engine.StoredCdr, reply *string) error { // Designed for external programs feeding CDRs to CGRateS func (self *CdrsV1) ProcessExternalCdr(cdr *engine.ExternalCdr, reply *string) error { - out, err := engine.LoadUserProfile(cdr) + out, err := engine.LoadUserProfile(cdr, "ExtraFields") if err != nil { *reply = err.Error() return err diff --git a/apier/v1/debit.go b/apier/v1/debit.go index f7334da90..9daf87fd1 100644 --- a/apier/v1/debit.go +++ b/apier/v1/debit.go @@ -27,7 +27,7 @@ func (self *ApierV1) DebitUsage(usageRecord engine.UsageRecord, reply *string) e if missing := utils.MissingStructFields(&usageRecord, []string{"Account", "Destination", "Usage"}); len(missing) != 0 { return utils.NewErrMandatoryIeMissing(missing...) } - out, err := engine.LoadUserProfile(usageRecord) + out, err := engine.LoadUserProfile(usageRecord, "") if err != nil { *reply = err.Error() return err diff --git a/engine/users.go b/engine/users.go index 8684b9620..ce1cfc8a2 100644 --- a/engine/users.go +++ b/engine/users.go @@ -355,7 +355,7 @@ func (ps *ProxyUserService) GetIndexes(in string, reply *map[string][]string) er return ps.Client.Call("UsersV1.AddIndex", in, reply) } -func LoadUserProfile(in interface{}) (interface{}, error) { +func LoadUserProfile(in interface{}, extraFields string) (interface{}, error) { m, err := utils.ToMapStringString(in) if err != nil { return nil, err @@ -377,8 +377,18 @@ func LoadUserProfile(in interface{}) (interface{}, error) { } } - //TODO: add extra fields - + // add extra fields + if extraFields != "" { + extra, err := utils.GetMapExtraFields(in, extraFields) + if err != nil { + return nil, err + } + for key, val := range extra { + if val != "" { + up.Profile[key] = val + } + } + } ups := UserProfiles{} if err := userService.GetUsers(*up, &ups); err != nil { return nil, err diff --git a/engine/users_test.go b/engine/users_test.go index b519803b9..12b14c21f 100644 --- a/engine/users_test.go +++ b/engine/users_test.go @@ -545,7 +545,7 @@ func TestUsersStoredCDRGetLoadUserProfile(t *testing.T) { Usage: "13", } - out, err := LoadUserProfile(ur) + out, err := LoadUserProfile(ur, "") if err != nil { t.Error("Error loading user profile: ", err) } @@ -553,7 +553,7 @@ func TestUsersStoredCDRGetLoadUserProfile(t *testing.T) { TOR: "04", ReqType: "4", Direction: "*out", - Tenant: "test1", + Tenant: "", Category: "call", Account: "rif", Subject: "0726", @@ -567,3 +567,88 @@ func TestUsersStoredCDRGetLoadUserProfile(t *testing.T) { t.Errorf("Expected: %+v got: %+v", expected, ur) } } + +func TestUsersStoredCDRGetLoadUserProfileExtraFields(t *testing.T) { + userService = &UserMap{ + table: map[string]map[string]string{ + "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "1"}, + }, + index: make(map[string]map[string]bool), + } + + ur := &ExternalCdr{ + TOR: utils.USERS, + ReqType: utils.USERS, + Direction: "*out", + Tenant: "", + Category: "call", + Account: utils.USERS, + Subject: utils.USERS, + Destination: utils.USERS, + SetupTime: utils.USERS, + AnswerTime: utils.USERS, + Usage: "13", + ExtraFields: map[string]string{ + "Test": "1", + }, + } + + out, err := LoadUserProfile(ur, "ExtraFields") + if err != nil { + t.Error("Error loading user profile: ", err) + } + expected := &ExternalCdr{ + TOR: "04", + ReqType: "4", + Direction: "*out", + Tenant: "", + Category: "call", + Account: "rif", + Subject: "0726", + Destination: "+404", + SetupTime: "s4", + AnswerTime: "t4", + Usage: "13", + } + *ur = out.(ExternalCdr) + if !reflect.DeepEqual(ur, expected) { + t.Errorf("Expected: %+v got: %+v", expected, ur) + } +} + +func TestUsersStoredCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) { + userService = &UserMap{ + table: map[string]map[string]string{ + "test:user": map[string]string{"TOR": "01", "ReqType": "1", "Direction": "*out", "Category": "c1", "Account": "dan", "Subject": "0723", "Destination": "+401", "SetupTime": "s1", "AnswerTime": "t1", "Usage": "10"}, + ":user": map[string]string{"TOR": "02", "ReqType": "2", "Direction": "*out", "Category": "c2", "Account": "ivo", "Subject": "0724", "Destination": "+402", "SetupTime": "s2", "AnswerTime": "t2", "Usage": "11"}, + "test:": map[string]string{"TOR": "03", "ReqType": "3", "Direction": "*out", "Category": "c3", "Account": "elloy", "Subject": "0725", "Destination": "+403", "SetupTime": "s3", "AnswerTime": "t3", "Usage": "12"}, + "test1:user1": map[string]string{"TOR": "04", "ReqType": "4", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726", "Destination": "+404", "SetupTime": "s4", "AnswerTime": "t4", "Usage": "13", "Test": "2"}, + }, + index: make(map[string]map[string]bool), + } + + ur := &ExternalCdr{ + TOR: utils.USERS, + ReqType: utils.USERS, + Direction: "*out", + Tenant: "", + Category: "call", + Account: utils.USERS, + Subject: utils.USERS, + Destination: utils.USERS, + SetupTime: utils.USERS, + AnswerTime: utils.USERS, + Usage: "13", + ExtraFields: map[string]string{ + "Test": "1", + }, + } + + _, err := LoadUserProfile(ur, "ExtraFields") + if err != utils.ErrNotFound { + t.Error("Error detecting err in loading user profile: ", err) + } +} diff --git a/utils/struct.go b/utils/struct.go index 4a29ddd6a..5904341be 100644 --- a/utils/struct.go +++ b/utils/struct.go @@ -106,14 +106,31 @@ func ToMapStringString(in interface{}) (map[string]string, error) { // gets us a StructField typField := typ.Field(i) field := v.Field(i) - switch field.Kind() { - case reflect.String: + if field.Kind() == reflect.String { out[typField.Name] = field.String() } } return out, nil } +// Converts a struct to map[string]string +func GetMapExtraFields(in interface{}, extraFields string) (map[string]string, error) { + out := make(map[string]string) + v := reflect.ValueOf(in) + if v.Kind() == reflect.Ptr { + v = v.Elem() + in = v.Interface() + } + field := v.FieldByName(extraFields) + if field.Kind() == reflect.Map { + keys := field.MapKeys() + for _, key := range keys { + out[key.String()] = field.MapIndex(key).String() + } + } + return out, nil +} + func FromMapStringString(m map[string]string, in interface{}) (interface{}, error) { v := reflect.ValueOf(in) if v.Kind() == reflect.Ptr { @@ -127,7 +144,9 @@ func FromMapStringString(m map[string]string, in interface{}) (interface{}, erro if field.IsValid() { if field.Kind() == reflect.String { - field.SetString(fieldValue) + if v.FieldByName(fieldName).String() != "" { + field.SetString(fieldValue) + } } } } diff --git a/utils/struct_test.go b/utils/struct_test.go index 9e6c38016..12723952f 100644 --- a/utils/struct_test.go +++ b/utils/struct_test.go @@ -5,7 +5,7 @@ import ( "testing" ) -func TestMapStruct(t *testing.T) { +func TestStructMapStruct(t *testing.T) { type TestStruct struct { Name string Surname string @@ -61,3 +61,29 @@ func TestMapStructAddStructs(t *testing.T) { t.Errorf("Expected: %+v got: %+v", ts, nts) } } + +func TestStructExtraFields(t *testing.T) { + ts := struct { + Name string + Surname string + Address string + ExtraFields map[string]string + }{ + Name: "1", + Surname: "2", + Address: "3", + ExtraFields: map[string]string{ + "k1": "v1", + "k2": "v2", + "k3": "v3", + }, + } + efMap, err := GetMapExtraFields(ts, "ExtraFields") + if err != nil { + t.Error("Error getting extra fields: ", err) + } + + if !reflect.DeepEqual(efMap, ts.ExtraFields) { + t.Errorf("expected: %v got: %v", ts.ExtraFields, efMap) + } +}