zitadel/internal/command/action_v2_execution.go

356 lines
10 KiB
Go
Raw Normal View History

package command
import (
"context"
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
"strings"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore/v1/models"
"github.com/zitadel/zitadel/internal/repository/execution"
"github.com/zitadel/zitadel/internal/zerrors"
)
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
const (
EventGroupSuffix = ".*"
)
type ExecutionAPICondition struct {
Method string
Service string
All bool
}
func (e *ExecutionAPICondition) IsValid() error {
if e.Method == "" && e.Service == "" && !e.All {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-3tkej630e6", "Errors.Execution.Invalid")
}
// never set two conditions
if e.Method != "" && (e.Service != "" || e.All) ||
e.Service != "" && (e.Method != "" || e.All) ||
e.All && (e.Method != "" || e.Service != "") {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-nee5q8aszq", "Errors.Execution.Invalid")
}
return nil
}
func (e *ExecutionAPICondition) ID(executionType domain.ExecutionType) string {
if e.Method != "" {
return execution.ID(executionType, e.Method)
}
if e.Service != "" {
return execution.ID(executionType, e.Service)
}
if e.All {
return execution.IDAll(executionType)
}
return ""
}
func (e *ExecutionAPICondition) Existing(c *Commands) error {
if e.Method != "" && !c.GrpcMethodExisting(e.Method) {
return zerrors.ThrowNotFound(nil, "COMMAND-vysplsevt8", "Errors.Execution.ConditionInvalid")
}
if e.Service != "" && !c.GrpcServiceExisting(e.Service) {
return zerrors.ThrowNotFound(nil, "COMMAND-qu6dfhiioq", "Errors.Execution.ConditionInvalid")
}
return nil
}
func (c *Commands) SetExecutionRequest(ctx context.Context, cond *ExecutionAPICondition, set *SetExecution, resourceOwner string) (_ *domain.ObjectDetails, err error) {
if err := cond.IsValid(); err != nil {
return nil, err
}
for _, target := range set.Targets {
if err = target.Validate(); err != nil {
return nil, err
}
}
if err := cond.Existing(c); err != nil {
return nil, err
}
if set.AggregateID == "" {
set.AggregateID = cond.ID(domain.ExecutionTypeRequest)
}
return c.setExecution(ctx, set, resourceOwner)
}
func (c *Commands) SetExecutionResponse(ctx context.Context, cond *ExecutionAPICondition, set *SetExecution, resourceOwner string) (_ *domain.ObjectDetails, err error) {
if err := cond.IsValid(); err != nil {
return nil, err
}
for _, target := range set.Targets {
if err = target.Validate(); err != nil {
return nil, err
}
}
if err := cond.Existing(c); err != nil {
return nil, err
}
if set.AggregateID == "" {
set.AggregateID = cond.ID(domain.ExecutionTypeResponse)
}
return c.setExecution(ctx, set, resourceOwner)
}
type ExecutionFunctionCondition string
func (e ExecutionFunctionCondition) IsValid() error {
if e == "" {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-5folwn5jws", "Errors.Execution.Invalid")
}
return nil
}
func (e ExecutionFunctionCondition) ID() string {
return execution.ID(domain.ExecutionTypeFunction, string(e))
}
func (e ExecutionFunctionCondition) Existing(c *Commands) error {
if !c.ActionFunctionExisting(string(e)) {
return zerrors.ThrowNotFound(nil, "COMMAND-cdy39t0ksr", "Errors.Execution.ConditionInvalid")
}
return nil
}
func (c *Commands) SetExecutionFunction(ctx context.Context, cond ExecutionFunctionCondition, set *SetExecution, resourceOwner string) (_ *domain.ObjectDetails, err error) {
if err := cond.IsValid(); err != nil {
return nil, err
}
for _, target := range set.Targets {
if err = target.Validate(); err != nil {
return nil, err
}
}
if err := cond.Existing(c); err != nil {
return nil, err
}
for _, target := range set.Targets {
if err = target.Validate(); err != nil {
return nil, err
}
}
if set.AggregateID == "" {
set.AggregateID = cond.ID()
}
return c.setExecution(ctx, set, resourceOwner)
}
type ExecutionEventCondition struct {
Event string
Group string
All bool
}
func (e *ExecutionEventCondition) IsValid() error {
if e.Event == "" && e.Group == "" && !e.All {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-w5smb6v7qu", "Errors.Execution.Invalid")
}
// never set two conditions
if e.Event != "" && (e.Group != "" || e.All) ||
e.Group != "" && (e.Event != "" || e.All) ||
e.All && (e.Event != "" || e.Group != "") {
return zerrors.ThrowInvalidArgument(nil, "COMMAND-hdm4zl1hmd", "Errors.Execution.Invalid")
}
return nil
}
func (e *ExecutionEventCondition) ID() string {
if e.Event != "" {
return execution.ID(domain.ExecutionTypeEvent, e.Event)
}
if e.Group != "" {
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
group := e.Group
if !strings.HasSuffix(e.Group, EventGroupSuffix) {
group += EventGroupSuffix
}
return execution.ID(domain.ExecutionTypeEvent, group)
}
if e.All {
return execution.IDAll(domain.ExecutionTypeEvent)
}
return ""
}
func (e *ExecutionEventCondition) Existing(c *Commands) error {
if e.Event != "" && !c.EventExisting(e.Event) {
return zerrors.ThrowNotFound(nil, "COMMAND-74aaqj8fv9", "Errors.Execution.ConditionInvalid")
}
if e.Group != "" && !c.EventGroupExisting(e.Group) {
return zerrors.ThrowNotFound(nil, "COMMAND-er5oneb5lz", "Errors.Execution.ConditionInvalid")
}
return nil
}
func (c *Commands) SetExecutionEvent(ctx context.Context, cond *ExecutionEventCondition, set *SetExecution, resourceOwner string) (_ *domain.ObjectDetails, err error) {
if err := cond.IsValid(); err != nil {
return nil, err
}
for _, target := range set.Targets {
if err = target.Validate(); err != nil {
return nil, err
}
}
if err := cond.Existing(c); err != nil {
return nil, err
}
if set.AggregateID == "" {
set.AggregateID = cond.ID()
}
return c.setExecution(ctx, set, resourceOwner)
}
type SetExecution struct {
models.ObjectRoot
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
Targets []*execution.Target
}
func (t SetExecution) GetIncludes() []string {
includes := make([]string, 0)
for i := range t.Targets {
if t.Targets[i].Type == domain.ExecutionTargetTypeInclude {
includes = append(includes, t.Targets[i].Target)
}
}
return includes
}
func (t SetExecution) GetTargets() []string {
targets := make([]string, 0)
for i := range t.Targets {
if t.Targets[i].Type == domain.ExecutionTargetTypeTarget {
targets = append(targets, t.Targets[i].Target)
}
}
return targets
}
func (e *SetExecution) Existing(c *Commands, ctx context.Context, resourceOwner string) error {
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
targets := e.GetTargets()
if len(targets) > 0 && !c.existsTargetsByIDs(ctx, targets, resourceOwner) {
return zerrors.ThrowNotFound(nil, "COMMAND-17e8fq1ggk", "Errors.Target.NotFound")
}
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
includes := e.GetIncludes()
if len(includes) > 0 && !c.existsExecutionsByIDs(ctx, includes, resourceOwner) {
return zerrors.ThrowNotFound(nil, "COMMAND-slgj0l4cdz", "Errors.Execution.IncludeNotFound")
}
get, set := createIncludeCacheFunctions()
// maxLevels could be configurable, but set as 3 for now
return checkForIncludeCircular(ctx, e.AggregateID, resourceOwner, includes, c.getExecutionIncludes(get, set), 3)
}
func (c *Commands) setExecution(ctx context.Context, set *SetExecution, resourceOwner string) (_ *domain.ObjectDetails, err error) {
if resourceOwner == "" || set.AggregateID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-gg3a6ol4om", "Errors.IDMissing")
}
wm, err := c.getExecutionWriteModelByID(ctx, set.AggregateID, resourceOwner)
if err != nil {
return nil, err
}
// Check if targets and includes for execution are existing
if wm.ExecutionTargetsEqual(set.Targets) {
return writeModelToObjectDetails(&wm.WriteModel), err
}
if err := set.Existing(c, ctx, resourceOwner); err != nil {
return nil, err
}
feat: add action v2 execution on requests and responses (#7637) * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: add execution of targets to grpc calls * feat: split request and response logic to handle the different context information * feat: split request and response logic to handle the different context information * fix: integration test * fix: import alias * fix: refactor execution package * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * fix: refactor execution interceptor integration and unit tests * docs: basic documentation for executions and targets * fix: change order for interceptors * fix: merge back origin/main * fix: change target definition command and query side (#7735) * fix: change target definition command and query side * fix: correct refactoring name changes * fix: correct refactoring name changes * fix: changing execution defintion with target list and type * fix: changing execution definition with target list and type * fix: add back search queries for target and include * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * fix: projections change for execution with targets suffix table * docs: add example to actions v2 * docs: add example to actions v2 * fix: correct integration tests on query for executions * fix: add separate event for execution v2 as content changed * fix: add separate event for execution v2 as content changed * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * Update internal/api/grpc/server/middleware/execution_interceptor.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes * fix: added review comment changes --------- Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: Elio Bischof <elio@zitadel.com>
2024-05-04 09:55:57 +00:00
if err := c.pushAppendAndReduce(ctx, wm, execution.NewSetEventV2(
ctx,
ExecutionAggregateFromWriteModel(&wm.WriteModel),
set.Targets,
)); err != nil {
return nil, err
}
return writeModelToObjectDetails(&wm.WriteModel), nil
}
func (c *Commands) existsExecutionsByIDs(ctx context.Context, ids []string, resourceOwner string) bool {
wm := NewExecutionsExistWriteModel(ids, resourceOwner)
err := c.eventstore.FilterToQueryReducer(ctx, wm)
if err != nil {
return false
}
return wm.AllExists()
}
func (c *Commands) getExecutionWriteModelByID(ctx context.Context, id string, resourceOwner string) (*ExecutionWriteModel, error) {
wm := NewExecutionWriteModel(id, resourceOwner)
err := c.eventstore.FilterToQueryReducer(ctx, wm)
if err != nil {
return nil, err
}
return wm, nil
}
func createIncludeCacheFunctions() (func(s string) ([]string, bool), func(s string, strings []string)) {
tempCache := make(map[string][]string)
return func(s string) ([]string, bool) {
include, ok := tempCache[s]
return include, ok
}, func(s string, strings []string) {
tempCache[s] = strings
}
}
type includeCacheFunc func(ctx context.Context, id string, resourceOwner string) ([]string, error)
func checkForIncludeCircular(ctx context.Context, id string, resourceOwner string, includes []string, cache includeCacheFunc, maxLevels int) error {
if len(includes) == 0 {
return nil
}
level := 0
for _, include := range includes {
if id == include {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-mo1cmjp5k7", "Errors.Execution.CircularInclude")
}
if err := checkForIncludeCircularRecur(ctx, []string{id}, resourceOwner, include, cache, maxLevels, level); err != nil {
return err
}
}
return nil
}
func (c *Commands) getExecutionIncludes(
getCache func(string) ([]string, bool),
setCache func(string, []string),
) includeCacheFunc {
return func(ctx context.Context, id string, resourceOwner string) ([]string, error) {
included, ok := getCache(id)
if !ok {
included, err := c.getExecutionWriteModelByID(ctx, id, resourceOwner)
if err != nil {
return nil, err
}
includes := included.IncludeList()
setCache(id, includes)
return includes, nil
}
return included, nil
}
}
func checkForIncludeCircularRecur(ctx context.Context, ids []string, resourceOwner string, include string, cache includeCacheFunc, maxLevels, level int) error {
included, err := cache(ctx, include, resourceOwner)
if err != nil {
return err
}
currentLevel := level + 1
if currentLevel >= maxLevels {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-gbhd3g57oo", "Errors.Execution.MaxLevelsInclude")
}
for _, includedInclude := range included {
if include == includedInclude {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-iuch02i656", "Errors.Execution.CircularInclude")
}
for _, id := range ids {
if includedInclude == id {
return zerrors.ThrowPreconditionFailed(nil, "COMMAND-819opvhgjv", "Errors.Execution.CircularInclude")
}
}
if err := checkForIncludeCircularRecur(ctx, append(ids, include), resourceOwner, includedInclude, cache, maxLevels, currentLevel); err != nil {
return err
}
}
return nil
}