This commit is contained in:
DanB
2015-07-15 19:11:23 +02:00
58 changed files with 568 additions and 271 deletions

View File

@@ -28,6 +28,11 @@ 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, "")
if err != nil {
return err
}
usageRecord = out.(engine.UsageRecord)
if usageRecord.TOR == "" {
usageRecord.TOR = utils.VOICE
}

View File

@@ -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, "ExtraFields")
if err != nil {
*reply = err.Error()
return err
}
*cdr = out.(engine.ExternalCdr)
if err := self.CdrSrv.ProcessExternalCdr(cdr); err != nil {
return utils.NewErrServerError(err)
}

View File

@@ -27,6 +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...)
}
out, err := engine.LoadUserProfile(usageRecord, "")
if err != nil {
*reply = err.Error()
return err
}
usageRecord = out.(engine.UsageRecord)
if usageRecord.TOR == "" {
usageRecord.TOR = utils.VOICE
}

View File

@@ -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:

View File

@@ -541,7 +541,7 @@ func main() {
return
}
}
//engine.SetPubSub(users)
engine.SetUserService(userServer)
}()
wg.Wait()

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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{}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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{} {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {
@@ -61,6 +58,6 @@ func (self *CmdGetUsers) PostprocessRpcParams() error {
}
func (self *CmdGetUsers) RpcResult() interface{} {
s := []*engine.UserProfile{}
s := engine.UserProfiles{}
return &s
}

View File

@@ -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

View File

@@ -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)
}
@@ -318,3 +354,50 @@ 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 LoadUserProfile(in interface{}, extraFields string) (interface{}, error) {
m, err := utils.ToMapStringString(in)
if err != nil {
return nil, err
}
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
}
}
// 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
}
if len(ups) > 0 {
up = ups[0]
m := up.Profile
m["Tenant"] = up.Tenant
return utils.FromMapStringString(m, in)
}
return nil, utils.ErrNotFound
}

View File

@@ -1,6 +1,7 @@
package engine
import (
"reflect"
"testing"
"github.com/cgrates/cgrates/utils"
@@ -148,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)
}
}
@@ -163,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)
}
}
@@ -178,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)
}
}
@@ -193,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)
}
}
@@ -207,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)
}
}
@@ -221,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)
}
}
@@ -234,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)
@@ -248,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)
@@ -297,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)
}
}
@@ -315,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)
}
}
@@ -333,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)
}
}
@@ -351,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)
}
}
@@ -368,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)
}
}
@@ -385,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)
}
}
@@ -401,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)
@@ -418,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)
}
}
@@ -501,3 +519,136 @@ 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: "",
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)
}
}
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)
}
}

View File

@@ -83,6 +83,7 @@ const (
ROUNDING_DOWN = "*down"
ANY = "*any"
ASAP = "*asap"
USERS = "*users"
COMMENT_CHAR = '#'
CSV_SEP = ','
FALLBACK_SEP = ';'

View File

@@ -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,82 @@ 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 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
typField := typ.Field(i)
field := v.Field(i)
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 {
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 {
if v.FieldByName(fieldName).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

89
utils/struct_test.go Normal file
View File

@@ -0,0 +1,89 @@
package utils
import (
"reflect"
"testing"
)
func TestStructMapStruct(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)
}
}
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)
}
}