console commands for account trigger APIs

This commit is contained in:
Radu Ioan Fericean
2016-01-26 20:26:15 +02:00
parent b7d0637e15
commit 3da4e2518d
8 changed files with 425 additions and 91 deletions

View File

@@ -556,6 +556,11 @@ func (self *ApierV1) GetActions(actsId string, reply *[]*utils.TPAction) error {
act.RatingSubject = engAct.Balance.RatingSubject
act.SharedGroups = engAct.Balance.SharedGroups.String()
act.BalanceWeight = engAct.Balance.Weight
act.TimingTags = engAct.Balance.TimingIDs.String()
act.BalanceId = engAct.Balance.Id
act.Categories = engAct.Balance.Categories.String()
act.BalanceBlocker = engAct.Balance.Blocker
act.BalanceDisabled = engAct.Balance.Disabled
}
acts = append(acts, act)
}
@@ -658,71 +663,6 @@ func (self *ApierV1) GetActionPlan(attr AttrGetActionPlan, reply *[]*engine.Acti
return nil
}
type AttrAddActionTrigger struct {
ActionTriggersId string
ActionTriggersUniqueId string
Tenant string
Account string
ThresholdType string
ThresholdValue float64
BalanceId string
BalanceType string
BalanceDirection string
BalanceDestinationIds string
BalanceRatingSubject string //ToDo
BalanceWeight float64
BalanceExpiryTime string
BalanceSharedGroup string //ToDo
Weight float64
ActionsId string
}
func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string) error {
if attr.BalanceDirection == "" {
attr.BalanceDirection = utils.OUT
}
balExpiryTime, err := utils.ParseTimeDetectLayout(attr.BalanceExpiryTime, self.Config.DefaultTimezone)
if err != nil {
return utils.NewErrServerError(err)
}
at := &engine.ActionTrigger{
ID: attr.ActionTriggersId,
UniqueID: attr.ActionTriggersUniqueId,
ThresholdType: attr.ThresholdType,
ThresholdValue: attr.ThresholdValue,
BalanceId: attr.BalanceId,
BalanceType: attr.BalanceType,
BalanceDirections: utils.ParseStringMap(attr.BalanceDirection),
BalanceDestinationIds: utils.ParseStringMap(attr.BalanceDestinationIds),
BalanceWeight: attr.BalanceWeight,
BalanceExpirationDate: balExpiryTime,
Weight: attr.Weight,
ActionsId: attr.ActionsId,
Executed: false,
}
tag := utils.AccountKey(attr.Tenant, attr.Account)
_, err = engine.Guardian.Guard(func() (interface{}, error) {
userBalance, err := self.AccountDb.GetAccount(tag)
if err != nil {
return 0, err
}
userBalance.ActionTriggers = append(userBalance.ActionTriggers, at)
if err = self.AccountDb.SetAccount(userBalance); err != nil {
return 0, err
}
return 0, nil
}, 0, tag)
if err != nil {
*reply = err.Error()
return err
}
*reply = OK
return nil
}
type AttrResetTriggeredAction struct {
Id string
Tenant string

View File

@@ -5,30 +5,95 @@ import (
"github.com/cgrates/cgrates/utils"
)
type AttrSetActionTriggers struct {
type AttrAddActionTrigger struct {
ActionTriggersId string
ActionTriggersUniqueId string
Tenant string
Account string
ActionTriggersIds *[]string
ThresholdType string
ThresholdValue float64
BalanceId string
BalanceType string
BalanceDirection string
BalanceDestinationIds string
BalanceRatingSubject string //ToDo
BalanceWeight float64
BalanceExpiryTime string
BalanceSharedGroup string //ToDo
Weight float64
ActionsId string
}
func (self *ApierV1) AddTriggeredAction(attr AttrAddActionTrigger, reply *string) error {
if attr.BalanceDirection == "" {
attr.BalanceDirection = utils.OUT
}
balExpiryTime, err := utils.ParseTimeDetectLayout(attr.BalanceExpiryTime, self.Config.DefaultTimezone)
if err != nil {
return utils.NewErrServerError(err)
}
at := &engine.ActionTrigger{
ID: attr.ActionTriggersId,
UniqueID: attr.ActionTriggersUniqueId,
ThresholdType: attr.ThresholdType,
ThresholdValue: attr.ThresholdValue,
BalanceId: attr.BalanceId,
BalanceType: attr.BalanceType,
BalanceDirections: utils.ParseStringMap(attr.BalanceDirection),
BalanceDestinationIds: utils.ParseStringMap(attr.BalanceDestinationIds),
BalanceWeight: attr.BalanceWeight,
BalanceExpirationDate: balExpiryTime,
Weight: attr.Weight,
ActionsId: attr.ActionsId,
Executed: false,
}
tag := utils.AccountKey(attr.Tenant, attr.Account)
_, err = engine.Guardian.Guard(func() (interface{}, error) {
userBalance, err := self.AccountDb.GetAccount(tag)
if err != nil {
return 0, err
}
userBalance.ActionTriggers = append(userBalance.ActionTriggers, at)
if err = self.AccountDb.SetAccount(userBalance); err != nil {
return 0, err
}
return 0, nil
}, 0, tag)
if err != nil {
*reply = err.Error()
return err
}
*reply = OK
return nil
}
type AttrSetAccountActionTriggers struct {
Tenant string
Account string
ActionTriggersIDs *[]string
ActionTriggerOverwrite bool
}
func (self *ApierV1) SetActionTriggers(attr AttrSetActionTriggers, reply *string) error {
func (self *ApierV1) SetAccountActionTriggers(attr AttrSetAccountActionTriggers, reply *string) error {
if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
accID := utils.AccountKey(attr.Tenant, attr.Account)
var account *engine.Account
_, err := engine.Guardian.Guard(func() (interface{}, error) {
if acc, err := self.AccountDb.GetAccount(accID); err != nil {
if acc, err := self.AccountDb.GetAccount(accID); err == nil {
account = acc
} else {
return 0, err
}
if attr.ActionTriggersIds != nil {
if attr.ActionTriggersIDs != nil {
if attr.ActionTriggerOverwrite {
account.ActionTriggers = make(engine.ActionTriggers, 0)
}
for _, actionTriggerID := range *attr.ActionTriggersIds {
for _, actionTriggerID := range *attr.ActionTriggersIDs {
atrs, err := self.RatingDb.GetActionTriggers(actionTriggerID)
if err != nil {
@@ -49,6 +114,9 @@ func (self *ApierV1) SetActionTriggers(attr AttrSetActionTriggers, reply *string
}
}
account.InitCounters()
if err := self.AccountDb.SetAccount(account); err != nil {
return 0, err
}
return 0, nil
}, 0, accID)
if err != nil {
@@ -59,21 +127,21 @@ func (self *ApierV1) SetActionTriggers(attr AttrSetActionTriggers, reply *string
return nil
}
type AttrRemoveActionTriggers struct {
type AttrRemoveAccountActionTriggers struct {
Tenant string
Account string
GroupID string
UniqueID string
}
func (self *ApierV1) RemoveActionTriggers(attr AttrRemoveActionTriggers, reply *string) error {
func (self *ApierV1) RemoveAccountActionTriggers(attr AttrRemoveAccountActionTriggers, reply *string) error {
if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
}
accID := utils.AccountKey(attr.Tenant, attr.Account)
var account *engine.Account
_, err := engine.Guardian.Guard(func() (interface{}, error) {
if acc, err := self.AccountDb.GetAccount(accID); err != nil {
var account *engine.Account
if acc, err := self.AccountDb.GetAccount(accID); err == nil {
account = acc
} else {
return 0, err
@@ -88,8 +156,10 @@ func (self *ApierV1) RemoveActionTriggers(attr AttrRemoveActionTriggers, reply *
newActionTriggers = append(newActionTriggers, at)
}
account.ActionTriggers = newActionTriggers
account.InitCounters()
if err := self.AccountDb.SetAccount(account); err != nil {
return 0, err
}
return 0, nil
}, 0, accID)
if err != nil {
@@ -100,14 +170,7 @@ func (self *ApierV1) RemoveActionTriggers(attr AttrRemoveActionTriggers, reply *
return nil
}
type AttrResetActionTriggers struct {
Tenant string
Account string
GroupID string
UniqueID string
}
func (self *ApierV1) ResetActionTriggers(attr AttrResetActionTriggers, reply *string) error {
func (self *ApierV1) ResetAccountActionTriggers(attr AttrRemoveAccountActionTriggers, reply *string) error {
if missing := utils.MissingStructFields(&attr, []string{"Tenant", "Account"}); len(missing) != 0 {
return utils.NewErrMandatoryIeMissing(missing...)
@@ -115,7 +178,7 @@ func (self *ApierV1) ResetActionTriggers(attr AttrResetActionTriggers, reply *st
accID := utils.AccountKey(attr.Tenant, attr.Account)
var account *engine.Account
_, err := engine.Guardian.Guard(func() (interface{}, error) {
if acc, err := self.AccountDb.GetAccount(accID); err != nil {
if acc, err := self.AccountDb.GetAccount(accID); err == nil {
account = acc
} else {
return 0, err
@@ -129,6 +192,9 @@ func (self *ApierV1) ResetActionTriggers(attr AttrResetActionTriggers, reply *st
}
account.ExecuteActionTriggers(nil)
if err := self.AccountDb.SetAccount(account); err != nil {
return 0, err
}
return 0, nil
}, 0, accID)
if err != nil {

View File

@@ -81,9 +81,9 @@ func (self *ApierV2) GetAccount(attr *utils.AttrGetAccount, reply *engine.Accoun
type AttrSetAccount struct {
Tenant string
Account string
ActionPlanIds *[]string
ActionPlanIDs *[]string
ActionPlansOverwrite bool
ActionTriggersIds *[]string
ActionTriggerIDs *[]string
ActionTriggerOverwrite bool
AllowNegative *bool
Disabled *bool
@@ -105,7 +105,7 @@ func (self *ApierV2) SetAccount(attr AttrSetAccount, reply *string) error {
Id: accID,
}
}
if attr.ActionPlanIds != nil {
if attr.ActionPlanIDs != nil {
_, err := engine.Guardian.Guard(func() (interface{}, error) {
actionPlansMap, err := self.RatingDb.GetAllActionPlans()
if err != nil {
@@ -121,7 +121,7 @@ func (self *ApierV2) SetAccount(attr AttrSetAccount, reply *string) error {
}
}
for _, actionPlanID := range *attr.ActionPlanIds {
for _, actionPlanID := range *attr.ActionPlanIDs {
ap, ok := actionPlansMap[actionPlanID]
if !ok {
return 0, utils.ErrNotFound
@@ -162,11 +162,11 @@ func (self *ApierV2) SetAccount(attr AttrSetAccount, reply *string) error {
}
}
if attr.ActionTriggersIds != nil {
if attr.ActionTriggerIDs != nil {
if attr.ActionTriggerOverwrite {
ub.ActionTriggers = make(engine.ActionTriggers, 0)
}
for _, actionTriggerID := range *attr.ActionTriggersIds {
for _, actionTriggerID := range *attr.ActionTriggerIDs {
atrs, err := self.RatingDb.GetActionTriggers(actionTriggerID)
if err != nil {
return 0, err

63
console/trigger_remove.go Normal file
View File

@@ -0,0 +1,63 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import "github.com/cgrates/cgrates/apier/v1"
func init() {
c := &CmdRemoveTriggers{
name: "triggers_remove",
rpcMethod: "ApierV1.RemoveAccountActionTriggers",
rpcParams: &v1.AttrRemoveAccountActionTriggers{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
// Commander implementation
type CmdRemoveTriggers struct {
name string
rpcMethod string
rpcParams *v1.AttrRemoveAccountActionTriggers
*CommandExecuter
}
func (self *CmdRemoveTriggers) Name() string {
return self.name
}
func (self *CmdRemoveTriggers) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdRemoveTriggers) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &v1.AttrRemoveAccountActionTriggers{}
}
return self.rpcParams
}
func (self *CmdRemoveTriggers) PostprocessRpcParams() error {
return nil
}
func (self *CmdRemoveTriggers) RpcResult() interface{} {
var s string
return &s
}

63
console/trigger_reset.go Normal file
View File

@@ -0,0 +1,63 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import "github.com/cgrates/cgrates/apier/v1"
func init() {
c := &CmdResetTriggers{
name: "triggers_reset",
rpcMethod: "ApierV1.ResetAccountActionTriggers",
rpcParams: &v1.AttrRemoveAccountActionTriggers{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
// Commander implementation
type CmdResetTriggers struct {
name string
rpcMethod string
rpcParams *v1.AttrRemoveAccountActionTriggers
*CommandExecuter
}
func (self *CmdResetTriggers) Name() string {
return self.name
}
func (self *CmdResetTriggers) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdResetTriggers) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &v1.AttrRemoveAccountActionTriggers{}
}
return self.rpcParams
}
func (self *CmdResetTriggers) PostprocessRpcParams() error {
return nil
}
func (self *CmdResetTriggers) RpcResult() interface{} {
var s string
return &s
}

63
console/trigger_set.go Normal file
View File

@@ -0,0 +1,63 @@
/*
Rating system designed to be used in VoIP Carriers World
Copyright (C) 2012-2015 ITsysCOM
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package console
import "github.com/cgrates/cgrates/apier/v1"
func init() {
c := &CmdSetTriggers{
name: "triggers_set",
rpcMethod: "ApierV1.SetAccountActionTriggers",
rpcParams: &v1.AttrSetAccountActionTriggers{},
}
commands[c.Name()] = c
c.CommandExecuter = &CommandExecuter{c}
}
// Commander implementation
type CmdSetTriggers struct {
name string
rpcMethod string
rpcParams *v1.AttrSetAccountActionTriggers
*CommandExecuter
}
func (self *CmdSetTriggers) Name() string {
return self.name
}
func (self *CmdSetTriggers) RpcMethod() string {
return self.rpcMethod
}
func (self *CmdSetTriggers) RpcParams(reset bool) interface{} {
if reset || self.rpcParams == nil {
self.rpcParams = &v1.AttrSetAccountActionTriggers{}
}
return self.rpcParams
}
func (self *CmdSetTriggers) PostprocessRpcParams() error {
return nil
}
func (self *CmdSetTriggers) RpcResult() interface{} {
var s string
return &s
}

View File

@@ -294,6 +294,7 @@ func (at *ActionTiming) Execute() (err error) {
// check action filter
if len(a.Filter) > 0 {
matched, err := ub.matchActionFilter(a.Filter)
//log.Print("Checkng: ", a.Filter, matched)
if err != nil {
return 0, err
}

View File

@@ -1759,6 +1759,144 @@ func TestActionConditionalTopupExistingBalance(t *testing.T) {
}
}
func TestActionConditionalDisabledIfNegative(t *testing.T) {
err := accountingStorage.SetAccount(
&Account{
Id: "cgrates.org:af",
BalanceMap: map[string]BalanceChain{
"*data": BalanceChain{
&Balance{
Uuid: "fc927edb-1bd6-425e-a2a3-9fd8bafaa524",
Id: "for_v3hsillmilld500m_data_500_m",
Value: 5.242,
Weight: 10,
RatingSubject: "for_v3hsillmilld500m_data_forfait",
Categories: utils.StringMap{
"data_france": true,
},
},
},
"*monetary": BalanceChain{
&Balance{
Uuid: "9fa1847a-f36a-41a7-8ec0-dfaab370141e",
Id: "*default",
Value: -1.95001,
},
},
"*sms": BalanceChain{
&Balance{
Uuid: "d348d15d-2988-4ee4-b847-6a552f94e2ec",
Id: "for_v3hsillmilld500m_mms_ill",
Value: 20000,
Weight: 10,
DestinationIds: utils.StringMap{
"FRANCE_NATIONAL": true,
},
Categories: utils.StringMap{
"mms_france": true,
"tmms_france": true,
"vmms_france": true,
},
},
&Balance{
Uuid: "f4643517-31f6-4199-980f-04cf535471ed",
Id: "for_v3hsillmilld500m_sms_ill",
Value: 20000,
Weight: 10,
DestinationIds: utils.StringMap{
"FRANCE_NATIONAL": true,
},
Categories: utils.StringMap{
"ms_france": true,
},
},
},
"*voice": BalanceChain{
&Balance{
Uuid: "079ab190-77f4-44f3-9c6f-3a0dd1a59dfd",
Id: "for_v3hsillmilld500m_voice_3_h",
Value: 10800,
Weight: 10,
DestinationIds: utils.StringMap{
"FRANCE_NATIONAL": true,
},
Categories: utils.StringMap{
"call_france": true,
},
},
},
},
})
if err != nil {
t.Errorf("error setting account: %v", err)
}
a1 := &Action{
ActionType: "*enable_disable_balance",
BalanceType: "*sms",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &Balance{
Weight: 10,
Disabled: true,
},
Weight: 9,
}
a2 := &Action{
ActionType: "*enable_disable_balance",
BalanceType: "*sms",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &Balance{
DestinationIds: utils.NewStringMap("FRANCE_NATIONAL"),
Weight: 10,
Disabled: true,
},
Weight: 8,
}
a3 := &Action{
ActionType: "*enable_disable_balance",
BalanceType: "*data",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &Balance{
RatingSubject: "for_v3hsillmilld500m_data_forfait",
Weight: 10,
Disabled: true,
},
Weight: 7,
}
a4 := &Action{
ActionType: "*enable_disable_balance",
BalanceType: "*voice",
Filter: "{\"*and\":[{\"Value\":{\"*lt\":0}},{\"Id\":{\"*eq\":\"*default\"}}]}",
Balance: &Balance{
DestinationIds: utils.NewStringMap("FRANCE_NATIONAL"),
Weight: 10,
Disabled: true,
},
Weight: 6,
}
at := &ActionTiming{
accountIDs: utils.StringMap{"cgrates.org:af": true},
actions: Actions{a1, a2, a3, a4},
}
at.Execute()
afterUb, err := accountingStorage.GetAccount("cgrates.org:af")
if err != nil {
t.Error("account not found: ", err, afterUb)
}
for btype, chain := range afterUb.BalanceMap {
if btype != utils.MONETARY {
for _, b := range chain {
if b.Disabled != true {
t.Errorf("Failed to disabled balance (%s): %+v", btype, b)
}
}
}
}
}
func TestActionSetBalance(t *testing.T) {
err := accountingStorage.SetAccount(
&Account{