From c04bc753fdef5eaf3b556c34644d80672aee16da Mon Sep 17 00:00:00 2001 From: DanB Date: Mon, 23 Dec 2013 14:26:33 +0100 Subject: [PATCH] Adding SetActions and SetActionTimings Apier methods --- apier/v1/apier.go | 115 +++++++++++++++++++++++++++++++++++ apier/v1/apier_local_test.go | 36 +++++++++++ cdrc/.cdrc.go.swp | Bin 20480 -> 0 bytes engine/storage_interface.go | 1 + utils/consts.go | 3 +- 5 files changed, 154 insertions(+), 1 deletion(-) delete mode 100644 cdrc/.cdrc.go.swp diff --git a/apier/v1/apier.go b/apier/v1/apier.go index bd508dc4a..8890f404c 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -184,6 +184,121 @@ func (self *ApierV1) SetRatingProfile(attrs utils.TPRatingProfile, reply *string return nil } +type AttrSetActions struct { + ActionsId string // Actions id + Overwrite bool // If previously defined, will be overwritten + Actions []*utils.TPAction // Set of actions this Actions profile will perform +} + +func (self *ApierV1) SetActions(attrs AttrSetActions, reply *string) error { + if missing := utils.MissingStructFields(&attrs, []string{"ActionsId", "Actions"}); len(missing) != 0 { + return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) + } + for _, action := range attrs.Actions { + requiredFields := []string{"Identifier", "Weight"} + if action.BalanceType != "" { // Add some inter-dependent parameters - if balanceType then we are not talking about simply calling actions + requiredFields = append(requiredFields, "Direction", "Units") + } + if missing := utils.MissingStructFields(action, requiredFields); len(missing) != 0 { + return fmt.Errorf("%s:Action:%s:%v", utils.ERR_MANDATORY_IE_MISSING, action.Identifier, missing) + } + } + if !attrs.Overwrite { + if exists, err := self.AccountDb.ExistsData(engine.ACTION_PREFIX, attrs.ActionsId); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } else if exists { + return errors.New(utils.ERR_EXISTS) + } + } + storeActions := make(engine.Actions, len(attrs.Actions)) + for idx, apiAct := range attrs.Actions { + a := &engine.Action{ + Id: utils.GenUUID(), + ActionType: apiAct.Identifier, + BalanceId: apiAct.BalanceType, + Direction: apiAct.Direction, + Weight: apiAct.Weight, + ExpirationString: apiAct.ExpiryTime, + ExtraParameters: apiAct.ExtraParameters, + Balance: &engine.Balance{ + Uuid: utils.GenUUID(), + Value: apiAct.Units, + Weight: apiAct.BalanceWeight, + DestinationId: apiAct.DestinationId, + RateSubject: apiAct.RatingSubject, + }, + } + storeActions[idx] = a + } + if err := self.AccountDb.SetActions(attrs.ActionsId, storeActions); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + *reply = OK + return nil +} + +type AttrSetActionTimings struct { + ActionTimingsId string // Profile id + Overwrite bool // If previously defined, will be overwritten + ActionTimings []*ApiActionTiming // Set of actions this Actions profile will perform +} + +type ApiActionTiming struct { + ActionsId string // Actions id + Years string // semicolon separated list of years this timing is valid on, *any or empty supported + Months string // semicolon separated list of months this timing is valid on, *any or empty supported + MonthDays string // semicolon separated list of month's days this timing is valid on, *any or empty supported + WeekDays string // semicolon separated list of week day names this timing is valid on *any or empty supported + Time string // String representing the time this timing starts on, *asap supported + Weight float64 // Binding's weight +} + +func (self *ApierV1) SetActionTimings(attrs AttrSetActionTimings, reply *string) error { + if missing := utils.MissingStructFields(&attrs, []string{"ActionTimingsId", "ActionTimings"}); len(missing) != 0 { + return fmt.Errorf("%s:%v", utils.ERR_MANDATORY_IE_MISSING, missing) + } + for _, at := range attrs.ActionTimings { + requiredFields := []string{"ActionsId", "Time", "Weight"} + if missing := utils.MissingStructFields(at, requiredFields); len(missing) != 0 { + return fmt.Errorf("%s:Action:%s:%v", utils.ERR_MANDATORY_IE_MISSING, at.ActionsId, missing) + } + } + if !attrs.Overwrite { + if exists, err := self.AccountDb.ExistsData(engine.ACTION_TIMING_PREFIX, attrs.ActionTimingsId); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } else if exists { + return errors.New(utils.ERR_EXISTS) + } + } + storeAtms := make(engine.ActionTimings, len(attrs.ActionTimings)) + for idx, apiAtm := range attrs.ActionTimings { + if exists, err := self.AccountDb.ExistsData(engine.ACTION_PREFIX, apiAtm.ActionsId); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } else if !exists { + return fmt.Errorf("%s:%s", utils.ERR_BROKEN_REFERENCE, err.Error()) + } + timing := new(engine.RITiming) + timing.Years.Parse(apiAtm.Years, ";") + timing.Months.Parse(apiAtm.Months, ";") + timing.MonthDays.Parse(apiAtm.MonthDays, ";") + timing.WeekDays.Parse(apiAtm.WeekDays, ";") + timing.StartTime = apiAtm.Time + at := &engine.ActionTiming{ + Id: utils.GenUUID(), + Tag: attrs.ActionTimingsId, + Weight: apiAtm.Weight, + Timing: &engine.RateInterval{Timing:timing}, + ActionsId: apiAtm.ActionsId, + } + storeAtms[idx] = at + } + if err := self.AccountDb.SetActionTimings(attrs.ActionTimingsId, storeAtms); err != nil { + return fmt.Errorf("%s:%s", utils.ERR_SERVER_ERROR, err.Error()) + } + *reply = OK + return nil +} + type AttrAddActionTrigger struct { Tenant string Account string diff --git a/apier/v1/apier_local_test.go b/apier/v1/apier_local_test.go index 160124d92..090855c3d 100644 --- a/apier/v1/apier_local_test.go +++ b/apier/v1/apier_local_test.go @@ -876,6 +876,42 @@ func TestApierExecuteAction(t *testing.T) { } } +func TestApierSetActions(t *testing.T) { + if !*testLocal { + return + } + act1 := &utils.TPAction {Identifier: engine.TOPUP_RESET, BalanceType: engine.CREDIT, Direction: engine.OUTBOUND, Units: 75.0, ExpiryTime: engine.UNLIMITED, Weight: 20.0} + attrs1 := &AttrSetActions{ActionsId: "ACTS_1", Actions : []*utils.TPAction{act1}} + reply1 := "" + if err := rater.Call("ApierV1.SetActions", attrs1, &reply1); err != nil { + t.Error("Got error on ApierV1.SetActions: ", err.Error()) + } else if reply1 != "OK" { + t.Errorf("Calling ApierV1.SetActions received: %s", reply1) + } + // Calling the second time should raise EXISTS + if err := rater.Call("ApierV1.SetActions", attrs1, &reply1); err == nil || err.Error() != "EXISTS"{ + t.Error("Unexpected result on duplication: ", err.Error()) + } +} + +func TestApierSetActionTimings(t *testing.T) { + if !*testLocal { + return + } + atm1 := &ApiActionTiming{ActionsId: "ACTS_1", MonthDays: "1", Time: "00:00:00", Weight: 20.0} + atms1 := &AttrSetActionTimings{ ActionTimingsId: "ATMS_1", ActionTimings: []*ApiActionTiming{atm1} } + reply1 := "" + if err := rater.Call("ApierV1.SetActionTimings", atms1, &reply1); err != nil { + t.Error("Got error on ApierV1.SetActionTimings: ", err.Error()) + } else if reply1 != "OK" { + t.Errorf("Calling ApierV1.SetActionTimings received: %s", reply1) + } + // Calling the second time should raise EXISTS + if err := rater.Call("ApierV1.SetActionTimings", atms1, &reply1); err == nil || err.Error() != "EXISTS"{ + t.Error("Unexpected result on duplication: ", err.Error()) + } +} + // Test here AddTriggeredAction func TestApierAddTriggeredAction(t *testing.T) { if !*testLocal { diff --git a/cdrc/.cdrc.go.swp b/cdrc/.cdrc.go.swp deleted file mode 100644 index e5df2cc19d144e21c6f0450bea512ee6b6a7da1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 HQgHqceP+9@ diff --git a/engine/storage_interface.go b/engine/storage_interface.go index a4ec94411..1235e0158 100644 --- a/engine/storage_interface.go +++ b/engine/storage_interface.go @@ -80,6 +80,7 @@ type RatingStorage interface { type AccountingStorage interface { Storage + ExistsData(string, string) (bool, error) CacheAccounting([]string) error GetActions(string, bool) (Actions, error) SetActions(string, Actions) error diff --git a/utils/consts.go b/utils/consts.go index ec820bf6a..9bf8e6327 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -18,7 +18,8 @@ const ( ERR_SERVER_ERROR = "SERVER_ERROR" ERR_NOT_FOUND = "NOT_FOUND" ERR_MANDATORY_IE_MISSING = "MANDATORY_IE_MISSING" - ERR_DUPLICATE = "DUPLICATE" + ERR_EXISTS = "EXISTS" + ERR_BROKEN_REFERENCE = "BROKEN_REFERENCE" TBL_TP_TIMINGS = "tp_timings" TBL_TP_DESTINATIONS = "tp_destinations" TBL_TP_RATES = "tp_rates"