mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
ActionProfile modifications
This commit is contained in:
committed by
Dan Christian Bogos
parent
e3bf9e10ec
commit
38e7c7eb39
@@ -66,9 +66,8 @@ func (aL *actSetBalance) execute(ctx *context.Context, data utils.MapStorage, tr
|
||||
if val, err = rsr.ParseDataProvider(data); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
args.Diktats[i] = &utils.BalDiktat{
|
||||
Path: actD.Path,
|
||||
Path: utils.IfaceAsString(actD.Opts[utils.MetaBalancePath]),
|
||||
Value: val,
|
||||
}
|
||||
}
|
||||
@@ -106,7 +105,7 @@ func (aL *actRemBalance) execute(ctx *context.Context, data utils.MapStorage, tr
|
||||
APIOpts: aL.cfg().Opts,
|
||||
}
|
||||
for i, actD := range aL.cfg().Diktats {
|
||||
args.BalanceIDs[i] = actD.Path
|
||||
args.BalanceIDs[i] = utils.IfaceAsString(actD.Opts[utils.MetaBalancePath])
|
||||
}
|
||||
var rply string
|
||||
return aL.connMgr.Call(ctx, aL.config.ActionSCfg().AccountSConns,
|
||||
|
||||
@@ -45,9 +45,9 @@ func parseParamStringToMap(paramStr string, targetMap map[string]any) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// actDynamicThreshold processes the `ActionValue` field from the action to construct a Threshold profile
|
||||
// actDynamicThreshold processes the `ActionDiktatsOpts` field from the action to construct a Threshold profile
|
||||
//
|
||||
// The ActionValue field format is expected as follows:
|
||||
// The ActionDiktatsOpts field format is expected as follows:
|
||||
//
|
||||
// 0 Tenant: string
|
||||
// 1 ID: string
|
||||
@@ -91,7 +91,8 @@ func (aL *actDynamicThreshold) execute(ctx *context.Context, data utils.MapStora
|
||||
if len(aL.aCfg.Diktats) == 0 {
|
||||
return fmt.Errorf("No diktats were speified for action <%v>", aL.aCfg.ID)
|
||||
}
|
||||
params := strings.Split(aL.aCfg.Diktats[0].Value, utils.InfieldSep)
|
||||
params := strings.Split(utils.IfaceAsString(aL.aCfg.Diktats[0].Opts[utils.MetaTemplate]),
|
||||
utils.InfieldSep)
|
||||
if len(params) != 11 {
|
||||
return fmt.Errorf("invalid number of parameters <%d> expected 11", len(params))
|
||||
}
|
||||
@@ -181,9 +182,9 @@ func (aL *actDynamicThreshold) execute(ctx *context.Context, data utils.MapStora
|
||||
utils.AdminSv1SetThresholdProfile, args, &rply)
|
||||
}
|
||||
|
||||
// actDynamicStats processes the `ActionValue` field from the action to construct a StatQueueProfile
|
||||
// actDynamicStats processes the `ActionDiktatsOpts` field from the action to construct a StatQueueProfile
|
||||
//
|
||||
// The ActionValue field format is expected as follows:
|
||||
// The ActionDiktatsOpts field format is expected as follows:
|
||||
//
|
||||
// 0 Tenant: string
|
||||
// 1 ID: string
|
||||
@@ -229,7 +230,8 @@ func (aL *actDynamicStats) execute(ctx *context.Context, data utils.MapStorage,
|
||||
if len(aL.aCfg.Diktats) == 0 {
|
||||
return fmt.Errorf("No diktats were speified for action <%v>", aL.aCfg.ID)
|
||||
}
|
||||
params := strings.Split(aL.aCfg.Diktats[0].Value, utils.InfieldSep)
|
||||
params := strings.Split(utils.IfaceAsString(aL.aCfg.Diktats[0].Opts[utils.MetaTemplate]),
|
||||
utils.InfieldSep)
|
||||
if len(params) != 14 {
|
||||
return fmt.Errorf("invalid number of parameters <%d> expected 14", len(params))
|
||||
}
|
||||
@@ -364,9 +366,9 @@ func (aL *actDynamicStats) execute(ctx *context.Context, data utils.MapStorage,
|
||||
utils.AdminSv1SetStatQueueProfile, args, &rply)
|
||||
}
|
||||
|
||||
// actDynamicAttribute processes the `ActionValue` field from the action to construct a AttributeProfile
|
||||
// actDynamicAttribute processes the `ActionDiktatsOpts` field from the action to construct a AttributeProfile
|
||||
//
|
||||
// The ActionValue field format is expected as follows:
|
||||
// The ActionDiktatsOpts field format is expected as follows:
|
||||
//
|
||||
// 0 Tenant: string
|
||||
// 1 ID: string
|
||||
@@ -409,7 +411,8 @@ func (aL *actDynamicAttribute) execute(ctx *context.Context, data utils.MapStora
|
||||
if len(aL.aCfg.Diktats) == 0 {
|
||||
return fmt.Errorf("No diktats were speified for action <%v>", aL.aCfg.ID)
|
||||
}
|
||||
params := strings.Split(aL.aCfg.Diktats[0].Value, utils.InfieldSep)
|
||||
params := strings.Split(utils.IfaceAsString(aL.aCfg.Diktats[0].Opts[utils.MetaTemplate]),
|
||||
utils.InfieldSep)
|
||||
if len(params) != 11 {
|
||||
return fmt.Errorf("invalid number of parameters <%d> expected 11", len(params))
|
||||
}
|
||||
@@ -509,9 +512,9 @@ func (aL *actDynamicAttribute) execute(ctx *context.Context, data utils.MapStora
|
||||
utils.AdminSv1SetAttributeProfile, args, &rply)
|
||||
}
|
||||
|
||||
// actDynamicResource processes the `ActionValue` field from the action to construct a ResourceProfile
|
||||
// actDynamicResource processes the `ActionDiktatsOpts` field from the action to construct a ResourceProfile
|
||||
//
|
||||
// The ActionValue field format is expected as follows:
|
||||
// The ActionDiktatsOpts field format is expected as follows:
|
||||
//
|
||||
// 0 Tenant: string
|
||||
// 1 ID: string
|
||||
@@ -554,7 +557,8 @@ func (aL *actDynamicResource) execute(ctx *context.Context, data utils.MapStorag
|
||||
if len(aL.aCfg.Diktats) == 0 {
|
||||
return fmt.Errorf("No diktats were speified for action <%v>", aL.aCfg.ID)
|
||||
}
|
||||
params := strings.Split(aL.aCfg.Diktats[0].Value, utils.InfieldSep)
|
||||
params := strings.Split(utils.IfaceAsString(aL.aCfg.Diktats[0].Opts[utils.MetaTemplate]),
|
||||
utils.InfieldSep)
|
||||
if len(params) != 11 {
|
||||
return fmt.Errorf("invalid number of parameters <%d> expected 11", len(params))
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ func newActHTTPPost(ctx *context.Context, tnt string, cgrEv *utils.CGREvent,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
eeCfg := config.NewEventExporterCfg(aL.id(), "", actD.Path, cfg.EEsCfg().ExporterCfg(utils.MetaDefault).FailedPostsDir,
|
||||
eeCfg := config.NewEventExporterCfg(aL.id(), utils.EmptyString,
|
||||
utils.IfaceAsString(actD.Opts[utils.MetaURL]),
|
||||
cfg.EEsCfg().ExporterCfg(utils.MetaDefault).FailedPostsDir,
|
||||
attempts, nil)
|
||||
aL.pstrs[i], _ = ees.NewHTTPjsonMapEE(eeCfg, cfg, nil, nil)
|
||||
}
|
||||
|
||||
@@ -120,6 +120,14 @@ func (admS *AdminS) V1SetActionProfile(ctx *context.Context, ap *utils.ActionPro
|
||||
if missing := utils.MissingStructFields(ap.ActionProfile, []string{utils.ID, utils.Actions}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
for i := range ap.ActionProfile.Actions {
|
||||
for j := range ap.ActionProfile.Actions[i].Diktats { // if there are diktats, make sure their ID exists
|
||||
if missing := utils.MissingStructFields(ap.ActionProfile.Actions[i].
|
||||
Diktats[j], []string{utils.ID}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ap.Tenant == utils.EmptyString {
|
||||
ap.Tenant = admS.cfg.GeneralCfg().DefaultTenant
|
||||
}
|
||||
|
||||
@@ -121,6 +121,17 @@ func (admS *AdminSv1) SetActionProfile(ctx *context.Context, ap *utils.ActionPro
|
||||
if missing := utils.MissingStructFields(ap.ActionProfile, []string{utils.ID, utils.Actions}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
for i := range ap.ActionProfile.Actions {
|
||||
if ap.ActionProfile.Actions[i] == nil {
|
||||
continue
|
||||
}
|
||||
for j := range ap.ActionProfile.Actions[i].Diktats { // if there are diktats, make sure their ID exists
|
||||
if missing := utils.MissingStructFields(ap.ActionProfile.Actions[i].
|
||||
Diktats[j], []string{utils.ID}); len(missing) != 0 {
|
||||
return utils.NewErrMandatoryIeMissing(missing...)
|
||||
}
|
||||
}
|
||||
}
|
||||
if ap.Tenant == utils.EmptyString {
|
||||
ap.Tenant = admS.cfg.GeneralCfg().DefaultTenant
|
||||
}
|
||||
|
||||
@@ -1646,8 +1646,13 @@ const CGRATES_CFG_JSON = `
|
||||
{"tag": "ActionTTL", "path": "Actions[<~*req.8>].TTL", "type": "*variable", "value": "~*req.10", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionType", "path": "Actions[<~*req.8>].Type", "type": "*variable", "value": "~*req.11", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionOpts", "path": "Actions[<~*req.8>].Opts", "type": "*variable", "value": "~*req.12", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionPath", "path": "Actions[<~*req.8>].Diktats.Path", "type": "*variable", "value": "~*req.13","new_branch":true, "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionValue", "path": "Actions[<~*req.8>].Diktats.Value", "type": "*variable", "value": "~*req.14", "filters": ["*notempty:~*req.8:"]}
|
||||
{"tag": "ActionWeights", "path": "Actions[<~*req.8>].Weights", "type": "*variable", "value": "~*req.13", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionBlockers", "path": "Actions[<~*req.8>].Blockers", "type": "*variable", "value": "~*req.14", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionDiktatsID", "path": "Actions[<~*req.8>].Diktats.ID", "type": "*variable", "value": "~*req.15","new_branch":true, "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionDiktatsFilterIDs", "path": "Actions[<~*req.8>].Diktats.FilterIDs", "type": "*variable", "value": "~*req.16", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionDiktatsOpts", "path": "Actions[<~*req.8>].Diktats.Opts", "type": "*variable", "value": "~*req.17", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionDiktatsWeights", "path": "Actions[<~*req.8>].Diktats.Weights", "type": "*variable", "value": "~*req.18", "filters": ["*notempty:~*req.8:"]},
|
||||
{"tag": "ActionDiktatsBlockers", "path": "Actions[<~*req.8>].Diktats.Blockers", "type": "*variable", "value": "~*req.19", "filters": ["*notempty:~*req.8:"]},
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2024,7 +2024,9 @@ func (apm ActionProfileMdls) CSVHeader() (result []string) {
|
||||
return []string{"#" + utils.Tenant, utils.ID, utils.FilterIDs,
|
||||
utils.Weights, utils.Blockers, utils.Schedule, utils.TargetType, utils.TargetIDs,
|
||||
utils.ActionID, utils.ActionFilterIDs, utils.ActionTTL,
|
||||
utils.ActionType, utils.ActionOpts, utils.ActionPath, utils.ActionValue,
|
||||
utils.ActionType, utils.ActionOpts, utils.ActionWeights, utils.ActionBlockers,
|
||||
utils.ActionDiktatsID, utils.ActionDiktatsFilterIDs, utils.ActionDiktatsOpts,
|
||||
utils.ActionDiktatsWeights, utils.ActionDiktatsBlockers,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2074,19 +2076,45 @@ func (apm ActionProfileMdls) AsTPActionProfile() (result []*utils.TPActionProfil
|
||||
Type: tp.ActionType,
|
||||
Opts: tp.ActionOpts,
|
||||
Diktats: []*utils.TPAPDiktat{{
|
||||
Path: tp.ActionPath,
|
||||
Value: tp.ActionValue,
|
||||
ID: tp.ActionDiktatsID,
|
||||
Opts: tp.ActionDiktatsOpts,
|
||||
}},
|
||||
}
|
||||
if tp.ActionFilterIDs != utils.EmptyString {
|
||||
tpAAction.FilterIDs = utils.NewStringSet(strings.Split(tp.ActionFilterIDs, utils.InfieldSep)).AsSlice()
|
||||
}
|
||||
if tp.ActionWeights != utils.EmptyString {
|
||||
tpAAction.Weights = tp.ActionWeights
|
||||
}
|
||||
if tp.ActionBlockers != utils.EmptyString {
|
||||
tpAAction.Blockers = tp.ActionBlockers
|
||||
}
|
||||
if tp.ActionDiktatsFilterIDs != utils.EmptyString {
|
||||
tpAAction.Diktats[0].FilterIDs = utils.NewStringSet(strings.Split(tp.ActionDiktatsFilterIDs, utils.InfieldSep)).AsSlice()
|
||||
}
|
||||
if tp.ActionDiktatsWeights != utils.EmptyString {
|
||||
tpAAction.Diktats[0].Weights = tp.ActionDiktatsWeights
|
||||
}
|
||||
if tp.ActionDiktatsBlockers != utils.EmptyString {
|
||||
tpAAction.Diktats[0].Blockers = tp.ActionDiktatsBlockers
|
||||
}
|
||||
aPrf.Actions = append(aPrf.Actions, tpAAction)
|
||||
} else {
|
||||
aPrf.Actions[lacts-1].Diktats = append(aPrf.Actions[lacts-1].Diktats, &utils.TPAPDiktat{
|
||||
Path: tp.ActionPath,
|
||||
Value: tp.ActionValue,
|
||||
})
|
||||
diktat := &utils.TPAPDiktat{
|
||||
ID: tp.ActionDiktatsID,
|
||||
Opts: tp.ActionDiktatsOpts,
|
||||
}
|
||||
if tp.ActionDiktatsFilterIDs != utils.EmptyString {
|
||||
diktat.FilterIDs = utils.NewStringSet(strings.Split(tp.ActionDiktatsFilterIDs, utils.InfieldSep)).AsSlice()
|
||||
}
|
||||
if tp.ActionDiktatsWeights != utils.EmptyString {
|
||||
diktat.Weights = tp.ActionDiktatsWeights
|
||||
}
|
||||
if tp.ActionDiktatsBlockers != utils.EmptyString {
|
||||
diktat.Blockers = tp.ActionDiktatsBlockers
|
||||
}
|
||||
aPrf.Actions[lacts-1].Diktats = append(aPrf.Actions[lacts-1].Diktats,
|
||||
diktat)
|
||||
}
|
||||
}
|
||||
actPrfMap[tenID] = aPrf
|
||||
@@ -2129,6 +2157,8 @@ func APItoModelTPActionProfile(tPrf *utils.TPActionProfile) (mdls ActionProfileM
|
||||
mdl.ActionTTL = action.TTL
|
||||
mdl.ActionType = action.Type
|
||||
mdl.ActionOpts = action.Opts
|
||||
mdl.ActionWeights = action.Weights
|
||||
mdl.ActionBlockers = action.Blockers
|
||||
for j, actD := range action.Diktats {
|
||||
if j != 0 {
|
||||
mdl = &ActionProfileMdl{
|
||||
@@ -2139,8 +2169,11 @@ func APItoModelTPActionProfile(tPrf *utils.TPActionProfile) (mdls ActionProfileM
|
||||
ActionType: mdl.ActionType,
|
||||
}
|
||||
}
|
||||
mdl.ActionPath = actD.Path
|
||||
mdl.ActionValue = actD.Value
|
||||
mdl.ActionDiktatsID = actD.ID
|
||||
mdl.ActionDiktatsFilterIDs = strings.Join(actD.FilterIDs, utils.InfieldSep)
|
||||
mdl.ActionDiktatsOpts = actD.Opts
|
||||
mdl.ActionDiktatsWeights = actD.Weights
|
||||
mdl.ActionDiktatsBlockers = actD.Blockers
|
||||
}
|
||||
mdls = append(mdls, mdl)
|
||||
}
|
||||
@@ -2173,9 +2206,33 @@ func APItoActionProfile(tpAp *utils.TPActionProfile, timezone string) (ap *utils
|
||||
for i, act := range tpAp.Actions {
|
||||
actDs := make([]*utils.APDiktat, len(act.Diktats))
|
||||
for j, actD := range act.Diktats {
|
||||
if actD.ID == utils.EmptyString {
|
||||
return nil, fmt.Errorf("missing ID from Diktats of ActionProfile <%s> Action <%s>", ap.TenantID(), actD.ID)
|
||||
}
|
||||
actDs[j] = &utils.APDiktat{
|
||||
Path: actD.Path,
|
||||
Value: actD.Value,
|
||||
ID: actD.ID,
|
||||
FilterIDs: actD.FilterIDs,
|
||||
}
|
||||
if actD.Opts != utils.EmptyString {
|
||||
actDs[j].Opts = make(map[string]any)
|
||||
for opt := range strings.SplitSeq(actD.Opts, utils.InfieldSep) { // example of opts: key1:val1;key2:val2;key3:val3
|
||||
keyValSls := utils.SplitPath(opt, utils.InInFieldSep[0], 2)
|
||||
if len(keyValSls) != 2 {
|
||||
return nil, fmt.Errorf("malformed option for ActionProfile <%s> for action <%s> for diktat <%s>", ap.TenantID(), actD.ID, actD.ID)
|
||||
|
||||
}
|
||||
actDs[j].Opts[keyValSls[0]] = keyValSls[1]
|
||||
}
|
||||
}
|
||||
if actD.Weights != utils.EmptyString {
|
||||
if actDs[j].Weights, err = utils.NewDynamicWeightsFromString(actD.Weights, utils.InfieldSep, utils.ANDSep); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if actD.Blockers != utils.EmptyString {
|
||||
if actDs[j].Blockers, err = utils.NewDynamicBlockersFromString(actD.Blockers, utils.InfieldSep, utils.ANDSep); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
ap.Actions[i] = &utils.APAction{
|
||||
@@ -2189,8 +2246,8 @@ func APItoActionProfile(tpAp *utils.TPActionProfile, timezone string) (ap *utils
|
||||
}
|
||||
if act.Opts != utils.EmptyString {
|
||||
ap.Actions[i].Opts = make(map[string]any)
|
||||
for _, opt := range strings.Split(act.Opts, utils.InfieldSep) { // example of opts: key1:val1;key2:val2;key3:val3
|
||||
keyValSls := utils.SplitConcatenatedKey(opt)
|
||||
for opt := range strings.SplitSeq(act.Opts, utils.InfieldSep) { // example of opts: key1:val1;key2:val2;key3:val3
|
||||
keyValSls := utils.SplitPath(opt, utils.InInFieldSep[0], 2)
|
||||
if len(keyValSls) != 2 {
|
||||
err = fmt.Errorf("malformed option for ActionProfile <%s> for action <%s>", ap.TenantID(), act.ID)
|
||||
return
|
||||
@@ -2198,7 +2255,16 @@ func APItoActionProfile(tpAp *utils.TPActionProfile, timezone string) (ap *utils
|
||||
ap.Actions[i].Opts[keyValSls[0]] = keyValSls[1]
|
||||
}
|
||||
}
|
||||
|
||||
if act.Weights != utils.EmptyString {
|
||||
if ap.Actions[i].Weights, err = utils.NewDynamicWeightsFromString(act.Weights, utils.InfieldSep, utils.ANDSep); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
if act.Blockers != utils.EmptyString {
|
||||
if ap.Actions[i].Blockers, err = utils.NewDynamicBlockersFromString(act.Blockers, utils.InfieldSep, utils.ANDSep); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -2221,9 +2287,16 @@ func ActionProfileToAPI(ap *utils.ActionProfile) (tpAp *utils.TPActionProfile) {
|
||||
for i, act := range ap.Actions {
|
||||
actDs := make([]*utils.TPAPDiktat, len(act.Diktats))
|
||||
for j, actD := range act.Diktats {
|
||||
elems := make([]string, 0, len(actD.Opts))
|
||||
for k, v := range actD.Opts {
|
||||
elems = append(elems, utils.ConcatenatedKey(k, utils.IfaceAsString(v)))
|
||||
}
|
||||
actDs[j] = &utils.TPAPDiktat{
|
||||
Path: actD.Path,
|
||||
Value: actD.Value,
|
||||
ID: actD.ID,
|
||||
FilterIDs: actD.FilterIDs,
|
||||
Opts: strings.Join(elems, utils.InfieldSep),
|
||||
Weights: actD.Weights.String(utils.InfieldSep, utils.ANDSep),
|
||||
Blockers: actD.Blockers.String(utils.InfieldSep, utils.ANDSep),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2236,8 +2309,10 @@ func ActionProfileToAPI(ap *utils.ActionProfile) (tpAp *utils.TPActionProfile) {
|
||||
FilterIDs: act.FilterIDs,
|
||||
TTL: act.TTL.String(),
|
||||
Type: act.Type,
|
||||
Diktats: actDs,
|
||||
Opts: strings.Join(elems, utils.InfieldSep),
|
||||
Weights: act.Weights.String(utils.InfieldSep, utils.ANDSep),
|
||||
Blockers: act.Blockers.String(utils.InfieldSep, utils.ANDSep),
|
||||
Diktats: actDs,
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
@@ -325,23 +325,28 @@ func (RateProfileMdl) TableName() string {
|
||||
}
|
||||
|
||||
type ActionProfileMdl struct {
|
||||
PK uint `gorm:"primary_key"`
|
||||
Tpid string
|
||||
Tenant string `index:"0" re:".*"`
|
||||
ID string `index:"1" re:".*"`
|
||||
FilterIDs string `index:"2" re:".*"`
|
||||
Weights string `index:"3" re:".*"`
|
||||
Blockers string `index:"4" re:".*"`
|
||||
Schedule string `index:"5" re:".*"`
|
||||
TargetType string `index:"6" re:".*"`
|
||||
TargetIDs string `index:"7" re:".*"`
|
||||
ActionID string `index:"8" re:".*"`
|
||||
ActionFilterIDs string `index:"9" re:".*"`
|
||||
ActionTTL string `index:"10" re:".*"`
|
||||
ActionType string `index:"11" re:".*"`
|
||||
ActionOpts string `index:"12" re:".*"`
|
||||
ActionPath string `index:"13" re:".*"`
|
||||
ActionValue string `index:"14" re:".*"`
|
||||
PK uint `gorm:"primary_key"`
|
||||
Tpid string
|
||||
Tenant string `index:"0" re:".*"`
|
||||
ID string `index:"1" re:".*"`
|
||||
FilterIDs string `index:"2" re:".*"`
|
||||
Weights string `index:"3" re:".*"`
|
||||
Blockers string `index:"4" re:".*"`
|
||||
Schedule string `index:"5" re:".*"`
|
||||
TargetType string `index:"6" re:".*"`
|
||||
TargetIDs string `index:"7" re:".*"`
|
||||
ActionID string `index:"8" re:".*"`
|
||||
ActionFilterIDs string `index:"9" re:".*"`
|
||||
ActionTTL string `index:"10" re:".*"`
|
||||
ActionType string `index:"11" re:".*"`
|
||||
ActionOpts string `index:"12" re:".*"`
|
||||
ActionWeights string `index:"13" re:".*"`
|
||||
ActionBlockers string `index:"14" re:".*"`
|
||||
ActionDiktatsID string `index:"15" re:".*"`
|
||||
ActionDiktatsFilterIDs string `index:"16" re:".*"`
|
||||
ActionDiktatsOpts string `index:"17" re:".*"`
|
||||
ActionDiktatsWeights string `index:"18" re:".*"`
|
||||
ActionDiktatsBlockers string `index:"19" re:".*"`
|
||||
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
@@ -45,7 +45,12 @@ func (tpActs TPActions) exportItems(ctx *context.Context, wrtr io.Writer, tnt st
|
||||
csvWriter := csv.NewWriter(wrtr)
|
||||
csvWriter.Comma = utils.CSVSep
|
||||
// before writing the profiles, we must write the headers
|
||||
if err = csvWriter.Write([]string{"#Tenant", "ID", "FilterIDs", "Weights", "Blockers", "Schedule", "TargetType", "TargetIDs", "ActionID", "ActionFilterIDs", "ActionTTL", "ActionType", "ActionOpts", "ActionPath", "ActionValue"}); err != nil {
|
||||
if err = csvWriter.Write([]string{"#" + utils.Tenant, utils.ID, utils.FilterIDs,
|
||||
utils.Weights, utils.Blockers, utils.Schedule, utils.TargetType, utils.TargetIDs,
|
||||
utils.ActionID, utils.ActionFilterIDs, utils.ActionTTL,
|
||||
utils.ActionType, utils.ActionOpts, utils.ActionWeights, utils.ActionBlockers,
|
||||
utils.ActionDiktatsID, utils.ActionDiktatsFilterIDs, utils.ActionDiktatsOpts,
|
||||
utils.ActionDiktatsWeights, utils.ActionDiktatsBlockers}); err != nil {
|
||||
return
|
||||
}
|
||||
for _, actsID := range itmIDs {
|
||||
|
||||
187
utils/actions.go
187
utils/actions.go
@@ -20,6 +20,7 @@ package utils
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -297,6 +298,8 @@ type APAction struct {
|
||||
TTL time.Duration // Cancel Action if not executed within TTL
|
||||
Type string // Type of Action
|
||||
Opts map[string]any // Extra options to pass depending on action type
|
||||
Weights DynamicWeights
|
||||
Blockers DynamicBlockers
|
||||
Diktats []*APDiktat
|
||||
}
|
||||
|
||||
@@ -318,6 +321,12 @@ func (a *APAction) Clone() *APAction {
|
||||
cloned.Opts = make(map[string]any, len(a.Opts))
|
||||
maps.Copy(cloned.Opts, a.Opts)
|
||||
}
|
||||
if a.Weights != nil {
|
||||
cloned.Weights = a.Weights.Clone()
|
||||
}
|
||||
if a.Blockers != nil {
|
||||
cloned.Blockers = a.Blockers.Clone()
|
||||
}
|
||||
if a.Diktats != nil {
|
||||
cloned.Diktats = make([]*APDiktat, len(a.Diktats))
|
||||
for i, diktat := range a.Diktats {
|
||||
@@ -336,6 +345,12 @@ func (a *APAction) Set(path []string, val any, newBranch bool) (err error) {
|
||||
if path[0] == Opts {
|
||||
return MapStorage(a.Opts).Set(path[1:], val)
|
||||
}
|
||||
if path[0] == Diktats && path[1] == Opts {
|
||||
if len(a.Diktats) == 0 || newBranch {
|
||||
a.Diktats = append(a.Diktats, new(APDiktat))
|
||||
}
|
||||
return MapStorage(a.Diktats[len(a.Diktats)-1].Opts).Set(path[2:], val)
|
||||
}
|
||||
return ErrWrongPath
|
||||
case 0:
|
||||
return ErrWrongPath
|
||||
@@ -360,6 +375,14 @@ func (a *APAction) Set(path []string, val any, newBranch bool) (err error) {
|
||||
a.TTL, err = IfaceAsDuration(val)
|
||||
case Opts:
|
||||
a.Opts, err = NewMapFromCSV(IfaceAsString(val))
|
||||
case Weights:
|
||||
if val != EmptyString {
|
||||
a.Weights, err = NewDynamicWeightsFromString(IfaceAsString(val), InfieldSep, ANDSep)
|
||||
}
|
||||
case Blockers:
|
||||
if val != EmptyString {
|
||||
a.Blockers, err = NewDynamicBlockersFromString(IfaceAsString(val), InfieldSep, ANDSep)
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
switch path[0] {
|
||||
@@ -372,10 +395,34 @@ func (a *APAction) Set(path []string, val any, newBranch bool) (err error) {
|
||||
a.Diktats = append(a.Diktats, new(APDiktat))
|
||||
}
|
||||
switch path[1] {
|
||||
case Path:
|
||||
a.Diktats[len(a.Diktats)-1].Path = IfaceAsString(val)
|
||||
case Value:
|
||||
a.Diktats[len(a.Diktats)-1].Value = IfaceAsString(val)
|
||||
default:
|
||||
if strings.HasPrefix(path[1], Opts) &&
|
||||
path[1][4] == '[' && path[1][len(path[1])-1] == ']' {
|
||||
a.Opts[path[1][5:len(path[1])-1]] = val
|
||||
return
|
||||
}
|
||||
return ErrWrongPath
|
||||
case ID:
|
||||
if dID := IfaceAsString(val); dID == EmptyString {
|
||||
return ErrWrongPath
|
||||
} else {
|
||||
a.Diktats[len(a.Diktats)-1].ID = dID
|
||||
}
|
||||
case FilterIDs:
|
||||
var valA []string
|
||||
valA, err = IfaceAsStringSlice(val)
|
||||
a.Diktats[len(a.Diktats)-1].FilterIDs = append(a.Diktats[len(a.Diktats)-1].
|
||||
FilterIDs, valA...)
|
||||
case Opts:
|
||||
a.Diktats[len(a.Diktats)-1].Opts, err = NewMapFromCSV(IfaceAsString(val))
|
||||
case Weights:
|
||||
if val != EmptyString {
|
||||
a.Diktats[len(a.Diktats)-1].Weights, err = NewDynamicWeightsFromString(IfaceAsString(val), InfieldSep, ANDSep)
|
||||
}
|
||||
case Blockers:
|
||||
if val != EmptyString {
|
||||
a.Diktats[len(a.Diktats)-1].Blockers, err = NewDynamicBlockersFromString(IfaceAsString(val), InfieldSep, ANDSep)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -387,23 +434,31 @@ func (a *APAction) Merge(v2 *APAction) {
|
||||
if len(v2.ID) != 0 {
|
||||
a.ID = v2.ID
|
||||
}
|
||||
a.FilterIDs = append(a.FilterIDs, v2.FilterIDs...)
|
||||
if v2.TTL != 0 {
|
||||
a.TTL = v2.TTL
|
||||
}
|
||||
if len(v2.Type) != 0 {
|
||||
a.Type = v2.Type
|
||||
}
|
||||
for key, value := range v2.Opts {
|
||||
a.Opts[key] = value
|
||||
maps.Copy(a.Opts, v2.Opts)
|
||||
if v2.Blockers != nil {
|
||||
a.Blockers = append(a.Blockers, v2.Blockers...)
|
||||
}
|
||||
a.FilterIDs = append(a.FilterIDs, v2.FilterIDs...)
|
||||
if len(a.Diktats) == 1 && a.Diktats[0].Path == EmptyString {
|
||||
if v2.Weights != nil {
|
||||
a.Weights = append(a.Weights, v2.Weights...)
|
||||
}
|
||||
if len(a.Diktats) == 1 && len(a.Diktats[0].Opts) == 0 {
|
||||
a.Diktats = a.Diktats[:0]
|
||||
}
|
||||
for _, diktat := range v2.Diktats {
|
||||
if diktat.Path != EmptyString {
|
||||
a.Diktats = append(a.Diktats, diktat)
|
||||
for _, diktatV2 := range v2.Diktats {
|
||||
if idx := slices.IndexFunc(a.Diktats, func(a *APDiktat) bool {
|
||||
return a.ID == diktatV2.ID
|
||||
}); idx != -1 {
|
||||
a.Diktats[idx].Merge(diktatV2)
|
||||
continue
|
||||
}
|
||||
a.Diktats = append(a.Diktats, diktatV2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,19 +527,20 @@ func (a *APAction) FieldAsInterface(fldPath []string) (_ any, err error) {
|
||||
return a.Type, nil
|
||||
case Opts:
|
||||
return a.Opts, nil
|
||||
case Weights:
|
||||
return a.Weights, nil
|
||||
case Blockers:
|
||||
return a.Blockers, nil
|
||||
}
|
||||
case 2:
|
||||
fld, idxStr := GetPathIndexString(fldPath[0])
|
||||
switch fld {
|
||||
default:
|
||||
if fld, _ := GetPathIndexString(fldPath[0]); fld != Opts {
|
||||
return nil, ErrNotFound
|
||||
case Opts:
|
||||
path := fldPath[1:]
|
||||
if idxStr != nil {
|
||||
path = append([]string{*idxStr}, path...)
|
||||
}
|
||||
return MapStorage(a.Opts).FieldAsInterface(path)
|
||||
case Diktats:
|
||||
}
|
||||
return MapStorage(a.Opts).FieldAsInterface(fldPath[1:])
|
||||
case 3:
|
||||
if fld, idxStr := GetPathIndexString(fldPath[0]); fld != Diktats {
|
||||
return nil, ErrNotFound
|
||||
} else {
|
||||
if idxStr == nil {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
@@ -502,8 +558,11 @@ func (a *APAction) FieldAsInterface(fldPath []string) (_ any, err error) {
|
||||
|
||||
// APDiktat defines a path and value operation to be executed by an action.
|
||||
type APDiktat struct {
|
||||
Path string // Path to execute
|
||||
Value string // Value to execute on Path
|
||||
ID string // Diktat ID
|
||||
FilterIDs []string // Diktat FilterIDs
|
||||
Opts map[string]any // Diktat options to pass
|
||||
Weights DynamicWeights
|
||||
Blockers DynamicBlockers
|
||||
|
||||
valRSR RSRParsers
|
||||
}
|
||||
@@ -514,8 +573,21 @@ func (d *APDiktat) Clone() *APDiktat {
|
||||
return nil
|
||||
}
|
||||
cloned := &APDiktat{
|
||||
Path: d.Path,
|
||||
Value: d.Value,
|
||||
ID: d.ID,
|
||||
}
|
||||
if d.FilterIDs != nil {
|
||||
cloned.FilterIDs = make([]string, len(d.FilterIDs))
|
||||
copy(cloned.FilterIDs, d.FilterIDs)
|
||||
}
|
||||
if d.Opts != nil {
|
||||
cloned.Opts = make(map[string]any, len(d.Opts))
|
||||
maps.Copy(cloned.Opts, d.Opts)
|
||||
}
|
||||
if d.Weights != nil {
|
||||
cloned.Weights = d.Weights.Clone()
|
||||
}
|
||||
if d.Blockers != nil {
|
||||
cloned.Blockers = d.Blockers.Clone()
|
||||
}
|
||||
if d.valRSR != nil {
|
||||
cloned.valRSR = d.valRSR.Clone()
|
||||
@@ -523,10 +595,20 @@ func (d *APDiktat) Clone() *APDiktat {
|
||||
return cloned
|
||||
}
|
||||
|
||||
// Merge combines the values from another APDiktat into this one.
|
||||
func (a *APDiktat) Merge(v2 *APDiktat) {
|
||||
a.FilterIDs = append(a.FilterIDs, v2.FilterIDs...)
|
||||
maps.Copy(a.Opts, v2.Opts)
|
||||
a.Blockers = append(a.Blockers, v2.Blockers...)
|
||||
a.Weights = append(a.Weights, v2.Weights...)
|
||||
}
|
||||
|
||||
// RSRValues returns the Value as RSRParsers or creates new ones if not initialized.
|
||||
func (dk *APDiktat) RSRValues() (RSRParsers, error) {
|
||||
if dk.valRSR == nil {
|
||||
return NewRSRParsers(dk.Value, RSRSep)
|
||||
if _, has := dk.Opts[MetaBalanceValue]; has {
|
||||
return NewRSRParsers(IfaceAsString(dk.Opts[MetaBalanceValue]), RSRSep)
|
||||
}
|
||||
}
|
||||
return dk.valRSR, nil
|
||||
}
|
||||
@@ -545,15 +627,52 @@ func (dk *APDiktat) FieldAsString(fldPath []string) (_ string, err error) {
|
||||
|
||||
// FieldAsInterface implements the DataProvider interface, retrieving field value as interface.
|
||||
func (dk *APDiktat) FieldAsInterface(fldPath []string) (_ any, err error) {
|
||||
if len(fldPath) != 1 {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
switch fldPath[0] {
|
||||
switch len(fldPath) {
|
||||
default:
|
||||
if fld, idxStr := GetPathIndexString(fldPath[0]); fld == Opts {
|
||||
path := fldPath[1:]
|
||||
if idxStr != nil {
|
||||
path = append([]string{*idxStr}, path...)
|
||||
}
|
||||
return MapStorage(dk.Opts).FieldAsInterface(path)
|
||||
}
|
||||
fallthrough
|
||||
case 0:
|
||||
return nil, ErrNotFound
|
||||
case Path:
|
||||
return dk.Path, nil
|
||||
case Value:
|
||||
return dk.Value, nil
|
||||
case 1:
|
||||
switch fldPath[0] {
|
||||
default:
|
||||
fld, idxStr := GetPathIndexString(fldPath[0])
|
||||
if idxStr != nil {
|
||||
switch fld {
|
||||
case FilterIDs:
|
||||
var idx int
|
||||
if idx, err = strconv.Atoi(*idxStr); err != nil {
|
||||
return
|
||||
}
|
||||
if idx < len(dk.FilterIDs) {
|
||||
return dk.FilterIDs[idx], nil
|
||||
}
|
||||
case Opts:
|
||||
return MapStorage(dk.Opts).FieldAsInterface([]string{*idxStr})
|
||||
}
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
case ID:
|
||||
return dk.ID, nil
|
||||
case FilterIDs:
|
||||
return dk.FilterIDs, nil
|
||||
case Opts:
|
||||
return dk.Opts, nil
|
||||
case Weights:
|
||||
return dk.Weights, nil
|
||||
case Blockers:
|
||||
return dk.Blockers, nil
|
||||
}
|
||||
case 2:
|
||||
if fld, _ := GetPathIndexString(fldPath[0]); fld != Opts {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return MapStorage(dk.Opts).FieldAsInterface(fldPath[1:])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,12 +687,17 @@ type TPAPAction struct {
|
||||
TTL string
|
||||
Type string
|
||||
Opts string
|
||||
Weights string
|
||||
Blockers string
|
||||
Diktats []*TPAPDiktat
|
||||
}
|
||||
|
||||
type TPAPDiktat struct {
|
||||
Path string
|
||||
Value string
|
||||
ID string
|
||||
FilterIDs []string
|
||||
Opts string
|
||||
Weights string
|
||||
Blockers string
|
||||
}
|
||||
|
||||
type TPAccount struct {
|
||||
|
||||
@@ -834,7 +834,13 @@ const (
|
||||
ActionFilterIDs = "ActionFilterIDs"
|
||||
ActionTTL = "ActionTTL"
|
||||
ActionOpts = "ActionOpts"
|
||||
ActionPath = "ActionPath"
|
||||
ActionWeights = "ActionWeights"
|
||||
ActionBlockers = "ActionBlockers"
|
||||
ActionDiktatsID = "ActionDiktatsID"
|
||||
ActionDiktatsFilterIDs = "ActionDiktatsFilterIDs"
|
||||
ActionDiktatsOpts = "ActionDiktatsOpts"
|
||||
ActionDiktatsWeights = "ActionDiktatsWeights"
|
||||
ActionDiktatsBlockers = "ActionDiktatsBlockers"
|
||||
TPid = "TPid"
|
||||
LoadId = "LoadId"
|
||||
ActionPlanId = "ActionPlanId"
|
||||
@@ -1131,7 +1137,6 @@ const (
|
||||
MetaRemoteSetAccount = "*remote_set_account"
|
||||
ActionID = "ActionID"
|
||||
ActionType = "ActionType"
|
||||
ActionValue = "ActionValue"
|
||||
BalanceValue = "BalanceValue"
|
||||
BalanceUnits = "BalanceUnits"
|
||||
BalanceUnitFactors = "BalanceUnitFactors"
|
||||
@@ -1145,6 +1150,11 @@ const (
|
||||
MetaDynamicStats = "*dynamic_stats"
|
||||
MetaDynamicAttribute = "*dynamic_attribute"
|
||||
MetaDynamicResource = "*dynamic_resource"
|
||||
|
||||
// Diktats Opts Fields
|
||||
MetaBalancePath = "*balancePath"
|
||||
MetaBalanceValue = "*balanceValue"
|
||||
MetaURL = "*url"
|
||||
)
|
||||
|
||||
// Migrator Metas
|
||||
|
||||
Reference in New Issue
Block a user