mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
UserS methods in both CallDescriptor and StoredCdr, fixes #129
This commit is contained in:
@@ -4,9 +4,11 @@
|
||||
Loading **CGRateS** Tariff Plans
|
||||
--------------------------------
|
||||
|
||||
Before proceeding to this step, you should have **CGRateS** installed and started with custom configuration, depending on the tutorial you have followed.
|
||||
Before proceeding to this step, you should have **CGRateS** installed and
|
||||
started with custom configuration, depending on the tutorial you have followed.
|
||||
|
||||
For our tutorial we load again prepared data out of shared folder, containing following rules:
|
||||
For our tutorial we load again prepared data out of shared folder, containing
|
||||
following rules:
|
||||
|
||||
- Create the necessary timings (always, asap, peak, offpeak).
|
||||
- Configure 3 destinations (1002, 1003 and 10 used as catch all rule).
|
||||
@@ -68,11 +70,11 @@ To verify that all actions successfully performed, we use following *cgr-console
|
||||
|
||||
::
|
||||
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1001"'
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1002"'
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1003"'
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1004"'
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1005"'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1001"]'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1002"]'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1003"]'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1004"]'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1005"]'
|
||||
|
||||
- Query call costs so we can see our calls will have expected costs (final cost will result as sum of *ConnectFee* and *Cost* fields):
|
||||
|
||||
@@ -108,7 +110,7 @@ Check that 1001 balance is properly deducted, during the call, and moreover cons
|
||||
|
||||
::
|
||||
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1001"'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1001"]'
|
||||
|
||||
|
||||
1002 -> 1001
|
||||
@@ -120,7 +122,7 @@ To check that we had debits we use again console command, this time not during t
|
||||
|
||||
::
|
||||
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1002"'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1002"]'
|
||||
|
||||
|
||||
1003 -> 1001
|
||||
@@ -132,7 +134,7 @@ To check that there are no debits during or by the end of the call, but when the
|
||||
|
||||
::
|
||||
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1003"'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1003"]'
|
||||
|
||||
|
||||
1004 -> 1001
|
||||
@@ -150,8 +152,8 @@ Check that 1001 balance is properly debitted, during the call, and moreover cons
|
||||
|
||||
::
|
||||
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1006"'
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1001"'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1006"]'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1001"]'
|
||||
|
||||
|
||||
1007 -> 1002
|
||||
@@ -163,8 +165,8 @@ Check that call can proceed even if 1007 has no units left into his own balances
|
||||
|
||||
::
|
||||
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1007"'
|
||||
cgr-console 'account Tenant="cgrates.org" Account="1001"'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1007"]'
|
||||
cgr-console 'accounts Tenant="cgrates.org" AccountIds=["1001"]'
|
||||
|
||||
|
||||
CDR Exporting
|
||||
@@ -192,4 +194,4 @@ To verify this mechanism simply add some random units into one account's balance
|
||||
cgr-console 'balance_set Tenant="cgrates.org" Account="1001" Direction="*out" Value=101'
|
||||
tail -f /var/log/syslog -n 20
|
||||
|
||||
On the CDRs side we will be able to integrate CdrStats monitors as part of our Fraud Detection system (eg: the increase of average cost for 1001 and 1002 accounts will signal us abnormalities, hence we will be notified via syslog).
|
||||
On the CDRs side we will be able to integrate CdrStats monitors as part of our Fraud Detection system (eg: the increase of average cost for 1001 and 1002 accounts will signal us abnormalities, hence we will be notified via syslog).
|
||||
|
||||
@@ -150,7 +150,8 @@ func (self *CdrServer) processCdr(storedCdr *StoredCdr) (err error) {
|
||||
if upData, err := LoadUserProfile(storedCdr, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
*storedCdr = upData.(StoredCdr)
|
||||
cdrRcv := upData.(*StoredCdr)
|
||||
*storedCdr = *cdrRcv
|
||||
}
|
||||
if storedCdr.ReqType == utils.META_NONE {
|
||||
return nil
|
||||
|
||||
@@ -54,6 +54,12 @@ func (rs *Responder) GetCost(arg *CallDescriptor, reply *CallCost) (err error) {
|
||||
if arg.Subject == "" {
|
||||
arg.Subject = arg.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*arg = *udRcv
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
r, e := rs.getCallCost(arg, "Responder.GetCost")
|
||||
*reply, err = *r, e
|
||||
@@ -74,6 +80,12 @@ func (rs *Responder) Debit(arg *CallDescriptor, reply *CallCost) (err error) {
|
||||
if arg.Subject == "" {
|
||||
arg.Subject = arg.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*arg = *udRcv
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
r, e := rs.getCallCost(arg, "Responder.Debit")
|
||||
*reply, err = *r, e
|
||||
@@ -92,6 +104,12 @@ func (rs *Responder) MaxDebit(arg *CallDescriptor, reply *CallCost) (err error)
|
||||
if arg.Subject == "" {
|
||||
arg.Subject = arg.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*arg = *udRcv
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
r, e := rs.getCallCost(arg, "Responder.MaxDebit")
|
||||
*reply, err = *r, e
|
||||
@@ -110,6 +128,12 @@ func (rs *Responder) RefundIncrements(arg *CallDescriptor, reply *float64) (err
|
||||
if arg.Subject == "" {
|
||||
arg.Subject = arg.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*arg = *udRcv
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(arg, "Responder.RefundIncrements")
|
||||
} else {
|
||||
@@ -125,6 +149,12 @@ func (rs *Responder) GetMaxSessionTime(arg *CallDescriptor, reply *float64) (err
|
||||
if arg.Subject == "" {
|
||||
arg.Subject = arg.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*arg = *udRcv
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
*reply, err = rs.callMethod(arg, "Responder.GetMaxSessionTime")
|
||||
} else {
|
||||
@@ -136,11 +166,17 @@ func (rs *Responder) GetMaxSessionTime(arg *CallDescriptor, reply *float64) (err
|
||||
|
||||
// Returns MaxSessionTime for an event received in SessionManager, considering DerivedCharging for it
|
||||
func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) error {
|
||||
if rs.Bal != nil {
|
||||
return errors.New("unsupported method on the balancer")
|
||||
}
|
||||
if ev.Subject == "" {
|
||||
ev.Subject = ev.Account
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
return errors.New("unsupported method on the balancer")
|
||||
if upData, err := LoadUserProfile(ev, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*StoredCdr)
|
||||
*ev = *udRcv
|
||||
}
|
||||
maxCallDuration := -1.0
|
||||
attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT),
|
||||
@@ -205,11 +241,17 @@ func (rs *Responder) GetDerivedMaxSessionTime(ev *StoredCdr, reply *float64) err
|
||||
|
||||
// Used by SM to get all the prepaid CallDescriptors attached to a session
|
||||
func (rs *Responder) GetSessionRuns(ev *StoredCdr, sRuns *[]*SessionRun) error {
|
||||
if rs.Bal != nil {
|
||||
return errors.New("Unsupported method on the balancer")
|
||||
}
|
||||
if ev.Subject == "" {
|
||||
ev.Subject = ev.Account
|
||||
}
|
||||
if rs.Bal != nil {
|
||||
return errors.New("Unsupported method on the balancer")
|
||||
if upData, err := LoadUserProfile(ev, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*StoredCdr)
|
||||
*ev = *udRcv
|
||||
}
|
||||
attrsDC := &utils.AttrDerivedChargers{Tenant: ev.GetTenant(utils.META_DEFAULT), Category: ev.GetCategory(utils.META_DEFAULT), Direction: ev.GetDirection(utils.META_DEFAULT),
|
||||
Account: ev.GetAccount(utils.META_DEFAULT), Subject: ev.GetSubject(utils.META_DEFAULT)}
|
||||
@@ -257,6 +299,12 @@ func (rs *Responder) ProcessCdr(cdr *StoredCdr, reply *string) error {
|
||||
if rs.CdrSrv == nil {
|
||||
return errors.New("CDR_SERVER_NOT_RUNNING")
|
||||
}
|
||||
if upData, err := LoadUserProfile(cdr, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*StoredCdr)
|
||||
*cdr = *udRcv
|
||||
}
|
||||
if err := rs.CdrSrv.ProcessCdr(cdr); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -279,6 +327,12 @@ func (rs *Responder) GetLCR(cd *CallDescriptor, reply *LCRCost) error {
|
||||
if cd.Subject == "" {
|
||||
cd.Subject = cd.Account
|
||||
}
|
||||
if upData, err := LoadUserProfile(cd, "ExtraFields"); err != nil {
|
||||
return err
|
||||
} else {
|
||||
udRcv := upData.(*CallDescriptor)
|
||||
*cd = *udRcv
|
||||
}
|
||||
lcrCost, err := cd.GetLCR(rs.Stats)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -360,10 +360,7 @@ func LoadUserProfile(in interface{}, extraFields string) (interface{}, error) {
|
||||
if userService == nil { // no user service => no fun
|
||||
return in, nil
|
||||
}
|
||||
m, err := utils.ToMapStringString(in)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := utils.ToMapStringString(in)
|
||||
var needsUsers bool
|
||||
for _, val := range m {
|
||||
if val == utils.USERS {
|
||||
@@ -391,12 +388,9 @@ func LoadUserProfile(in interface{}, extraFields string) (interface{}, error) {
|
||||
}
|
||||
// add extra fields
|
||||
if extraFields != "" {
|
||||
extra, err := utils.GetMapExtraFields(in, extraFields)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extra := utils.GetMapExtraFields(in, extraFields)
|
||||
for key, val := range extra {
|
||||
if val != "" {
|
||||
if val != "" && val != utils.USERS {
|
||||
up.Profile[key] = val
|
||||
}
|
||||
}
|
||||
@@ -409,7 +403,9 @@ func LoadUserProfile(in interface{}, extraFields string) (interface{}, error) {
|
||||
up = ups[0]
|
||||
m := up.Profile
|
||||
m["Tenant"] = up.Tenant
|
||||
return utils.FromMapStringString(m, in)
|
||||
utils.FromMapStringString(m, in)
|
||||
utils.SetMapExtraFields(in, m, extraFields)
|
||||
return in, nil
|
||||
}
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package engine
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
@@ -520,7 +521,7 @@ func TestUsersAddUpdateRemoveIndexes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersStoredCDRGetLoadUserProfile(t *testing.T) {
|
||||
func TestUsersUsageRecordGetLoadUserProfile(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"},
|
||||
@@ -562,13 +563,13 @@ func TestUsersStoredCDRGetLoadUserProfile(t *testing.T) {
|
||||
AnswerTime: "t4",
|
||||
Usage: "13",
|
||||
}
|
||||
*ur = out.(UsageRecord)
|
||||
ur = out.(*UsageRecord)
|
||||
if !reflect.DeepEqual(ur, expected) {
|
||||
t.Errorf("Expected: %+v got: %+v", expected, ur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersStoredCDRGetLoadUserProfileExtraFields(t *testing.T) {
|
||||
func TestUsersExternalCdrGetLoadUserProfileExtraFields(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"},
|
||||
@@ -612,14 +613,17 @@ func TestUsersStoredCDRGetLoadUserProfileExtraFields(t *testing.T) {
|
||||
SetupTime: "s4",
|
||||
AnswerTime: "t4",
|
||||
Usage: "13",
|
||||
ExtraFields: map[string]string{
|
||||
"Test": "1",
|
||||
},
|
||||
}
|
||||
*ur = out.(ExternalCdr)
|
||||
ur = out.(*ExternalCdr)
|
||||
if !reflect.DeepEqual(ur, expected) {
|
||||
t.Errorf("Expected: %+v got: %+v", expected, ur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersStoredCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) {
|
||||
func TestUsersExternalCdrGetLoadUserProfileExtraFieldsNotFound(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"},
|
||||
@@ -652,3 +656,147 @@ func TestUsersStoredCDRGetLoadUserProfileExtraFieldsNotFound(t *testing.T) {
|
||||
t.Error("Error detecting err in loading user profile: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersExternalCdrGetLoadUserProfileExtraFieldsSet(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", "Best": "BestValue"},
|
||||
},
|
||||
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",
|
||||
"Best": utils.USERS,
|
||||
},
|
||||
}
|
||||
|
||||
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",
|
||||
ExtraFields: map[string]string{
|
||||
"Test": "1",
|
||||
"Best": "BestValue",
|
||||
},
|
||||
}
|
||||
ur = out.(*ExternalCdr)
|
||||
if !reflect.DeepEqual(ur, expected) {
|
||||
t.Errorf("Expected: %+v got: %+v", expected, ur)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersCallDescLoadUserProfile(t *testing.T) {
|
||||
userService = &UserMap{
|
||||
table: map[string]map[string]string{
|
||||
"cgrates.org:dan": map[string]string{"ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "dan", "Cli": "+4986517174963"},
|
||||
"cgrates.org:danvoice": map[string]string{"TOR": "*voice", "ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "0723"},
|
||||
"cgrates:rif": map[string]string{"ReqType": "*postpaid", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726"},
|
||||
},
|
||||
index: make(map[string]map[string]bool),
|
||||
}
|
||||
startTime := time.Now()
|
||||
cd := &CallDescriptor{
|
||||
TOR: "*sms",
|
||||
Tenant: utils.USERS,
|
||||
Category: utils.USERS,
|
||||
Subject: utils.USERS,
|
||||
Account: utils.USERS,
|
||||
Destination: "+4986517174963",
|
||||
TimeStart: startTime,
|
||||
TimeEnd: startTime.Add(time.Duration(1) * time.Minute),
|
||||
ExtraFields: map[string]string{"Cli": "+4986517174963"},
|
||||
}
|
||||
expected := &CallDescriptor{
|
||||
TOR: "*sms",
|
||||
Tenant: "cgrates.org",
|
||||
Category: "call1",
|
||||
Account: "dan",
|
||||
Subject: "dan",
|
||||
Destination: "+4986517174963",
|
||||
TimeStart: startTime,
|
||||
TimeEnd: startTime.Add(time.Duration(1) * time.Minute),
|
||||
ExtraFields: map[string]string{"Cli": "+4986517174963"},
|
||||
}
|
||||
out, err := LoadUserProfile(cd, "ExtraFields")
|
||||
if err != nil {
|
||||
t.Error("Error loading user profile: ", err)
|
||||
}
|
||||
cdRcv := out.(*CallDescriptor)
|
||||
if !reflect.DeepEqual(expected, cdRcv) {
|
||||
t.Errorf("Expected: %+v got: %+v", expected, cdRcv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsersStoredCdrLoadUserProfile(t *testing.T) {
|
||||
userService = &UserMap{
|
||||
table: map[string]map[string]string{
|
||||
"cgrates.org:dan": map[string]string{"ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "dan", "Cli": "+4986517174963"},
|
||||
"cgrates.org:danvoice": map[string]string{"TOR": "*voice", "ReqType": "*prepaid", "Category": "call1", "Account": "dan", "Subject": "0723"},
|
||||
"cgrates:rif": map[string]string{"ReqType": "*postpaid", "Direction": "*out", "Category": "call", "Account": "rif", "Subject": "0726"},
|
||||
},
|
||||
index: make(map[string]map[string]bool),
|
||||
}
|
||||
startTime := time.Now()
|
||||
cdr := &StoredCdr{
|
||||
TOR: "*sms",
|
||||
ReqType: utils.USERS,
|
||||
Tenant: utils.USERS,
|
||||
Category: utils.USERS,
|
||||
Account: utils.USERS,
|
||||
Subject: utils.USERS,
|
||||
Destination: "+4986517174963",
|
||||
SetupTime: startTime,
|
||||
AnswerTime: startTime,
|
||||
Usage: time.Duration(1) * time.Minute,
|
||||
ExtraFields: map[string]string{"Cli": "+4986517174963"},
|
||||
}
|
||||
expected := &StoredCdr{
|
||||
TOR: "*sms",
|
||||
ReqType: "*prepaid",
|
||||
Tenant: "cgrates.org",
|
||||
Category: "call1",
|
||||
Account: "dan",
|
||||
Subject: "dan",
|
||||
Destination: "+4986517174963",
|
||||
SetupTime: startTime,
|
||||
AnswerTime: startTime,
|
||||
Usage: time.Duration(1) * time.Minute,
|
||||
ExtraFields: map[string]string{"Cli": "+4986517174963"},
|
||||
}
|
||||
out, err := LoadUserProfile(cdr, "ExtraFields")
|
||||
if err != nil {
|
||||
t.Error("Error loading user profile: ", err)
|
||||
}
|
||||
cdRcv := out.(*StoredCdr)
|
||||
if !reflect.DeepEqual(expected, cdRcv) {
|
||||
t.Errorf("Expected: %+v got: %+v", expected, cdRcv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func NonemptyStructFields(s interface{}) map[string]interface{} {
|
||||
}*/
|
||||
|
||||
// Converts a struct to map[string]interface{}
|
||||
func ToMapMapStringInterface(in interface{}) (map[string]interface{}, error) {
|
||||
func ToMapMapStringInterface(in interface{}) map[string]interface{} {
|
||||
out := make(map[string]interface{})
|
||||
|
||||
v := reflect.ValueOf(in)
|
||||
@@ -89,11 +89,11 @@ func ToMapMapStringInterface(in interface{}) (map[string]interface{}, error) {
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
out[typ.Field(i).Name] = v.Field(i).Interface()
|
||||
}
|
||||
return out, nil
|
||||
return out
|
||||
}
|
||||
|
||||
// Converts a struct to map[string]string
|
||||
func ToMapStringString(in interface{}) (map[string]string, error) {
|
||||
func ToMapStringString(in interface{}) map[string]string {
|
||||
out := make(map[string]string)
|
||||
|
||||
v := reflect.ValueOf(in)
|
||||
@@ -110,11 +110,10 @@ func ToMapStringString(in interface{}) (map[string]string, error) {
|
||||
out[typField.Name] = field.String()
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
return out
|
||||
}
|
||||
|
||||
// Converts a struct to map[string]string
|
||||
func GetMapExtraFields(in interface{}, extraFields string) (map[string]string, error) {
|
||||
func GetMapExtraFields(in interface{}, extraFields string) map[string]string {
|
||||
out := make(map[string]string)
|
||||
v := reflect.ValueOf(in)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
@@ -128,21 +127,38 @@ func GetMapExtraFields(in interface{}, extraFields string) (map[string]string, e
|
||||
out[key.String()] = field.MapIndex(key).String()
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
return out
|
||||
}
|
||||
|
||||
func FromMapStringString(m map[string]string, in interface{}) (interface{}, error) {
|
||||
func SetMapExtraFields(in interface{}, values map[string]string, extraFields string) {
|
||||
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() {
|
||||
efField := v.FieldByName(extraFields)
|
||||
if efField.Kind() == reflect.Map {
|
||||
keys := efField.MapKeys()
|
||||
for _, key := range keys {
|
||||
if efField.MapIndex(key).String() != "" {
|
||||
if val, found := values[key.String()]; found {
|
||||
efField.SetMapIndex(key, reflect.ValueOf(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FromMapStringString(m map[string]string, in interface{}) {
|
||||
v := reflect.ValueOf(in)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
in = v.Interface()
|
||||
}
|
||||
for fieldName, fieldValue := range m {
|
||||
field := v.FieldByName(fieldName)
|
||||
if field.IsValid() {
|
||||
if field.Kind() == reflect.String {
|
||||
if v.FieldByName(fieldName).String() != "" {
|
||||
field.SetString(fieldValue)
|
||||
@@ -150,7 +166,7 @@ func FromMapStringString(m map[string]string, in interface{}) (interface{}, erro
|
||||
}
|
||||
}
|
||||
}
|
||||
return elem.Interface(), nil
|
||||
return
|
||||
}
|
||||
|
||||
// Update struct with map fields, returns not matching map keys, s is a struct to be updated
|
||||
|
||||
@@ -18,16 +18,16 @@ func TestStructMapStruct(t *testing.T) {
|
||||
Address: "3",
|
||||
Other: "",
|
||||
}
|
||||
m, err := ToMapStringString(ts)
|
||||
if err != nil {
|
||||
t.Error("Error converting to map: ", err)
|
||||
nts := &TestStruct{
|
||||
Name: "1",
|
||||
Surname: "2",
|
||||
Address: "3",
|
||||
Other: "",
|
||||
}
|
||||
out, err := FromMapStringString(m, ts)
|
||||
if err != nil {
|
||||
t.Error("Error converting to struct: ", err)
|
||||
}
|
||||
nts := out.(TestStruct)
|
||||
if !reflect.DeepEqual(ts, &nts) {
|
||||
m := ToMapStringString(ts)
|
||||
|
||||
FromMapStringString(m, ts)
|
||||
if !reflect.DeepEqual(ts, nts) {
|
||||
t.Log(m)
|
||||
t.Errorf("Expected: %+v got: %+v", ts, nts)
|
||||
}
|
||||
@@ -46,17 +46,17 @@ func TestMapStructAddStructs(t *testing.T) {
|
||||
Address: "3",
|
||||
Other: "",
|
||||
}
|
||||
m, err := ToMapStringString(ts)
|
||||
if err != nil {
|
||||
t.Error("Error converting to map: ", err)
|
||||
nts := &TestStruct{
|
||||
Name: "1",
|
||||
Surname: "2",
|
||||
Address: "3",
|
||||
Other: "",
|
||||
}
|
||||
m := ToMapStringString(ts)
|
||||
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) {
|
||||
FromMapStringString(m, ts)
|
||||
|
||||
if !reflect.DeepEqual(ts, nts) {
|
||||
t.Log(m)
|
||||
t.Errorf("Expected: %+v got: %+v", ts, nts)
|
||||
}
|
||||
@@ -78,10 +78,7 @@ func TestStructExtraFields(t *testing.T) {
|
||||
"k3": "v3",
|
||||
},
|
||||
}
|
||||
efMap, err := GetMapExtraFields(ts, "ExtraFields")
|
||||
if err != nil {
|
||||
t.Error("Error getting extra fields: ", err)
|
||||
}
|
||||
efMap := GetMapExtraFields(ts, "ExtraFields")
|
||||
|
||||
if !reflect.DeepEqual(efMap, ts.ExtraFields) {
|
||||
t.Errorf("expected: %v got: %v", ts.ExtraFields, efMap)
|
||||
|
||||
Reference in New Issue
Block a user