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) + } +}