From bcb089822f47c8c1c030b9c10be594cb45999f0a Mon Sep 17 00:00:00 2001 From: arberkatellari Date: Tue, 17 Sep 2024 10:24:20 +0200 Subject: [PATCH] Add APIerSV1TimingIsActiveAt --- apier/v1/apier.go | 19 ++++++++ general_tests/balance_timings_it_test.go | 31 +++++++++++++ utils/apitpdata.go | 59 ++++++++++++++++++++++++ utils/consts.go | 1 + 4 files changed, 110 insertions(+) diff --git a/apier/v1/apier.go b/apier/v1/apier.go index 711e976ee..ea839fecc 100644 --- a/apier/v1/apier.go +++ b/apier/v1/apier.go @@ -2057,3 +2057,22 @@ func (apierSv1 *APIerSv1) ExportCDRs(ctx *context.Context, args *utils.ArgExport } return } + +type TimeParams struct { + TimingID string // Holds the TimingID to get from the DataDB + Time string // Time to compare with TimingID +} + +// Replies true if the TimingID is active at the specified time, false if not +func (apierSv1 *APIerSv1) TimingIsActiveAt(ctx *context.Context, params TimeParams, reply *bool) (err error) { + timing, err := apierSv1.DataManager.GetTiming(params.TimingID, false, utils.NonTransactional) + if err != nil { + return err + } + if tm, err := utils.ParseTimeDetectLayout(params.Time, apierSv1.Config.GeneralCfg().DefaultTimezone); err != nil { + return err + } else { + *reply = timing.IsActiveAt(tm) + } + return +} diff --git a/general_tests/balance_timings_it_test.go b/general_tests/balance_timings_it_test.go index d135cdfcb..573fc97fb 100644 --- a/general_tests/balance_timings_it_test.go +++ b/general_tests/balance_timings_it_test.go @@ -129,6 +129,37 @@ HALF2,*any,*any,*any,*any,12:00:00;23:59:59`, client, _ := testEnv.Setup(t, *utils.WaitRater) time.Sleep(50 * time.Millisecond) + t.Run("TimingIsActiveAt", func(t *testing.T) { + var reply *bool + params := &v1.TimeParams{ + TimingID: "HALF1", + Time: "2024-09-17T10:00:00Z", + } + if err := client.Call(context.Background(), utils.APIerSV1TimingIsActiveAt, params, &reply); err != nil { + t.Fatal(err) + } else if !*reply { + t.Errorf("expected TimingID to be Active") + } + params = &v1.TimeParams{ + TimingID: "HALF2", + Time: "2024-09-17T10:00:00Z", + } + if err := client.Call(context.Background(), utils.APIerSV1TimingIsActiveAt, params, &reply); err != nil { + t.Fatal(err) + } else if *reply { + t.Errorf("expected TimingID to be inactive") + } + params = &v1.TimeParams{ + TimingID: "HALF2", + Time: "2024-09-17T12:00:00Z", + } + if err := client.Call(context.Background(), utils.APIerSV1TimingIsActiveAt, params, &reply); err != nil { + t.Fatal(err) + } else if !*reply { + t.Errorf("expected TimingID to be Active") + } + }) + t.Run("GetAccount", func(t *testing.T) { var acnt engine.Account attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"} diff --git a/utils/apitpdata.go b/utils/apitpdata.go index d769bf1db..bf87b97fc 100644 --- a/utils/apitpdata.go +++ b/utils/apitpdata.go @@ -22,6 +22,7 @@ import ( "fmt" "slices" "sort" + "strconv" "strings" "time" ) @@ -191,6 +192,64 @@ type TPTiming struct { EndTime string } +// Returns wheter the Timing is active at the specified time +func (t *TPTiming) IsActiveAt(tm time.Time) bool { + // check for years + if len(t.Years) > 0 && !t.Years.Contains(tm.Year()) { + return false + } + // check for months + if len(t.Months) > 0 && !t.Months.Contains(tm.Month()) { + return false + } + // check for month days + if len(t.MonthDays) > 0 && !t.MonthDays.Contains(tm.Day()) { + return false + } + // check for weekdays + if len(t.WeekDays) > 0 && !t.WeekDays.Contains(tm.Weekday()) { + return false + } + // check for start hour + if tm.Before(t.getLeftMargin(tm)) { + return false + } + // check for end hour + if tm.After(t.getRightMargin(tm)) { + return false + } + return true +} + +// Returns a time object that represents the end of the interval realtive to the received time +func (t *TPTiming) getRightMargin(tm time.Time) (rigthtTime time.Time) { + year, month, day := tm.Year(), tm.Month(), tm.Day() + hour, min, sec, nsec := 23, 59, 59, 0 + loc := tm.Location() + if t.EndTime != "" { + split := strings.Split(t.EndTime, ":") + hour, _ = strconv.Atoi(split[0]) + min, _ = strconv.Atoi(split[1]) + sec, _ = strconv.Atoi(split[2]) + return time.Date(year, month, day, hour, min, sec, nsec, loc) + } + return time.Date(year, month, day, hour, min, sec, nsec, loc).Add(time.Second) +} + +// Returns a time object that represents the start of the interval realtive to the received time +func (t *TPTiming) getLeftMargin(tm time.Time) (rigthtTime time.Time) { + year, month, day := tm.Year(), tm.Month(), tm.Day() + hour, min, sec, nsec := 0, 0, 0, 0 + loc := tm.Location() + if t.StartTime != "" { + split := strings.Split(t.StartTime, ":") + hour, _ = strconv.Atoi(split[0]) + min, _ = strconv.Atoi(split[1]) + sec, _ = strconv.Atoi(split[2]) + } + return time.Date(year, month, day, hour, min, sec, nsec, loc) +} + // TPTimingWithAPIOpts is used in replicatorV1 for dispatcher type TPTimingWithAPIOpts struct { *TPTiming diff --git a/utils/consts.go b/utils/consts.go index 55295c506..d2a766b29 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -1543,6 +1543,7 @@ const ( APIerSv1SetTiming = "APIerSv1.SetTiming" APIerSv1RemoveTiming = "APIerSv1.RemoveTiming" APIerSV1GetAccountCost = "APIerSv1.GetAccountCost" + APIerSV1TimingIsActiveAt = "APIerSv1.TimingIsActiveAt" ) // APIerSv1 TP APIs