mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20:47:32 +00:00
feat: query side for executions and targets for actions v2 (#7524)
* feat: add projections and query side to executions and targets * feat: add list and get endpoints for targets * feat: add integration tests for query endpoints target and execution * fix: linting * fix: linting * fix: review changes, renames and corrections * fix: review changes, renames and corrections * fix: review changes, renames and corrections * fix: review changes, renames and corrections * fix: review changes, renames and corrections * fix: review changes, renames and corrections * fix: remove position from list details
This commit is contained in:
@@ -1011,6 +1011,7 @@ InternalAuthZ:
|
|||||||
- "events.read"
|
- "events.read"
|
||||||
- "milestones.read"
|
- "milestones.read"
|
||||||
- "session.delete"
|
- "session.delete"
|
||||||
|
- "execution.target.read"
|
||||||
- "execution.target.write"
|
- "execution.target.write"
|
||||||
- "execution.target.delete"
|
- "execution.target.delete"
|
||||||
- "execution.read"
|
- "execution.read"
|
||||||
@@ -1048,6 +1049,8 @@ InternalAuthZ:
|
|||||||
- "project.grant.member.read"
|
- "project.grant.member.read"
|
||||||
- "events.read"
|
- "events.read"
|
||||||
- "milestones.read"
|
- "milestones.read"
|
||||||
|
- "execution.target.read"
|
||||||
|
- "execution.read"
|
||||||
- Role: "IAM_ORG_MANAGER"
|
- Role: "IAM_ORG_MANAGER"
|
||||||
Permissions:
|
Permissions:
|
||||||
- "org.read"
|
- "org.read"
|
||||||
|
@@ -37,7 +37,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
|
|||||||
var err error
|
var err error
|
||||||
var details *domain.ObjectDetails
|
var details *domain.ObjectDetails
|
||||||
switch t := req.GetCondition().GetConditionType().(type) {
|
switch t := req.GetCondition().GetConditionType().(type) {
|
||||||
case *execution.SetConditions_Request:
|
case *execution.Condition_Request:
|
||||||
cond := &command.ExecutionAPICondition{
|
cond := &command.ExecutionAPICondition{
|
||||||
Method: t.Request.GetMethod(),
|
Method: t.Request.GetMethod(),
|
||||||
Service: t.Request.GetService(),
|
Service: t.Request.GetService(),
|
||||||
@@ -47,7 +47,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *execution.SetConditions_Response:
|
case *execution.Condition_Response:
|
||||||
cond := &command.ExecutionAPICondition{
|
cond := &command.ExecutionAPICondition{
|
||||||
Method: t.Response.GetMethod(),
|
Method: t.Response.GetMethod(),
|
||||||
Service: t.Response.GetService(),
|
Service: t.Response.GetService(),
|
||||||
@@ -57,7 +57,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *execution.SetConditions_Event:
|
case *execution.Condition_Event:
|
||||||
cond := &command.ExecutionEventCondition{
|
cond := &command.ExecutionEventCondition{
|
||||||
Event: t.Event.GetEvent(),
|
Event: t.Event.GetEvent(),
|
||||||
Group: t.Event.GetGroup(),
|
Group: t.Event.GetGroup(),
|
||||||
@@ -67,7 +67,7 @@ func (s *Server) SetExecution(ctx context.Context, req *execution.SetExecutionRe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *execution.SetConditions_Function:
|
case *execution.Condition_Function:
|
||||||
details, err = s.command.SetExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), set, authz.GetInstance(ctx).InstanceID())
|
details, err = s.command.SetExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), set, authz.GetInstance(ctx).InstanceID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -82,7 +82,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
|
|||||||
var err error
|
var err error
|
||||||
var details *domain.ObjectDetails
|
var details *domain.ObjectDetails
|
||||||
switch t := req.GetCondition().GetConditionType().(type) {
|
switch t := req.GetCondition().GetConditionType().(type) {
|
||||||
case *execution.SetConditions_Request:
|
case *execution.Condition_Request:
|
||||||
cond := &command.ExecutionAPICondition{
|
cond := &command.ExecutionAPICondition{
|
||||||
Method: t.Request.GetMethod(),
|
Method: t.Request.GetMethod(),
|
||||||
Service: t.Request.GetService(),
|
Service: t.Request.GetService(),
|
||||||
@@ -92,7 +92,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *execution.SetConditions_Response:
|
case *execution.Condition_Response:
|
||||||
cond := &command.ExecutionAPICondition{
|
cond := &command.ExecutionAPICondition{
|
||||||
Method: t.Response.GetMethod(),
|
Method: t.Response.GetMethod(),
|
||||||
Service: t.Response.GetService(),
|
Service: t.Response.GetService(),
|
||||||
@@ -102,7 +102,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *execution.SetConditions_Event:
|
case *execution.Condition_Event:
|
||||||
cond := &command.ExecutionEventCondition{
|
cond := &command.ExecutionEventCondition{
|
||||||
Event: t.Event.GetEvent(),
|
Event: t.Event.GetEvent(),
|
||||||
Group: t.Event.GetGroup(),
|
Group: t.Event.GetGroup(),
|
||||||
@@ -112,7 +112,7 @@ func (s *Server) DeleteExecution(ctx context.Context, req *execution.DeleteExecu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case *execution.SetConditions_Function:
|
case *execution.Condition_Function:
|
||||||
details, err = s.command.DeleteExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), authz.GetInstance(ctx).InstanceID())
|
details, err = s.command.DeleteExecutionFunction(ctx, command.ExecutionFunctionCondition(t.Function), authz.GetInstance(ctx).InstanceID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@@ -28,10 +28,10 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_All{All: true},
|
Condition: &execution.RequestExecution_All{All: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -42,9 +42,9 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{},
|
Request: &execution.RequestExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: []string{targetResp.GetId()},
|
Targets: []string{targetResp.GetId()},
|
||||||
@@ -55,10 +55,10 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "method, not existing",
|
name: "method, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Method{
|
Condition: &execution.RequestExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.NotExistingService/List",
|
Method: "/zitadel.session.v2beta.NotExistingService/List",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -72,10 +72,10 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "method, ok",
|
name: "method, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Method{
|
Condition: &execution.RequestExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
|
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -94,10 +94,10 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "service, not existing",
|
name: "service, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Service{
|
Condition: &execution.RequestExecution_Service{
|
||||||
Service: "NotExistingService",
|
Service: "NotExistingService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -111,10 +111,10 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "service, ok",
|
name: "service, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Service{
|
Condition: &execution.RequestExecution_Service{
|
||||||
Service: "zitadel.session.v2beta.SessionService",
|
Service: "zitadel.session.v2beta.SessionService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -133,10 +133,10 @@ func TestServer_SetExecution_Request(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_All{
|
Condition: &execution.RequestExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -170,16 +170,17 @@ func TestServer_SetExecution_Request_Include(t *testing.T) {
|
|||||||
targetResp := Tester.CreateTarget(CTX, t)
|
targetResp := Tester.CreateTarget(CTX, t)
|
||||||
executionCond := "request"
|
executionCond := "request"
|
||||||
Tester.SetExecution(CTX, t,
|
Tester.SetExecution(CTX, t,
|
||||||
&execution.SetConditions{
|
&execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_All{
|
Condition: &execution.RequestExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[]string{targetResp.GetId()},
|
[]string{targetResp.GetId()},
|
||||||
|
[]string{},
|
||||||
)
|
)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -193,10 +194,10 @@ func TestServer_SetExecution_Request_Include(t *testing.T) {
|
|||||||
name: "method, ok",
|
name: "method, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Method{
|
Condition: &execution.RequestExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
|
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -215,10 +216,10 @@ func TestServer_SetExecution_Request_Include(t *testing.T) {
|
|||||||
name: "service, ok",
|
name: "service, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Service{
|
Condition: &execution.RequestExecution_Service{
|
||||||
Service: "zitadel.session.v2beta.SessionService",
|
Service: "zitadel.session.v2beta.SessionService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -237,10 +238,10 @@ func TestServer_SetExecution_Request_Include(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_All{
|
Condition: &execution.RequestExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -285,10 +286,10 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_All{All: true},
|
Condition: &execution.RequestExecution_All{All: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -299,9 +300,9 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{},
|
Request: &execution.RequestExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -311,10 +312,10 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "method, not existing",
|
name: "method, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Method{
|
Condition: &execution.RequestExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/NotExisting",
|
Method: "/zitadel.session.v2beta.SessionService/NotExisting",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -327,14 +328,14 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "method, ok",
|
name: "method, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Method{
|
Condition: &execution.RequestExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/GetSession",
|
Method: "/zitadel.session.v2beta.SessionService/GetSession",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -352,10 +353,10 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "service, not existing",
|
name: "service, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Service{
|
Condition: &execution.RequestExecution_Service{
|
||||||
Service: "NotExistingService",
|
Service: "NotExistingService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -368,14 +369,14 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "service, ok",
|
name: "service, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_Service{
|
Condition: &execution.RequestExecution_Service{
|
||||||
Service: "zitadel.user.v2beta.UserService",
|
Service: "zitadel.user.v2beta.UserService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -393,14 +394,14 @@ func TestServer_DeleteExecution_Request(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Request{
|
ConditionType: &execution.Condition_Request{
|
||||||
Request: &execution.SetRequestExecution{
|
Request: &execution.RequestExecution{
|
||||||
Condition: &execution.SetRequestExecution_All{
|
Condition: &execution.RequestExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -448,10 +449,10 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_All{All: true},
|
Condition: &execution.ResponseExecution_All{All: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -462,9 +463,9 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{},
|
Response: &execution.ResponseExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: []string{targetResp.GetId()},
|
Targets: []string{targetResp.GetId()},
|
||||||
@@ -475,10 +476,10 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "method, not existing",
|
name: "method, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Method{
|
Condition: &execution.ResponseExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.NotExistingService/List",
|
Method: "/zitadel.session.v2beta.NotExistingService/List",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -492,10 +493,10 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "method, ok",
|
name: "method, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Method{
|
Condition: &execution.ResponseExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
|
Method: "/zitadel.session.v2beta.SessionService/ListSessions",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -514,10 +515,10 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "service, not existing",
|
name: "service, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Service{
|
Condition: &execution.ResponseExecution_Service{
|
||||||
Service: "NotExistingService",
|
Service: "NotExistingService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -531,10 +532,10 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "service, ok",
|
name: "service, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Service{
|
Condition: &execution.ResponseExecution_Service{
|
||||||
Service: "zitadel.session.v2beta.SessionService",
|
Service: "zitadel.session.v2beta.SessionService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -553,10 +554,10 @@ func TestServer_SetExecution_Response(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_All{
|
Condition: &execution.ResponseExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -601,10 +602,10 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_All{
|
Condition: &execution.ResponseExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -617,9 +618,9 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{},
|
Response: &execution.ResponseExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -629,10 +630,10 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "method, not existing",
|
name: "method, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Method{
|
Condition: &execution.ResponseExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/NotExisting",
|
Method: "/zitadel.session.v2beta.SessionService/NotExisting",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -645,14 +646,14 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "method, ok",
|
name: "method, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Method{
|
Condition: &execution.ResponseExecution_Method{
|
||||||
Method: "/zitadel.session.v2beta.SessionService/GetSession",
|
Method: "/zitadel.session.v2beta.SessionService/GetSession",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -670,10 +671,10 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "service, not existing",
|
name: "service, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Service{
|
Condition: &execution.ResponseExecution_Service{
|
||||||
Service: "NotExistingService",
|
Service: "NotExistingService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -686,14 +687,14 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "service, ok",
|
name: "service, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_Service{
|
Condition: &execution.ResponseExecution_Service{
|
||||||
Service: "zitadel.user.v2beta.UserService",
|
Service: "zitadel.user.v2beta.UserService",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -711,14 +712,14 @@ func TestServer_DeleteExecution_Response(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_All{
|
Condition: &execution.ResponseExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -766,10 +767,10 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_All{
|
Condition: &execution.EventExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -782,9 +783,9 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{},
|
Event: &execution.EventExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: []string{targetResp.GetId()},
|
Targets: []string{targetResp.GetId()},
|
||||||
@@ -798,10 +799,10 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "event, not existing",
|
name: "event, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Event{
|
Condition: &execution.EventExecution_Event{
|
||||||
Event: "xxx",
|
Event: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -816,10 +817,10 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "event, ok",
|
name: "event, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Event{
|
Condition: &execution.EventExecution_Event{
|
||||||
Event: "xxx",
|
Event: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -841,10 +842,10 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "group, not existing",
|
name: "group, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Group{
|
Condition: &execution.EventExecution_Group{
|
||||||
Group: "xxx",
|
Group: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -859,10 +860,10 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "group, ok",
|
name: "group, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Group{
|
Condition: &execution.EventExecution_Group{
|
||||||
Group: "xxx",
|
Group: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -881,10 +882,10 @@ func TestServer_SetExecution_Event(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_All{
|
Condition: &execution.EventExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -929,10 +930,10 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_All{
|
Condition: &execution.EventExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -945,9 +946,9 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{},
|
Event: &execution.EventExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -959,10 +960,10 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "event, not existing",
|
name: "event, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Event{
|
Condition: &execution.EventExecution_Event{
|
||||||
Event: "xxx",
|
Event: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -976,14 +977,14 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "event, ok",
|
name: "event, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Event{
|
Condition: &execution.EventExecution_Event{
|
||||||
Event: "xxx",
|
Event: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1001,10 +1002,10 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "group, not existing",
|
name: "group, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Group{
|
Condition: &execution.EventExecution_Group{
|
||||||
Group: "xxx",
|
Group: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1017,14 +1018,14 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "group, ok",
|
name: "group, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_Group{
|
Condition: &execution.EventExecution_Group{
|
||||||
Group: "xxx",
|
Group: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1042,10 +1043,10 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "all, not existing",
|
name: "all, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_All{
|
Condition: &execution.EventExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1063,14 +1064,14 @@ func TestServer_DeleteExecution_Event(t *testing.T) {
|
|||||||
name: "all, ok",
|
name: "all, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Event{
|
ConditionType: &execution.Condition_Event{
|
||||||
Event: &execution.SetEventExecution{
|
Event: &execution.EventExecution{
|
||||||
Condition: &execution.SetEventExecution_All{
|
Condition: &execution.EventExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1118,10 +1119,10 @@ func TestServer_SetExecution_Function(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_All{All: true},
|
Condition: &execution.ResponseExecution_All{All: true},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1132,9 +1133,9 @@ func TestServer_SetExecution_Function(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{},
|
Response: &execution.ResponseExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Targets: []string{targetResp.GetId()},
|
Targets: []string{targetResp.GetId()},
|
||||||
@@ -1145,8 +1146,8 @@ func TestServer_SetExecution_Function(t *testing.T) {
|
|||||||
name: "function, not existing",
|
name: "function, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Function{
|
ConditionType: &execution.Condition_Function{
|
||||||
Function: "xxx",
|
Function: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1158,8 +1159,8 @@ func TestServer_SetExecution_Function(t *testing.T) {
|
|||||||
name: "function, ok",
|
name: "function, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.SetExecutionRequest{
|
req: &execution.SetExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Function{
|
ConditionType: &execution.Condition_Function{
|
||||||
Function: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication",
|
Function: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1202,10 +1203,10 @@ func TestServer_DeleteExecution_Function(t *testing.T) {
|
|||||||
name: "missing permission",
|
name: "missing permission",
|
||||||
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{
|
Response: &execution.ResponseExecution{
|
||||||
Condition: &execution.SetResponseExecution_All{
|
Condition: &execution.ResponseExecution_All{
|
||||||
All: true,
|
All: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1218,9 +1219,9 @@ func TestServer_DeleteExecution_Function(t *testing.T) {
|
|||||||
name: "no condition, error",
|
name: "no condition, error",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Response{
|
ConditionType: &execution.Condition_Response{
|
||||||
Response: &execution.SetResponseExecution{},
|
Response: &execution.ResponseExecution{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1230,8 +1231,8 @@ func TestServer_DeleteExecution_Function(t *testing.T) {
|
|||||||
name: "function, not existing",
|
name: "function, not existing",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Function{
|
ConditionType: &execution.Condition_Function{
|
||||||
Function: "xxx",
|
Function: "xxx",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1242,12 +1243,12 @@ func TestServer_DeleteExecution_Function(t *testing.T) {
|
|||||||
name: "function, ok",
|
name: "function, ok",
|
||||||
ctx: CTX,
|
ctx: CTX,
|
||||||
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
dep: func(ctx context.Context, request *execution.DeleteExecutionRequest) error {
|
||||||
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()})
|
Tester.SetExecution(ctx, t, request.GetCondition(), []string{targetResp.GetId()}, []string{})
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
req: &execution.DeleteExecutionRequest{
|
req: &execution.DeleteExecutionRequest{
|
||||||
Condition: &execution.SetConditions{
|
Condition: &execution.Condition{
|
||||||
ConditionType: &execution.SetConditions_Function{
|
ConditionType: &execution.Condition_Function{
|
||||||
Function: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication",
|
Function: "Action.Flow.Type.ExternalAuthentication.Action.TriggerType.PostAuthentication",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
286
internal/api/grpc/execution/v3alpha/query.go
Normal file
286
internal/api/grpc/execution/v3alpha/query.go
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
package execution
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) ListTargets(ctx context.Context, req *execution.ListTargetsRequest) (*execution.ListTargetsResponse, error) {
|
||||||
|
queries, err := listTargetsRequestToModel(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := s.query.SearchTargets(ctx, queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &execution.ListTargetsResponse{
|
||||||
|
Result: targetsToPb(resp.Targets),
|
||||||
|
Details: object.ToListDetails(resp.SearchResponse),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listTargetsRequestToModel(req *execution.ListTargetsRequest) (*query.TargetSearchQueries, error) {
|
||||||
|
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||||
|
queries, err := targetQueriesToQuery(req.Queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &query.TargetSearchQueries{
|
||||||
|
SearchRequest: query.SearchRequest{
|
||||||
|
Offset: offset,
|
||||||
|
Limit: limit,
|
||||||
|
Asc: asc,
|
||||||
|
SortingColumn: targetFieldNameToSortingColumn(req.SortingColumn),
|
||||||
|
},
|
||||||
|
Queries: queries,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetFieldNameToSortingColumn(field execution.TargetFieldName) query.Column {
|
||||||
|
switch field {
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_UNSPECIFIED:
|
||||||
|
return query.TargetColumnID
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_ID:
|
||||||
|
return query.TargetColumnID
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_CREATION_DATE:
|
||||||
|
return query.TargetColumnCreationDate
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_CHANGE_DATE:
|
||||||
|
return query.TargetColumnChangeDate
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_NAME:
|
||||||
|
return query.TargetColumnName
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_TARGET_TYPE:
|
||||||
|
return query.TargetColumnTargetType
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_URL:
|
||||||
|
return query.TargetColumnURL
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_TIMEOUT:
|
||||||
|
return query.TargetColumnTimeout
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_ASYNC:
|
||||||
|
return query.TargetColumnAsync
|
||||||
|
case execution.TargetFieldName_FIELD_NAME_INTERRUPT_ON_ERROR:
|
||||||
|
return query.TargetColumnInterruptOnError
|
||||||
|
default:
|
||||||
|
return query.TargetColumnID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetQueriesToQuery(queries []*execution.TargetSearchQuery) (_ []query.SearchQuery, err error) {
|
||||||
|
q := make([]query.SearchQuery, len(queries))
|
||||||
|
for i, query := range queries {
|
||||||
|
q[i], err = targetQueryToQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetQueryToQuery(query *execution.TargetSearchQuery) (query.SearchQuery, error) {
|
||||||
|
switch q := query.Query.(type) {
|
||||||
|
case *execution.TargetSearchQuery_TargetNameQuery:
|
||||||
|
return targetNameQueryToQuery(q.TargetNameQuery)
|
||||||
|
case *execution.TargetSearchQuery_InTargetIdsQuery:
|
||||||
|
return targetInTargetIdsQueryToQuery(q.InTargetIdsQuery)
|
||||||
|
default:
|
||||||
|
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetNameQueryToQuery(q *execution.TargetNameQuery) (query.SearchQuery, error) {
|
||||||
|
return query.NewTargetNameSearchQuery(object.TextMethodToQuery(q.Method), q.GetTargetName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetInTargetIdsQueryToQuery(q *execution.InTargetIDsQuery) (query.SearchQuery, error) {
|
||||||
|
return query.NewTargetInIDsSearchQuery(q.GetTargetIds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) GetTargetByID(ctx context.Context, req *execution.GetTargetByIDRequest) (_ *execution.GetTargetByIDResponse, err error) {
|
||||||
|
resp, err := s.query.GetTargetByID(ctx, req.GetTargetId())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &execution.GetTargetByIDResponse{
|
||||||
|
Target: targetToPb(resp),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetsToPb(targets []*query.Target) []*execution.Target {
|
||||||
|
t := make([]*execution.Target, len(targets))
|
||||||
|
for i, target := range targets {
|
||||||
|
t[i] = targetToPb(target)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func targetToPb(t *query.Target) *execution.Target {
|
||||||
|
target := &execution.Target{
|
||||||
|
Details: object.DomainToDetailsPb(&t.ObjectDetails),
|
||||||
|
TargetId: t.ID,
|
||||||
|
Name: t.Name,
|
||||||
|
Timeout: durationpb.New(t.Timeout),
|
||||||
|
}
|
||||||
|
if t.Async {
|
||||||
|
target.ExecutionType = &execution.Target_IsAsync{IsAsync: t.Async}
|
||||||
|
}
|
||||||
|
if t.InterruptOnError {
|
||||||
|
target.ExecutionType = &execution.Target_InterruptOnError{InterruptOnError: t.InterruptOnError}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t.TargetType {
|
||||||
|
case domain.TargetTypeWebhook:
|
||||||
|
target.TargetType = &execution.Target_RestWebhook{RestWebhook: &execution.SetRESTWebhook{Url: t.URL}}
|
||||||
|
case domain.TargetTypeRequestResponse:
|
||||||
|
target.TargetType = &execution.Target_RestRequestResponse{RestRequestResponse: &execution.SetRESTRequestResponse{Url: t.URL}}
|
||||||
|
default:
|
||||||
|
target.TargetType = nil
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListExecutions(ctx context.Context, req *execution.ListExecutionsRequest) (*execution.ListExecutionsResponse, error) {
|
||||||
|
queries, err := listExecutionsRequestToModel(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resp, err := s.query.SearchExecutions(ctx, queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &execution.ListExecutionsResponse{
|
||||||
|
Result: executionsToPb(resp.Executions),
|
||||||
|
Details: object.ToListDetails(resp.SearchResponse),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listExecutionsRequestToModel(req *execution.ListExecutionsRequest) (*query.ExecutionSearchQueries, error) {
|
||||||
|
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||||
|
queries, err := executionQueriesToQuery(req.Queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &query.ExecutionSearchQueries{
|
||||||
|
SearchRequest: query.SearchRequest{
|
||||||
|
Offset: offset,
|
||||||
|
Limit: limit,
|
||||||
|
Asc: asc,
|
||||||
|
},
|
||||||
|
Queries: queries,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func executionQueriesToQuery(queries []*execution.SearchQuery) (_ []query.SearchQuery, err error) {
|
||||||
|
q := make([]query.SearchQuery, len(queries))
|
||||||
|
for i, query := range queries {
|
||||||
|
q[i], err = executionQueryToQuery(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func executionQueryToQuery(searchQuery *execution.SearchQuery) (query.SearchQuery, error) {
|
||||||
|
switch q := searchQuery.Query.(type) {
|
||||||
|
case *execution.SearchQuery_InConditionsQuery:
|
||||||
|
return inConditionsQueryToQuery(q.InConditionsQuery)
|
||||||
|
case *execution.SearchQuery_ExecutionTypeQuery:
|
||||||
|
return executionTypeToQuery(q.ExecutionTypeQuery)
|
||||||
|
case *execution.SearchQuery_TargetQuery:
|
||||||
|
return query.NewExecutionTargetSearchQuery(q.TargetQuery.GetTargetId())
|
||||||
|
case *execution.SearchQuery_IncludeQuery:
|
||||||
|
return query.NewExecutionIncludeSearchQuery(q.IncludeQuery.GetInclude())
|
||||||
|
default:
|
||||||
|
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func executionTypeToQuery(q *execution.ExecutionTypeQuery) (query.SearchQuery, error) {
|
||||||
|
switch q.ExecutionType {
|
||||||
|
case execution.ExecutionType_EXECUTION_TYPE_UNSPECIFIED:
|
||||||
|
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified)
|
||||||
|
case execution.ExecutionType_EXECUTION_TYPE_REQUEST:
|
||||||
|
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeRequest)
|
||||||
|
case execution.ExecutionType_EXECUTION_TYPE_RESPONSE:
|
||||||
|
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeResponse)
|
||||||
|
case execution.ExecutionType_EXECUTION_TYPE_EVENT:
|
||||||
|
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeEvent)
|
||||||
|
case execution.ExecutionType_EXECUTION_TYPE_FUNCTION:
|
||||||
|
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeFunction)
|
||||||
|
default:
|
||||||
|
return query.NewExecutionTypeSearchQuery(domain.ExecutionTypeUnspecified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inConditionsQueryToQuery(q *execution.InConditionsQuery) (query.SearchQuery, error) {
|
||||||
|
values := make([]string, len(q.GetConditions()))
|
||||||
|
for i, condition := range q.GetConditions() {
|
||||||
|
id, err := conditionToID(condition)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
values[i] = id
|
||||||
|
}
|
||||||
|
return query.NewExecutionInIDsSearchQuery(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func conditionToID(q *execution.Condition) (string, error) {
|
||||||
|
switch t := q.GetConditionType().(type) {
|
||||||
|
case *execution.Condition_Request:
|
||||||
|
cond := &command.ExecutionAPICondition{
|
||||||
|
Method: t.Request.GetMethod(),
|
||||||
|
Service: t.Request.GetService(),
|
||||||
|
All: t.Request.GetAll(),
|
||||||
|
}
|
||||||
|
return cond.ID(domain.ExecutionTypeRequest), nil
|
||||||
|
case *execution.Condition_Response:
|
||||||
|
cond := &command.ExecutionAPICondition{
|
||||||
|
Method: t.Response.GetMethod(),
|
||||||
|
Service: t.Response.GetService(),
|
||||||
|
All: t.Response.GetAll(),
|
||||||
|
}
|
||||||
|
return cond.ID(domain.ExecutionTypeResponse), nil
|
||||||
|
case *execution.Condition_Event:
|
||||||
|
cond := &command.ExecutionEventCondition{
|
||||||
|
Event: t.Event.GetEvent(),
|
||||||
|
Group: t.Event.GetGroup(),
|
||||||
|
All: t.Event.GetAll(),
|
||||||
|
}
|
||||||
|
return cond.ID(), nil
|
||||||
|
case *execution.Condition_Function:
|
||||||
|
return t.Function, nil
|
||||||
|
default:
|
||||||
|
return "", zerrors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func executionsToPb(executions []*query.Execution) []*execution.Execution {
|
||||||
|
e := make([]*execution.Execution, len(executions))
|
||||||
|
for i, execution := range executions {
|
||||||
|
e[i] = executionToPb(execution)
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func executionToPb(e *query.Execution) *execution.Execution {
|
||||||
|
var targets, includes []string
|
||||||
|
if len(e.Targets) > 0 {
|
||||||
|
targets = e.Targets
|
||||||
|
}
|
||||||
|
if len(e.Includes) > 0 {
|
||||||
|
includes = e.Includes
|
||||||
|
}
|
||||||
|
return &execution.Execution{
|
||||||
|
Details: object.DomainToDetailsPb(&e.ObjectDetails),
|
||||||
|
ExecutionId: e.ID,
|
||||||
|
Targets: targets,
|
||||||
|
Includes: includes,
|
||||||
|
}
|
||||||
|
}
|
715
internal/api/grpc/execution/v3alpha/query_integration_test.go
Normal file
715
internal/api/grpc/execution/v3alpha/query_integration_test.go
Normal file
@@ -0,0 +1,715 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package execution_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/integration"
|
||||||
|
execution "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha"
|
||||||
|
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServer_GetTargetByID(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
dep func(context.Context, *execution.GetTargetByIDRequest, *execution.GetTargetByIDResponse) error
|
||||||
|
req *execution.GetTargetByIDRequest
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *execution.GetTargetByIDResponse
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "missing permission",
|
||||||
|
args: args{
|
||||||
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
|
req: &execution.GetTargetByIDRequest{},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not found",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
req: &execution.GetTargetByIDRequest{TargetId: "notexisting"},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get, ok",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.GetTargetByIDRequest, response *execution.GetTargetByIDResponse) error {
|
||||||
|
name := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||||
|
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false)
|
||||||
|
request.TargetId = resp.GetId()
|
||||||
|
|
||||||
|
response.Target.TargetId = resp.GetId()
|
||||||
|
response.Target.Name = name
|
||||||
|
response.Target.Details.ResourceOwner = resp.GetDetails().GetResourceOwner()
|
||||||
|
response.Target.Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Target.Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.GetTargetByIDRequest{},
|
||||||
|
},
|
||||||
|
want: &execution.GetTargetByIDResponse{
|
||||||
|
Target: &execution.Target{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get, async, ok",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.GetTargetByIDRequest, response *execution.GetTargetByIDResponse) error {
|
||||||
|
name := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||||
|
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, true, false)
|
||||||
|
request.TargetId = resp.GetId()
|
||||||
|
|
||||||
|
response.Target.TargetId = resp.GetId()
|
||||||
|
response.Target.Name = name
|
||||||
|
response.Target.Details.ResourceOwner = resp.GetDetails().GetResourceOwner()
|
||||||
|
response.Target.Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Target.Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.GetTargetByIDRequest{},
|
||||||
|
},
|
||||||
|
want: &execution.GetTargetByIDResponse{
|
||||||
|
Target: &execution.Target{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
ExecutionType: &execution.Target_IsAsync{IsAsync: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get, interruptOnError, ok",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.GetTargetByIDRequest, response *execution.GetTargetByIDResponse) error {
|
||||||
|
name := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||||
|
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, true)
|
||||||
|
request.TargetId = resp.GetId()
|
||||||
|
|
||||||
|
response.Target.TargetId = resp.GetId()
|
||||||
|
response.Target.Name = name
|
||||||
|
response.Target.Details.ResourceOwner = resp.GetDetails().GetResourceOwner()
|
||||||
|
response.Target.Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Target.Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.GetTargetByIDRequest{},
|
||||||
|
},
|
||||||
|
want: &execution.GetTargetByIDResponse{
|
||||||
|
Target: &execution.Target{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
ExecutionType: &execution.Target_InterruptOnError{InterruptOnError: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.args.dep != nil {
|
||||||
|
err := tt.args.dep(tt.args.ctx, tt.args.req, tt.want)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retryDuration := 5 * time.Second
|
||||||
|
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||||
|
retryDuration = time.Until(ctxDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||||
|
got, getErr := Client.GetTargetByID(tt.args.ctx, tt.args.req)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(ttt, getErr, "Error: "+getErr.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(ttt, getErr)
|
||||||
|
}
|
||||||
|
if getErr != nil {
|
||||||
|
fmt.Println("Error: " + getErr.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
integration.AssertDetails(t, tt.want.GetTarget(), got.GetTarget())
|
||||||
|
|
||||||
|
assert.Equal(t, tt.want.Target, got.Target)
|
||||||
|
|
||||||
|
}, retryDuration, time.Millisecond*100, "timeout waiting for expected execution result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServer_ListTargets(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
dep func(context.Context, *execution.ListTargetsRequest, *execution.ListTargetsResponse) error
|
||||||
|
req *execution.ListTargetsRequest
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *execution.ListTargetsResponse
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "missing permission",
|
||||||
|
args: args{
|
||||||
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
|
req: &execution.ListTargetsRequest{},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list, not found",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
req: &execution.ListTargetsRequest{
|
||||||
|
Queries: []*execution.TargetSearchQuery{
|
||||||
|
{Query: &execution.TargetSearchQuery_InTargetIdsQuery{
|
||||||
|
InTargetIdsQuery: &execution.InTargetIDsQuery{
|
||||||
|
TargetIds: []string{"notfound"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListTargetsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 0,
|
||||||
|
},
|
||||||
|
Result: []*execution.Target{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list single id",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListTargetsRequest, response *execution.ListTargetsResponse) error {
|
||||||
|
name := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||||
|
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false)
|
||||||
|
request.Queries[0].Query = &execution.TargetSearchQuery_InTargetIdsQuery{
|
||||||
|
InTargetIdsQuery: &execution.InTargetIDsQuery{
|
||||||
|
TargetIds: []string{resp.GetId()},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response.Details.Timestamp = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
response.Result[0].TargetId = resp.GetId()
|
||||||
|
response.Result[0].Name = name
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListTargetsRequest{
|
||||||
|
Queries: []*execution.TargetSearchQuery{{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListTargetsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 1,
|
||||||
|
},
|
||||||
|
Result: []*execution.Target{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "list single name",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListTargetsRequest, response *execution.ListTargetsResponse) error {
|
||||||
|
name := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||||
|
resp := Tester.CreateTargetWithNameAndType(ctx, t, name, false, false)
|
||||||
|
request.Queries[0].Query = &execution.TargetSearchQuery_TargetNameQuery{
|
||||||
|
TargetNameQuery: &execution.TargetNameQuery{
|
||||||
|
TargetName: name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response.Details.Timestamp = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
response.Result[0].TargetId = resp.GetId()
|
||||||
|
response.Result[0].Name = name
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListTargetsRequest{
|
||||||
|
Queries: []*execution.TargetSearchQuery{{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListTargetsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 1,
|
||||||
|
},
|
||||||
|
Result: []*execution.Target{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list multiple id",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListTargetsRequest, response *execution.ListTargetsResponse) error {
|
||||||
|
name1 := fmt.Sprint(time.Now().UnixNano() + 1)
|
||||||
|
name2 := fmt.Sprint(time.Now().UnixNano() + 3)
|
||||||
|
name3 := fmt.Sprint(time.Now().UnixNano() + 5)
|
||||||
|
resp1 := Tester.CreateTargetWithNameAndType(ctx, t, name1, false, false)
|
||||||
|
resp2 := Tester.CreateTargetWithNameAndType(ctx, t, name2, true, false)
|
||||||
|
resp3 := Tester.CreateTargetWithNameAndType(ctx, t, name3, false, true)
|
||||||
|
request.Queries[0].Query = &execution.TargetSearchQuery_InTargetIdsQuery{
|
||||||
|
InTargetIdsQuery: &execution.InTargetIDsQuery{
|
||||||
|
TargetIds: []string{resp1.GetId(), resp2.GetId(), resp3.GetId()},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
response.Details.Timestamp = resp3.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp3.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
response.Result[0].Details.ChangeDate = resp1.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp1.GetDetails().GetSequence()
|
||||||
|
response.Result[0].TargetId = resp1.GetId()
|
||||||
|
response.Result[0].Name = name1
|
||||||
|
response.Result[1].Details.ChangeDate = resp2.GetDetails().GetChangeDate()
|
||||||
|
response.Result[1].Details.Sequence = resp2.GetDetails().GetSequence()
|
||||||
|
response.Result[1].TargetId = resp2.GetId()
|
||||||
|
response.Result[1].Name = name2
|
||||||
|
response.Result[2].Details.ChangeDate = resp3.GetDetails().GetChangeDate()
|
||||||
|
response.Result[2].Details.Sequence = resp3.GetDetails().GetSequence()
|
||||||
|
response.Result[2].TargetId = resp3.GetId()
|
||||||
|
response.Result[2].Name = name3
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListTargetsRequest{
|
||||||
|
Queries: []*execution.TargetSearchQuery{{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListTargetsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 3,
|
||||||
|
},
|
||||||
|
Result: []*execution.Target{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
ExecutionType: &execution.Target_IsAsync{IsAsync: true},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
TargetType: &execution.Target_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
ExecutionType: &execution.Target_InterruptOnError{InterruptOnError: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.args.dep != nil {
|
||||||
|
err := tt.args.dep(tt.args.ctx, tt.args.req, tt.want)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retryDuration := 5 * time.Second
|
||||||
|
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||||
|
retryDuration = time.Until(ctxDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||||
|
got, listErr := Client.ListTargets(tt.args.ctx, tt.args.req)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(ttt, listErr, "Error: "+listErr.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(ttt, listErr)
|
||||||
|
}
|
||||||
|
if listErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// always first check length, otherwise its failed anyway
|
||||||
|
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||||
|
for i := range tt.want.Result {
|
||||||
|
assert.Contains(ttt, got.Result, tt.want.Result[i])
|
||||||
|
}
|
||||||
|
integration.AssertListDetails(t, tt.want, got)
|
||||||
|
}, retryDuration, time.Millisecond*100, "timeout waiting for expected execution result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServer_ListExecutions_Request(t *testing.T) {
|
||||||
|
targetResp := Tester.CreateTarget(CTX, t)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
dep func(context.Context, *execution.ListExecutionsRequest, *execution.ListExecutionsResponse) error
|
||||||
|
req *execution.ListExecutionsRequest
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *execution.ListExecutionsResponse
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "missing permission",
|
||||||
|
args: args{
|
||||||
|
ctx: Tester.WithAuthorization(context.Background(), integration.OrgOwner),
|
||||||
|
req: &execution.ListExecutionsRequest{},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list single condition",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error {
|
||||||
|
resp := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{})
|
||||||
|
|
||||||
|
response.Details.Timestamp = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListExecutionsRequest{
|
||||||
|
Queries: []*execution.SearchQuery{{
|
||||||
|
Query: &execution.SearchQuery_InConditionsQuery{
|
||||||
|
InConditionsQuery: &execution.InConditionsQuery{
|
||||||
|
Conditions: []*execution.Condition{{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.session.v2beta.SessionService/GetSession",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListExecutionsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 1,
|
||||||
|
},
|
||||||
|
Result: []*execution.Execution{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
ExecutionId: "request./zitadel.session.v2beta.SessionService/GetSession",
|
||||||
|
Targets: []string{targetResp.GetId()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list single target",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error {
|
||||||
|
target := Tester.CreateTarget(ctx, t)
|
||||||
|
// add target as query to the request
|
||||||
|
request.Queries[0] = &execution.SearchQuery{
|
||||||
|
Query: &execution.SearchQuery_TargetQuery{
|
||||||
|
TargetQuery: &execution.TargetQuery{
|
||||||
|
TargetId: target.GetId(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
resp := Tester.SetExecution(ctx, t, &execution.Condition{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.management.v1.ManagementService/UpdateAction",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, []string{target.GetId()}, []string{})
|
||||||
|
|
||||||
|
response.Details.Timestamp = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
response.Result[0].Details.ChangeDate = resp.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp.GetDetails().GetSequence()
|
||||||
|
response.Result[0].Targets[0] = target.GetId()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListExecutionsRequest{
|
||||||
|
Queries: []*execution.SearchQuery{{}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListExecutionsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 1,
|
||||||
|
},
|
||||||
|
Result: []*execution.Execution{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
ExecutionId: "request./zitadel.management.v1.ManagementService/UpdateAction",
|
||||||
|
Targets: []string{""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
name: "list single include",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error {
|
||||||
|
Tester.SetExecution(ctx, t, &execution.Condition{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.management.v1.ManagementService/GetAction",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, []string{targetResp.GetId()}, []string{})
|
||||||
|
resp2 := Tester.SetExecution(ctx, t, &execution.Condition{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.management.v1.ManagementService/ListActions",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, []string{}, []string{"request./zitadel.management.v1.ManagementService/GetAction"})
|
||||||
|
|
||||||
|
response.Details.Timestamp = resp2.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp2.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
response.Result[0].Details.ChangeDate = resp2.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp2.GetDetails().GetSequence()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListExecutionsRequest{
|
||||||
|
Queries: []*execution.SearchQuery{{
|
||||||
|
Query: &execution.SearchQuery_IncludeQuery{
|
||||||
|
IncludeQuery: &execution.IncludeQuery{Include: "request./zitadel.management.v1.ManagementService/GetAction"},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListExecutionsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 1,
|
||||||
|
},
|
||||||
|
Result: []*execution.Execution{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
ExecutionId: "request./zitadel.management.v1.ManagementService/ListActions",
|
||||||
|
Includes: []string{"request./zitadel.management.v1.ManagementService/GetAction"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list multiple conditions",
|
||||||
|
args: args{
|
||||||
|
ctx: CTX,
|
||||||
|
dep: func(ctx context.Context, request *execution.ListExecutionsRequest, response *execution.ListExecutionsResponse) error {
|
||||||
|
|
||||||
|
resp1 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[0], []string{targetResp.GetId()}, []string{})
|
||||||
|
response.Result[0].Details.ChangeDate = resp1.GetDetails().GetChangeDate()
|
||||||
|
response.Result[0].Details.Sequence = resp1.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
resp2 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[1], []string{targetResp.GetId()}, []string{})
|
||||||
|
response.Result[1].Details.ChangeDate = resp2.GetDetails().GetChangeDate()
|
||||||
|
response.Result[1].Details.Sequence = resp2.GetDetails().GetSequence()
|
||||||
|
|
||||||
|
resp3 := Tester.SetExecution(ctx, t, request.Queries[0].GetInConditionsQuery().GetConditions()[2], []string{targetResp.GetId()}, []string{})
|
||||||
|
response.Details.Timestamp = resp3.GetDetails().GetChangeDate()
|
||||||
|
response.Details.ProcessedSequence = resp3.GetDetails().GetSequence()
|
||||||
|
response.Result[2].Details.ChangeDate = resp3.GetDetails().GetChangeDate()
|
||||||
|
response.Result[2].Details.Sequence = resp3.GetDetails().GetSequence()
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
req: &execution.ListExecutionsRequest{
|
||||||
|
Queries: []*execution.SearchQuery{{
|
||||||
|
Query: &execution.SearchQuery_InConditionsQuery{
|
||||||
|
InConditionsQuery: &execution.InConditionsQuery{
|
||||||
|
Conditions: []*execution.Condition{
|
||||||
|
{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.session.v2beta.SessionService/GetSession",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.session.v2beta.SessionService/CreateSession",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ConditionType: &execution.Condition_Request{
|
||||||
|
Request: &execution.RequestExecution{
|
||||||
|
Condition: &execution.RequestExecution_Method{
|
||||||
|
Method: "/zitadel.session.v2beta.SessionService/SetSession",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &execution.ListExecutionsResponse{
|
||||||
|
Details: &object.ListDetails{
|
||||||
|
TotalResult: 3,
|
||||||
|
},
|
||||||
|
Result: []*execution.Execution{
|
||||||
|
{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
ExecutionId: "request./zitadel.session.v2beta.SessionService/GetSession",
|
||||||
|
Targets: []string{targetResp.GetId()},
|
||||||
|
}, {
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
ExecutionId: "request./zitadel.session.v2beta.SessionService/CreateSession",
|
||||||
|
Targets: []string{targetResp.GetId()},
|
||||||
|
}, {
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Instance.InstanceID(),
|
||||||
|
},
|
||||||
|
ExecutionId: "request./zitadel.session.v2beta.SessionService/SetSession",
|
||||||
|
Targets: []string{targetResp.GetId()},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if tt.args.dep != nil {
|
||||||
|
err := tt.args.dep(tt.args.ctx, tt.args.req, tt.want)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
retryDuration := 5 * time.Second
|
||||||
|
if ctxDeadline, ok := CTX.Deadline(); ok {
|
||||||
|
retryDuration = time.Until(ctxDeadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||||
|
got, listErr := Client.ListExecutions(tt.args.ctx, tt.args.req)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(ttt, listErr, "Error: "+listErr.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(ttt, listErr)
|
||||||
|
}
|
||||||
|
if listErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// always first check length, otherwise its failed anyway
|
||||||
|
assert.Len(ttt, got.Result, len(tt.want.Result))
|
||||||
|
for i := range tt.want.Result {
|
||||||
|
assert.Contains(ttt, got.Result, tt.want.Result[i])
|
||||||
|
}
|
||||||
|
integration.AssertListDetails(t, tt.want, got)
|
||||||
|
}, retryDuration, time.Millisecond*100, "timeout waiting for expected execution result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -27,7 +27,6 @@ func Test_createTargetToCommand(t *testing.T) {
|
|||||||
args: args{nil},
|
args: args{nil},
|
||||||
want: &command.AddTarget{
|
want: &command.AddTarget{
|
||||||
Name: "",
|
Name: "",
|
||||||
TargetType: domain.TargetTypeUnspecified,
|
|
||||||
URL: "",
|
URL: "",
|
||||||
Timeout: 0,
|
Timeout: 0,
|
||||||
Async: false,
|
Async: false,
|
||||||
|
@@ -2360,6 +2360,7 @@ func TestCommands_DeleteExecutionEvent(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommands_DeleteExecutionFunction(t *testing.T) {
|
func TestCommands_DeleteExecutionFunction(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
eventstore *eventstore.Eventstore
|
eventstore *eventstore.Eventstore
|
||||||
|
@@ -3,11 +3,8 @@ package domain
|
|||||||
type TargetType uint
|
type TargetType uint
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TargetTypeUnspecified TargetType = iota
|
TargetTypeWebhook TargetType = iota
|
||||||
TargetTypeWebhook
|
|
||||||
TargetTypeRequestResponse
|
TargetTypeRequestResponse
|
||||||
|
|
||||||
TargetTypeStateCount
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type TargetState int32
|
type TargetState int32
|
||||||
|
@@ -63,9 +63,9 @@ func AssertListDetails[D ListDetailsMsg](t testing.TB, expected, actual D) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gotCD := gotDetails.GetTimestamp().AsTime()
|
|
||||||
now := time.Now()
|
|
||||||
assert.WithinRange(t, gotCD, now.Add(-time.Minute), now.Add(time.Minute))
|
|
||||||
|
|
||||||
assert.Equal(t, wantDetails.GetTotalResult(), gotDetails.GetTotalResult())
|
assert.Equal(t, wantDetails.GetTotalResult(), gotDetails.GetTotalResult())
|
||||||
|
|
||||||
|
gotCD := gotDetails.GetTimestamp().AsTime()
|
||||||
|
wantCD := time.Now()
|
||||||
|
assert.WithinRange(t, gotCD, wantCD.Add(-time.Minute), wantCD.Add(time.Minute))
|
||||||
}
|
}
|
||||||
|
@@ -520,7 +520,7 @@ func (s *Tester) CreateProjectMembership(t *testing.T, ctx context.Context, proj
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateTarget(ctx context.Context, t *testing.T) *execution.CreateTargetResponse {
|
func (s *Tester) CreateTarget(ctx context.Context, t *testing.T) *execution.CreateTargetResponse {
|
||||||
target, err := s.Client.ExecutionV3.CreateTarget(ctx, &execution.CreateTargetRequest{
|
req := &execution.CreateTargetRequest{
|
||||||
Name: fmt.Sprint(time.Now().UnixNano() + 1),
|
Name: fmt.Sprint(time.Now().UnixNano() + 1),
|
||||||
TargetType: &execution.CreateTargetRequest_RestWebhook{
|
TargetType: &execution.CreateTargetRequest_RestWebhook{
|
||||||
RestWebhook: &execution.SetRESTWebhook{
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
@@ -528,18 +528,42 @@ func (s *Tester) CreateTarget(ctx context.Context, t *testing.T) *execution.Crea
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Timeout: durationpb.New(10 * time.Second),
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
ExecutionType: &execution.CreateTargetRequest_InterruptOnError{
|
}
|
||||||
InterruptOnError: true,
|
target, err := s.Client.ExecutionV3.CreateTarget(ctx, req)
|
||||||
},
|
|
||||||
})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) SetExecution(ctx context.Context, t *testing.T, cond *execution.SetConditions, targets []string) *execution.SetExecutionResponse {
|
func (s *Tester) CreateTargetWithNameAndType(ctx context.Context, t *testing.T, name string, async bool, interrupt bool) *execution.CreateTargetResponse {
|
||||||
|
req := &execution.CreateTargetRequest{
|
||||||
|
Name: name,
|
||||||
|
TargetType: &execution.CreateTargetRequest_RestWebhook{
|
||||||
|
RestWebhook: &execution.SetRESTWebhook{
|
||||||
|
Url: "https://example.com",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Timeout: durationpb.New(10 * time.Second),
|
||||||
|
}
|
||||||
|
if async {
|
||||||
|
req.ExecutionType = &execution.CreateTargetRequest_IsAsync{
|
||||||
|
IsAsync: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if interrupt {
|
||||||
|
req.ExecutionType = &execution.CreateTargetRequest_InterruptOnError{
|
||||||
|
InterruptOnError: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
target, err := s.Client.ExecutionV3.CreateTarget(ctx, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tester) SetExecution(ctx context.Context, t *testing.T, cond *execution.Condition, targets []string, includes []string) *execution.SetExecutionResponse {
|
||||||
target, err := s.Client.ExecutionV3.SetExecution(ctx, &execution.SetExecutionRequest{
|
target, err := s.Client.ExecutionV3.SetExecution(ctx, &execution.SetExecutionRequest{
|
||||||
Condition: cond,
|
Condition: cond,
|
||||||
Targets: targets,
|
Targets: targets,
|
||||||
|
Includes: includes,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return target
|
return target
|
||||||
|
@@ -318,6 +318,7 @@ func (s *Tester) Done() {
|
|||||||
//
|
//
|
||||||
// Note: the database must already be setup and initialized before
|
// Note: the database must already be setup and initialized before
|
||||||
// using NewTester. See the CONTRIBUTING.md document for details.
|
// using NewTester. See the CONTRIBUTING.md document for details.
|
||||||
|
|
||||||
func NewTester(ctx context.Context, zitadelConfigYAML ...string) *Tester {
|
func NewTester(ctx context.Context, zitadelConfigYAML ...string) *Tester {
|
||||||
args := strings.Split(commandLine, " ")
|
args := strings.Split(commandLine, " ")
|
||||||
|
|
||||||
|
@@ -12,7 +12,6 @@ import (
|
|||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
"github.com/zitadel/logging"
|
"github.com/zitadel/logging"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
|
||||||
"github.com/zitadel/zitadel/internal/api/call"
|
"github.com/zitadel/zitadel/internal/api/call"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/query/projection"
|
"github.com/zitadel/zitadel/internal/query/projection"
|
||||||
@@ -20,6 +19,10 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Stateful interface {
|
||||||
|
SetState(*State)
|
||||||
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
LastRun time.Time
|
LastRun time.Time
|
||||||
|
|
||||||
@@ -83,29 +86,7 @@ func (q *Queries) SearchCurrentStates(ctx context.Context, queries *CurrentState
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) latestState(ctx context.Context, projections ...table) (state *State, err error) {
|
func (q *Queries) latestState(ctx context.Context, projections ...table) (state *State, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
return latestState(ctx, q.client, projections...)
|
||||||
defer func() { span.EndWithError(err) }()
|
|
||||||
|
|
||||||
query, scan := prepareLatestState(ctx, q.client)
|
|
||||||
or := make(sq.Or, len(projections))
|
|
||||||
for i, projection := range projections {
|
|
||||||
or[i] = sq.Eq{CurrentStateColProjectionName.identifier(): projection.name}
|
|
||||||
}
|
|
||||||
stmt, args, err := query.
|
|
||||||
Where(or).
|
|
||||||
Where(sq.Eq{CurrentStateColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}).
|
|
||||||
OrderBy(CurrentStateColEventDate.identifier() + " DESC").
|
|
||||||
ToSql()
|
|
||||||
if err != nil {
|
|
||||||
return nil, zerrors.ThrowInternal(err, "QUERY-5CfX9", "Errors.Query.SQLStatement")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
|
||||||
state, err = scan(row)
|
|
||||||
return err
|
|
||||||
}, stmt, args...)
|
|
||||||
|
|
||||||
return state, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) ClearCurrentSequence(ctx context.Context, projectionName string) (err error) {
|
func (q *Queries) ClearCurrentSequence(ctx context.Context, projectionName string) (err error) {
|
||||||
|
191
internal/query/execution.go
Normal file
191
internal/query/execution.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/query/projection"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
executionTable = table{
|
||||||
|
name: projection.ExecutionTable,
|
||||||
|
instanceIDCol: projection.ExecutionInstanceIDCol,
|
||||||
|
}
|
||||||
|
ExecutionColumnID = Column{
|
||||||
|
name: projection.ExecutionIDCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnCreationDate = Column{
|
||||||
|
name: projection.ExecutionCreationDateCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnChangeDate = Column{
|
||||||
|
name: projection.ExecutionChangeDateCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnResourceOwner = Column{
|
||||||
|
name: projection.ExecutionResourceOwnerCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnInstanceID = Column{
|
||||||
|
name: projection.ExecutionInstanceIDCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnSequence = Column{
|
||||||
|
name: projection.ExecutionSequenceCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnTargets = Column{
|
||||||
|
name: projection.ExecutionTargetsCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
ExecutionColumnIncludes = Column{
|
||||||
|
name: projection.ExecutionIncludesCol,
|
||||||
|
table: executionTable,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Executions struct {
|
||||||
|
SearchResponse
|
||||||
|
Executions []*Execution
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executions) SetState(s *State) {
|
||||||
|
e.State = s
|
||||||
|
}
|
||||||
|
|
||||||
|
type Execution struct {
|
||||||
|
ID string
|
||||||
|
domain.ObjectDetails
|
||||||
|
|
||||||
|
Targets database.TextArray[string]
|
||||||
|
Includes database.TextArray[string]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExecutionSearchQueries struct {
|
||||||
|
SearchRequest
|
||||||
|
Queries []SearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *ExecutionSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||||
|
query = q.SearchRequest.toQuery(query)
|
||||||
|
for _, q := range q.Queries {
|
||||||
|
query = q.toQuery(query)
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SearchExecutions(ctx context.Context, queries *ExecutionSearchQueries) (executions *Executions, err error) {
|
||||||
|
eq := sq.Eq{
|
||||||
|
ExecutionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||||
|
}
|
||||||
|
query, scan := prepareExecutionsQuery(ctx, q.client)
|
||||||
|
return genericRowsQueryWithState[*Executions](ctx, q.client, executionTable, combineToWhereStmt(query, queries.toQuery, eq), scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetExecutionByID(ctx context.Context, id string) (execution *Execution, err error) {
|
||||||
|
eq := sq.Eq{
|
||||||
|
ExecutionColumnID.identifier(): id,
|
||||||
|
ExecutionColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||||
|
}
|
||||||
|
query, scan := prepareExecutionQuery(ctx, q.client)
|
||||||
|
return genericRowQuery[*Execution](ctx, q.client, query.Where(eq), scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExecutionInIDsSearchQuery(values []string) (SearchQuery, error) {
|
||||||
|
return NewInTextQuery(ExecutionColumnID, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExecutionTypeSearchQuery(t domain.ExecutionType) (SearchQuery, error) {
|
||||||
|
return NewTextQuery(ExecutionColumnID, t.String(), TextStartsWith)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExecutionTargetSearchQuery(value string) (SearchQuery, error) {
|
||||||
|
return NewTextQuery(ExecutionColumnTargets, value, TextListContains)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExecutionIncludeSearchQuery(value string) (SearchQuery, error) {
|
||||||
|
return NewTextQuery(ExecutionColumnIncludes, value, TextListContains)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareExecutionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*Executions, error)) {
|
||||||
|
return sq.Select(
|
||||||
|
ExecutionColumnID.identifier(),
|
||||||
|
ExecutionColumnChangeDate.identifier(),
|
||||||
|
ExecutionColumnResourceOwner.identifier(),
|
||||||
|
ExecutionColumnSequence.identifier(),
|
||||||
|
ExecutionColumnTargets.identifier(),
|
||||||
|
ExecutionColumnIncludes.identifier(),
|
||||||
|
countColumn.identifier(),
|
||||||
|
).From(executionTable.identifier()).
|
||||||
|
PlaceholderFormat(sq.Dollar),
|
||||||
|
func(rows *sql.Rows) (*Executions, error) {
|
||||||
|
executions := make([]*Execution, 0)
|
||||||
|
var count uint64
|
||||||
|
for rows.Next() {
|
||||||
|
execution := new(Execution)
|
||||||
|
err := rows.Scan(
|
||||||
|
&execution.ID,
|
||||||
|
&execution.EventDate,
|
||||||
|
&execution.ResourceOwner,
|
||||||
|
&execution.Sequence,
|
||||||
|
&execution.Targets,
|
||||||
|
&execution.Includes,
|
||||||
|
&count,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
executions = append(executions, execution)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, zerrors.ThrowInternal(err, "QUERY-72xfx5jlj7", "Errors.Query.CloseRows")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Executions{
|
||||||
|
Executions: executions,
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: count,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareExecutionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) (*Execution, error)) {
|
||||||
|
return sq.Select(
|
||||||
|
ExecutionColumnID.identifier(),
|
||||||
|
ExecutionColumnChangeDate.identifier(),
|
||||||
|
ExecutionColumnResourceOwner.identifier(),
|
||||||
|
ExecutionColumnSequence.identifier(),
|
||||||
|
ExecutionColumnTargets.identifier(),
|
||||||
|
ExecutionColumnIncludes.identifier(),
|
||||||
|
).From(executionTable.identifier()).
|
||||||
|
PlaceholderFormat(sq.Dollar),
|
||||||
|
func(row *sql.Row) (*Execution, error) {
|
||||||
|
execution := new(Execution)
|
||||||
|
err := row.Scan(
|
||||||
|
&execution.ID,
|
||||||
|
&execution.EventDate,
|
||||||
|
&execution.ResourceOwner,
|
||||||
|
&execution.Sequence,
|
||||||
|
&execution.Targets,
|
||||||
|
&execution.Includes,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, zerrors.ThrowNotFound(err, "QUERY-qzn1xycesh", "Errors.Execution.NotFound")
|
||||||
|
}
|
||||||
|
return nil, zerrors.ThrowInternal(err, "QUERY-f8sjvm4tb8", "Errors.Internal")
|
||||||
|
}
|
||||||
|
return execution, nil
|
||||||
|
}
|
||||||
|
}
|
253
internal/query/execution_test.go
Normal file
253
internal/query/execution_test.go
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
prepareExecutionsStmt = `SELECT projections.executions.id,` +
|
||||||
|
` projections.executions.change_date,` +
|
||||||
|
` projections.executions.resource_owner,` +
|
||||||
|
` projections.executions.sequence,` +
|
||||||
|
` projections.executions.targets,` +
|
||||||
|
` projections.executions.includes,` +
|
||||||
|
` COUNT(*) OVER ()` +
|
||||||
|
` FROM projections.executions`
|
||||||
|
prepareExecutionsCols = []string{
|
||||||
|
"id",
|
||||||
|
"change_date",
|
||||||
|
"resource_owner",
|
||||||
|
"sequence",
|
||||||
|
"targets",
|
||||||
|
"includes",
|
||||||
|
"count",
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareExecutionStmt = `SELECT projections.executions.id,` +
|
||||||
|
` projections.executions.change_date,` +
|
||||||
|
` projections.executions.resource_owner,` +
|
||||||
|
` projections.executions.sequence,` +
|
||||||
|
` projections.executions.targets,` +
|
||||||
|
` projections.executions.includes` +
|
||||||
|
` FROM projections.executions`
|
||||||
|
prepareExecutionCols = []string{
|
||||||
|
"id",
|
||||||
|
"change_date",
|
||||||
|
"resource_owner",
|
||||||
|
"sequence",
|
||||||
|
"targets",
|
||||||
|
"includes",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ExecutionPrepares(t *testing.T) {
|
||||||
|
type want struct {
|
||||||
|
sqlExpectations sqlExpectation
|
||||||
|
err checkErr
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
prepare interface{}
|
||||||
|
want want
|
||||||
|
object interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "prepareExecutionsQuery no result",
|
||||||
|
prepare: prepareExecutionsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueries(
|
||||||
|
regexp.QuoteMeta(prepareExecutionsStmt),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Executions{Executions: []*Execution{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareExecutionsQuery one result",
|
||||||
|
prepare: prepareExecutionsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueries(
|
||||||
|
regexp.QuoteMeta(prepareExecutionsStmt),
|
||||||
|
prepareExecutionsCols,
|
||||||
|
[][]driver.Value{
|
||||||
|
{
|
||||||
|
"id",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211109),
|
||||||
|
database.TextArray[string]{"target"},
|
||||||
|
database.TextArray[string]{"include"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Executions{
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: 1,
|
||||||
|
},
|
||||||
|
Executions: []*Execution{
|
||||||
|
{
|
||||||
|
ID: "id",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211109,
|
||||||
|
},
|
||||||
|
Targets: database.TextArray[string]{"target"},
|
||||||
|
Includes: database.TextArray[string]{"include"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareExecutionsQuery multiple result",
|
||||||
|
prepare: prepareExecutionsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueries(
|
||||||
|
regexp.QuoteMeta(prepareExecutionsStmt),
|
||||||
|
prepareExecutionsCols,
|
||||||
|
[][]driver.Value{
|
||||||
|
{
|
||||||
|
"id-1",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211109),
|
||||||
|
database.TextArray[string]{"target1"},
|
||||||
|
database.TextArray[string]{"include1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id-2",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211110),
|
||||||
|
database.TextArray[string]{"target2"},
|
||||||
|
database.TextArray[string]{"include2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Executions{
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: 2,
|
||||||
|
},
|
||||||
|
Executions: []*Execution{
|
||||||
|
{
|
||||||
|
ID: "id-1",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211109,
|
||||||
|
},
|
||||||
|
Targets: database.TextArray[string]{"target1"},
|
||||||
|
Includes: database.TextArray[string]{"include1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "id-2",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211110,
|
||||||
|
},
|
||||||
|
Targets: database.TextArray[string]{"target2"},
|
||||||
|
Includes: database.TextArray[string]{"include2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareExecutionsQuery sql err",
|
||||||
|
prepare: prepareExecutionsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueryErr(
|
||||||
|
regexp.QuoteMeta(prepareExecutionsStmt),
|
||||||
|
sql.ErrConnDone,
|
||||||
|
),
|
||||||
|
err: func(err error) (error, bool) {
|
||||||
|
if !errors.Is(err, sql.ErrConnDone) {
|
||||||
|
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||||
|
}
|
||||||
|
return nil, true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
object: (*Execution)(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareExecutionQuery no result",
|
||||||
|
prepare: prepareExecutionQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueriesScanErr(
|
||||||
|
regexp.QuoteMeta(prepareExecutionStmt),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
err: func(err error) (error, bool) {
|
||||||
|
if !zerrors.IsNotFound(err) {
|
||||||
|
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||||
|
}
|
||||||
|
return nil, true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
object: (*Execution)(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareExecutionQuery found",
|
||||||
|
prepare: prepareExecutionQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQuery(
|
||||||
|
regexp.QuoteMeta(prepareExecutionStmt),
|
||||||
|
prepareExecutionCols,
|
||||||
|
[]driver.Value{
|
||||||
|
"id",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211109),
|
||||||
|
database.TextArray[string]{"target"},
|
||||||
|
database.TextArray[string]{"include"},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Execution{
|
||||||
|
ID: "id",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211109,
|
||||||
|
},
|
||||||
|
Targets: database.TextArray[string]{"target"},
|
||||||
|
Includes: database.TextArray[string]{"include"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareExecutionQuery sql err",
|
||||||
|
prepare: prepareExecutionQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueryErr(
|
||||||
|
regexp.QuoteMeta(prepareExecutionStmt),
|
||||||
|
sql.ErrConnDone,
|
||||||
|
),
|
||||||
|
err: func(err error) (error, bool) {
|
||||||
|
if !errors.Is(err, sql.ErrConnDone) {
|
||||||
|
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||||
|
}
|
||||||
|
return nil, true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
object: (*Execution)(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
109
internal/query/generic.go
Normal file
109
internal/query/generic.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
|
"github.com/zitadel/zitadel/internal/database"
|
||||||
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func genericRowsQuery[R any](
|
||||||
|
ctx context.Context,
|
||||||
|
client *database.DB,
|
||||||
|
query sq.SelectBuilder,
|
||||||
|
scan func(rows *sql.Rows) (R, error),
|
||||||
|
) (resp R, err error) {
|
||||||
|
var rnil R
|
||||||
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
|
stmt, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return rnil, zerrors.ThrowInvalidArgument(err, "QUERY-05wf2q36ji", "Errors.Query.InvalidRequest")
|
||||||
|
}
|
||||||
|
err = client.QueryContext(ctx, func(rows *sql.Rows) error {
|
||||||
|
resp, err = scan(rows)
|
||||||
|
return err
|
||||||
|
}, stmt, args...)
|
||||||
|
if err != nil {
|
||||||
|
return rnil, zerrors.ThrowInternal(err, "QUERY-y2u7vctrha", "Errors.Internal")
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func genericRowsQueryWithState[R Stateful](
|
||||||
|
ctx context.Context,
|
||||||
|
client *database.DB,
|
||||||
|
projection table,
|
||||||
|
query sq.SelectBuilder,
|
||||||
|
scan func(rows *sql.Rows) (R, error),
|
||||||
|
) (resp R, err error) {
|
||||||
|
var rnil R
|
||||||
|
resp, err = genericRowsQuery[R](ctx, client, query, scan)
|
||||||
|
if err != nil {
|
||||||
|
return rnil, err
|
||||||
|
}
|
||||||
|
state, err := latestState(ctx, client, projection)
|
||||||
|
if err != nil {
|
||||||
|
return rnil, err
|
||||||
|
}
|
||||||
|
resp.SetState(state)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func latestState(ctx context.Context, client *database.DB, projections ...table) (state *State, err error) {
|
||||||
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
|
query, scan := prepareLatestState(ctx, client)
|
||||||
|
or := make(sq.Or, len(projections))
|
||||||
|
for i, projection := range projections {
|
||||||
|
or[i] = sq.Eq{CurrentStateColProjectionName.identifier(): projection.name}
|
||||||
|
}
|
||||||
|
stmt, args, err := query.
|
||||||
|
Where(or).
|
||||||
|
Where(sq.Eq{CurrentStateColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()}).
|
||||||
|
OrderBy(CurrentStateColEventDate.identifier() + " DESC").
|
||||||
|
ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, zerrors.ThrowInternal(err, "QUERY-5CfX9", "Errors.Query.SQLStatement")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.QueryRowContext(ctx, func(row *sql.Row) error {
|
||||||
|
state, err = scan(row)
|
||||||
|
return err
|
||||||
|
}, stmt, args...)
|
||||||
|
|
||||||
|
return state, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func genericRowQuery[R any](
|
||||||
|
ctx context.Context,
|
||||||
|
client *database.DB,
|
||||||
|
query sq.SelectBuilder,
|
||||||
|
scan func(row *sql.Row) (R, error),
|
||||||
|
) (resp R, err error) {
|
||||||
|
var rnil R
|
||||||
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
|
stmt, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return rnil, zerrors.ThrowInternal(err, "QUERY-s969t763z4", "Errors.Query.SQLStatement")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = client.QueryRowContext(ctx, func(row *sql.Row) error {
|
||||||
|
resp, err = scan(row)
|
||||||
|
return err
|
||||||
|
}, stmt, args...)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func combineToWhereStmt(query sq.SelectBuilder, toQuery func(query sq.SelectBuilder) sq.SelectBuilder, eq interface{}) sq.SelectBuilder {
|
||||||
|
return toQuery(query).Where(eq)
|
||||||
|
}
|
@@ -99,7 +99,7 @@ func TestActionProjection_reduces(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
action.ChangedEventType,
|
action.DeactivatedEventType,
|
||||||
action.AggregateType,
|
action.AggregateType,
|
||||||
[]byte(`{}`),
|
[]byte(`{}`),
|
||||||
),
|
),
|
||||||
@@ -131,7 +131,7 @@ func TestActionProjection_reduces(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
action.ChangedEventType,
|
action.ReactivatedEventType,
|
||||||
action.AggregateType,
|
action.AggregateType,
|
||||||
[]byte(`{}`),
|
[]byte(`{}`),
|
||||||
),
|
),
|
||||||
@@ -163,7 +163,7 @@ func TestActionProjection_reduces(t *testing.T) {
|
|||||||
args: args{
|
args: args{
|
||||||
event: getEvent(
|
event: getEvent(
|
||||||
testEvent(
|
testEvent(
|
||||||
action.ChangedEventType,
|
action.RemovedEventType,
|
||||||
action.AggregateType,
|
action.AggregateType,
|
||||||
[]byte(`{}`),
|
[]byte(`{}`),
|
||||||
),
|
),
|
||||||
|
109
internal/query/projection/execution.go
Normal file
109
internal/query/projection/execution.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package projection
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
|
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
|
exec "github.com/zitadel/zitadel/internal/repository/execution"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ExecutionTable = "projections.executions"
|
||||||
|
ExecutionIDCol = "id"
|
||||||
|
ExecutionCreationDateCol = "creation_date"
|
||||||
|
ExecutionChangeDateCol = "change_date"
|
||||||
|
ExecutionResourceOwnerCol = "resource_owner"
|
||||||
|
ExecutionInstanceIDCol = "instance_id"
|
||||||
|
ExecutionSequenceCol = "sequence"
|
||||||
|
ExecutionTargetsCol = "targets"
|
||||||
|
ExecutionIncludesCol = "includes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type executionProjection struct{}
|
||||||
|
|
||||||
|
func newExecutionProjection(ctx context.Context, config handler.Config) *handler.Handler {
|
||||||
|
return handler.NewHandler(ctx, &config, new(executionProjection))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*executionProjection) Name() string {
|
||||||
|
return ExecutionTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*executionProjection) Init() *old_handler.Check {
|
||||||
|
return handler.NewTableCheck(
|
||||||
|
handler.NewTable([]*handler.InitColumn{
|
||||||
|
handler.NewColumn(ExecutionIDCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(ExecutionCreationDateCol, handler.ColumnTypeTimestamp),
|
||||||
|
handler.NewColumn(ExecutionChangeDateCol, handler.ColumnTypeTimestamp),
|
||||||
|
handler.NewColumn(ExecutionResourceOwnerCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(ExecutionInstanceIDCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(ExecutionSequenceCol, handler.ColumnTypeInt64),
|
||||||
|
handler.NewColumn(ExecutionTargetsCol, handler.ColumnTypeTextArray, handler.Nullable()),
|
||||||
|
handler.NewColumn(ExecutionIncludesCol, handler.ColumnTypeTextArray, handler.Nullable()),
|
||||||
|
},
|
||||||
|
handler.NewPrimaryKey(ExecutionInstanceIDCol, ExecutionIDCol),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *executionProjection) Reducers() []handler.AggregateReducer {
|
||||||
|
return []handler.AggregateReducer{
|
||||||
|
{
|
||||||
|
Aggregate: exec.AggregateType,
|
||||||
|
EventReducers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: exec.SetEventType,
|
||||||
|
Reduce: p.reduceExecutionSet,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: exec.RemovedEventType,
|
||||||
|
Reduce: p.reduceExecutionRemoved,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Aggregate: instance.AggregateType,
|
||||||
|
EventReducers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: instance.InstanceRemovedEventType,
|
||||||
|
Reduce: reduceInstanceRemovedHelper(ExecutionInstanceIDCol),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *executionProjection) reduceExecutionSet(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*exec.SetEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
columns := []handler.Column{
|
||||||
|
handler.NewCol(ExecutionInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
handler.NewCol(ExecutionIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCol(ExecutionResourceOwnerCol, e.Aggregate().ResourceOwner),
|
||||||
|
handler.NewCol(ExecutionCreationDateCol, handler.OnlySetValueOnInsert(ExecutionTable, e.CreationDate())),
|
||||||
|
handler.NewCol(ExecutionChangeDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(ExecutionSequenceCol, e.Sequence()),
|
||||||
|
handler.NewCol(ExecutionTargetsCol, e.Targets),
|
||||||
|
handler.NewCol(ExecutionIncludesCol, e.Includes),
|
||||||
|
}
|
||||||
|
return handler.NewUpsertStatement(e, columns[0:2], columns), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *executionProjection) reduceExecutionRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*exec.RemovedEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return handler.NewDeleteStatement(
|
||||||
|
e,
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(ExecutionInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
handler.NewCond(ExecutionIDCol, e.Aggregate().ID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
129
internal/query/projection/execution_test.go
Normal file
129
internal/query/projection/execution_test.go
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package projection
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
|
exec "github.com/zitadel/zitadel/internal/repository/execution"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExecutionProjection_reduces(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
event func(t *testing.T) eventstore.Event
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
reduce func(event eventstore.Event) (*handler.Statement, error)
|
||||||
|
want wantReduce
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "reduceExecutionSet",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
exec.SetEventType,
|
||||||
|
exec.AggregateType,
|
||||||
|
[]byte(`{"targets": ["target"], "includes": ["include"]}`),
|
||||||
|
),
|
||||||
|
eventstore.GenericEventMapper[exec.SetEvent],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: (&executionProjection{}).reduceExecutionSet,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("execution"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "INSERT INTO projections.executions (instance_id, id, resource_owner, creation_date, change_date, sequence, targets, includes) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) ON CONFLICT (instance_id, id) DO UPDATE SET (resource_owner, creation_date, change_date, sequence, targets, includes) = (EXCLUDED.resource_owner, projections.executions.creation_date, EXCLUDED.change_date, EXCLUDED.sequence, EXCLUDED.targets, EXCLUDED.includes)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"instance-id",
|
||||||
|
"agg-id",
|
||||||
|
"ro-id",
|
||||||
|
anyArg{},
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
[]string{"target"},
|
||||||
|
[]string{"include"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceExecutionRemoved",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
exec.RemovedEventType,
|
||||||
|
exec.AggregateType,
|
||||||
|
[]byte(`{}`),
|
||||||
|
),
|
||||||
|
eventstore.GenericEventMapper[exec.RemovedEvent],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: (&executionProjection{}).reduceExecutionRemoved,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("execution"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM projections.executions WHERE (instance_id = $1) AND (id = $2)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"instance-id",
|
||||||
|
"agg-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceInstanceRemoved",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
instance.InstanceRemovedEventType,
|
||||||
|
instance.AggregateType,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
instance.InstanceRemovedEventMapper,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: reduceInstanceRemovedHelper(ExecutionInstanceIDCol),
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("instance"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM projections.executions WHERE (instance_id = $1)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"agg-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
event := baseEvent(t)
|
||||||
|
got, err := tt.reduce(event)
|
||||||
|
if ok := zerrors.IsErrorInvalidArgument(err); !ok {
|
||||||
|
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
event = tt.args.event(t)
|
||||||
|
got, err = tt.reduce(event)
|
||||||
|
assertReduce(t, got, err, ExecutionTable, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -74,6 +74,8 @@ var (
|
|||||||
RestrictionsProjection *handler.Handler
|
RestrictionsProjection *handler.Handler
|
||||||
SystemFeatureProjection *handler.Handler
|
SystemFeatureProjection *handler.Handler
|
||||||
InstanceFeatureProjection *handler.Handler
|
InstanceFeatureProjection *handler.Handler
|
||||||
|
TargetProjection *handler.Handler
|
||||||
|
ExecutionProjection *handler.Handler
|
||||||
)
|
)
|
||||||
|
|
||||||
type projection interface {
|
type projection interface {
|
||||||
@@ -152,6 +154,8 @@ func Create(ctx context.Context, sqlClient *database.DB, es handler.EventStore,
|
|||||||
RestrictionsProjection = newRestrictionsProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["restrictions"]))
|
RestrictionsProjection = newRestrictionsProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["restrictions"]))
|
||||||
SystemFeatureProjection = newSystemFeatureProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["system_features"]))
|
SystemFeatureProjection = newSystemFeatureProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["system_features"]))
|
||||||
InstanceFeatureProjection = newInstanceFeatureProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["instance_features"]))
|
InstanceFeatureProjection = newInstanceFeatureProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["instance_features"]))
|
||||||
|
TargetProjection = newTargetProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["targets"]))
|
||||||
|
ExecutionProjection = newExecutionProjection(ctx, applyCustomConfig(projectionConfig, config.Customizations["executions"]))
|
||||||
newProjectionsList()
|
newProjectionsList()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -263,5 +267,7 @@ func newProjectionsList() {
|
|||||||
RestrictionsProjection,
|
RestrictionsProjection,
|
||||||
SystemFeatureProjection,
|
SystemFeatureProjection,
|
||||||
InstanceFeatureProjection,
|
InstanceFeatureProjection,
|
||||||
|
ExecutionProjection,
|
||||||
|
TargetProjection,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
165
internal/query/projection/target.go
Normal file
165
internal/query/projection/target.go
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
package projection
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
|
old_handler "github.com/zitadel/zitadel/internal/eventstore/handler"
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/target"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TargetTable = "projections.targets"
|
||||||
|
TargetIDCol = "id"
|
||||||
|
TargetCreationDateCol = "creation_date"
|
||||||
|
TargetChangeDateCol = "change_date"
|
||||||
|
TargetResourceOwnerCol = "resource_owner"
|
||||||
|
TargetInstanceIDCol = "instance_id"
|
||||||
|
TargetSequenceCol = "sequence"
|
||||||
|
TargetNameCol = "name"
|
||||||
|
TargetTargetType = "target_type"
|
||||||
|
TargetURLCol = "url"
|
||||||
|
TargetTimeoutCol = "timeout"
|
||||||
|
TargetAsyncCol = "async"
|
||||||
|
TargetInterruptOnErrorCol = "interrupt_on_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
type targetProjection struct{}
|
||||||
|
|
||||||
|
func newTargetProjection(ctx context.Context, config handler.Config) *handler.Handler {
|
||||||
|
return handler.NewHandler(ctx, &config, new(targetProjection))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*targetProjection) Name() string {
|
||||||
|
return TargetTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*targetProjection) Init() *old_handler.Check {
|
||||||
|
return handler.NewTableCheck(
|
||||||
|
handler.NewTable([]*handler.InitColumn{
|
||||||
|
handler.NewColumn(TargetIDCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(TargetCreationDateCol, handler.ColumnTypeTimestamp),
|
||||||
|
handler.NewColumn(TargetChangeDateCol, handler.ColumnTypeTimestamp),
|
||||||
|
handler.NewColumn(TargetResourceOwnerCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(TargetInstanceIDCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(TargetTargetType, handler.ColumnTypeEnum),
|
||||||
|
handler.NewColumn(TargetSequenceCol, handler.ColumnTypeInt64),
|
||||||
|
handler.NewColumn(TargetNameCol, handler.ColumnTypeText),
|
||||||
|
handler.NewColumn(TargetURLCol, handler.ColumnTypeText, handler.Default("")),
|
||||||
|
handler.NewColumn(TargetTimeoutCol, handler.ColumnTypeInt64, handler.Default(0)),
|
||||||
|
handler.NewColumn(TargetAsyncCol, handler.ColumnTypeBool, handler.Default(false)),
|
||||||
|
handler.NewColumn(TargetInterruptOnErrorCol, handler.ColumnTypeBool, handler.Default(false)),
|
||||||
|
},
|
||||||
|
handler.NewPrimaryKey(TargetInstanceIDCol, TargetIDCol),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *targetProjection) Reducers() []handler.AggregateReducer {
|
||||||
|
return []handler.AggregateReducer{
|
||||||
|
{
|
||||||
|
Aggregate: target.AggregateType,
|
||||||
|
EventReducers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: target.AddedEventType,
|
||||||
|
Reduce: p.reduceTargetAdded,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: target.ChangedEventType,
|
||||||
|
Reduce: p.reduceTargetChanged,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Event: target.RemovedEventType,
|
||||||
|
Reduce: p.reduceTargetRemoved,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Aggregate: instance.AggregateType,
|
||||||
|
EventReducers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: instance.InstanceRemovedEventType,
|
||||||
|
Reduce: reduceInstanceRemovedHelper(TargetInstanceIDCol),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *targetProjection) reduceTargetAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*target.AddedEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return handler.NewCreateStatement(
|
||||||
|
e,
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(TargetInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
handler.NewCol(TargetResourceOwnerCol, e.Aggregate().ResourceOwner),
|
||||||
|
handler.NewCol(TargetIDCol, e.Aggregate().ID),
|
||||||
|
handler.NewCol(TargetCreationDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(TargetChangeDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(TargetSequenceCol, e.Sequence()),
|
||||||
|
handler.NewCol(TargetNameCol, e.Name),
|
||||||
|
handler.NewCol(TargetURLCol, e.URL),
|
||||||
|
handler.NewCol(TargetTargetType, e.TargetType),
|
||||||
|
handler.NewCol(TargetTimeoutCol, e.Timeout),
|
||||||
|
handler.NewCol(TargetAsyncCol, e.Async),
|
||||||
|
handler.NewCol(TargetInterruptOnErrorCol, e.InterruptOnError),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *targetProjection) reduceTargetChanged(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*target.ChangedEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
values := []handler.Column{
|
||||||
|
handler.NewCol(TargetChangeDateCol, e.CreationDate()),
|
||||||
|
handler.NewCol(TargetSequenceCol, e.Sequence()),
|
||||||
|
handler.NewCol(TargetResourceOwnerCol, e.Aggregate().ResourceOwner),
|
||||||
|
}
|
||||||
|
if e.Name != nil {
|
||||||
|
values = append(values, handler.NewCol(TargetNameCol, *e.Name))
|
||||||
|
}
|
||||||
|
if e.TargetType != nil {
|
||||||
|
values = append(values, handler.NewCol(TargetTargetType, *e.TargetType))
|
||||||
|
}
|
||||||
|
if e.URL != nil {
|
||||||
|
values = append(values, handler.NewCol(TargetURLCol, *e.URL))
|
||||||
|
}
|
||||||
|
if e.Timeout != nil {
|
||||||
|
values = append(values, handler.NewCol(TargetTimeoutCol, *e.Timeout))
|
||||||
|
}
|
||||||
|
if e.Async != nil {
|
||||||
|
values = append(values, handler.NewCol(TargetAsyncCol, *e.Async))
|
||||||
|
}
|
||||||
|
if e.InterruptOnError != nil {
|
||||||
|
values = append(values, handler.NewCol(TargetInterruptOnErrorCol, *e.InterruptOnError))
|
||||||
|
}
|
||||||
|
return handler.NewUpdateStatement(
|
||||||
|
e,
|
||||||
|
values,
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(TargetInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
handler.NewCond(TargetIDCol, e.Aggregate().ID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *targetProjection) reduceTargetRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*target.RemovedEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return handler.NewDeleteStatement(
|
||||||
|
e,
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(TargetInstanceIDCol, e.Aggregate().InstanceID),
|
||||||
|
handler.NewCond(TargetIDCol, e.Aggregate().ID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
173
internal/query/projection/target_test.go
Normal file
173
internal/query/projection/target_test.go
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
package projection
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/target"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTargetProjection_reduces(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
event func(t *testing.T) eventstore.Event
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
reduce func(event eventstore.Event) (*handler.Statement, error)
|
||||||
|
want wantReduce
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "reduceTargetAdded",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
target.AddedEventType,
|
||||||
|
target.AggregateType,
|
||||||
|
[]byte(`{"name": "name", "targetType":0, "url":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true}`),
|
||||||
|
),
|
||||||
|
eventstore.GenericEventMapper[target.AddedEvent],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: (&targetProjection{}).reduceTargetAdded,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("target"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "INSERT INTO projections.targets (instance_id, resource_owner, id, creation_date, change_date, sequence, name, url, target_type, timeout, async, interrupt_on_error) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"instance-id",
|
||||||
|
"ro-id",
|
||||||
|
"agg-id",
|
||||||
|
anyArg{},
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"name",
|
||||||
|
"https://example.com",
|
||||||
|
domain.TargetTypeWebhook,
|
||||||
|
3 * time.Second,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceTargetChanged",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
target.ChangedEventType,
|
||||||
|
target.AggregateType,
|
||||||
|
[]byte(`{"name": "name2", "targetType":0, "url":"https://example.com", "timeout": 3000000000, "async": true, "interruptOnError": true}`),
|
||||||
|
),
|
||||||
|
eventstore.GenericEventMapper[target.ChangedEvent],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: (&targetProjection{}).reduceTargetChanged,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("target"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.targets SET (change_date, sequence, resource_owner, name, target_type, url, timeout, async, interrupt_on_error) = ($1, $2, $3, $4, $5, $6, $7, $8, $9) WHERE (instance_id = $10) AND (id = $11)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
uint64(15),
|
||||||
|
"ro-id",
|
||||||
|
"name2",
|
||||||
|
domain.TargetTypeWebhook,
|
||||||
|
"https://example.com",
|
||||||
|
3 * time.Second,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
"instance-id",
|
||||||
|
"agg-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceTargetRemoved",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
target.RemovedEventType,
|
||||||
|
target.AggregateType,
|
||||||
|
[]byte(`{}`),
|
||||||
|
),
|
||||||
|
eventstore.GenericEventMapper[target.RemovedEvent],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: (&targetProjection{}).reduceTargetRemoved,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("target"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM projections.targets WHERE (instance_id = $1) AND (id = $2)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"instance-id",
|
||||||
|
"agg-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "reduceInstanceRemoved",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(
|
||||||
|
testEvent(
|
||||||
|
instance.InstanceRemovedEventType,
|
||||||
|
instance.AggregateType,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
instance.InstanceRemovedEventMapper,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
reduce: reduceInstanceRemovedHelper(TargetInstanceIDCol),
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("instance"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "DELETE FROM projections.targets WHERE (instance_id = $1)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
"agg-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
event := baseEvent(t)
|
||||||
|
got, err := tt.reduce(event)
|
||||||
|
if ok := zerrors.IsErrorInvalidArgument(err); !ok {
|
||||||
|
t.Errorf("no wrong event mapping: %v, got: %v", err, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
event = tt.args.event(t)
|
||||||
|
got, err = tt.reduce(event)
|
||||||
|
assertReduce(t, got, err, TargetTable, tt.want)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
219
internal/query/target.go
Normal file
219
internal/query/target.go
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sq "github.com/Masterminds/squirrel"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/query/projection"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
targetTable = table{
|
||||||
|
name: projection.TargetTable,
|
||||||
|
instanceIDCol: projection.TargetInstanceIDCol,
|
||||||
|
}
|
||||||
|
TargetColumnID = Column{
|
||||||
|
name: projection.TargetIDCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnCreationDate = Column{
|
||||||
|
name: projection.TargetCreationDateCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnChangeDate = Column{
|
||||||
|
name: projection.TargetChangeDateCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnResourceOwner = Column{
|
||||||
|
name: projection.TargetResourceOwnerCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnInstanceID = Column{
|
||||||
|
name: projection.TargetInstanceIDCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnSequence = Column{
|
||||||
|
name: projection.TargetSequenceCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnName = Column{
|
||||||
|
name: projection.TargetNameCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnTargetType = Column{
|
||||||
|
name: projection.TargetTargetType,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnURL = Column{
|
||||||
|
name: projection.TargetURLCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnTimeout = Column{
|
||||||
|
name: projection.TargetTimeoutCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnAsync = Column{
|
||||||
|
name: projection.TargetAsyncCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
TargetColumnInterruptOnError = Column{
|
||||||
|
name: projection.TargetInterruptOnErrorCol,
|
||||||
|
table: targetTable,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Targets struct {
|
||||||
|
SearchResponse
|
||||||
|
Targets []*Target
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Targets) SetState(s *State) {
|
||||||
|
t.State = s
|
||||||
|
}
|
||||||
|
|
||||||
|
type Target struct {
|
||||||
|
ID string
|
||||||
|
domain.ObjectDetails
|
||||||
|
|
||||||
|
Name string
|
||||||
|
TargetType domain.TargetType
|
||||||
|
URL string
|
||||||
|
Timeout time.Duration
|
||||||
|
Async bool
|
||||||
|
InterruptOnError bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type TargetSearchQueries struct {
|
||||||
|
SearchRequest
|
||||||
|
Queries []SearchQuery
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *TargetSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||||
|
query = q.SearchRequest.toQuery(query)
|
||||||
|
for _, q := range q.Queries {
|
||||||
|
query = q.toQuery(query)
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) SearchTargets(ctx context.Context, queries *TargetSearchQueries) (targets *Targets, err error) {
|
||||||
|
eq := sq.Eq{
|
||||||
|
TargetColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||||
|
}
|
||||||
|
query, scan := prepareTargetsQuery(ctx, q.client)
|
||||||
|
return genericRowsQueryWithState[*Targets](ctx, q.client, targetTable, combineToWhereStmt(query, queries.toQuery, eq), scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetTargetByID(ctx context.Context, id string) (target *Target, err error) {
|
||||||
|
eq := sq.Eq{
|
||||||
|
TargetColumnID.identifier(): id,
|
||||||
|
TargetColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||||
|
}
|
||||||
|
query, scan := prepareTargetQuery(ctx, q.client)
|
||||||
|
return genericRowQuery[*Target](ctx, q.client, query.Where(eq), scan)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTargetNameSearchQuery(method TextComparison, value string) (SearchQuery, error) {
|
||||||
|
return NewTextQuery(TargetColumnName, value, method)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTargetInIDsSearchQuery(values []string) (SearchQuery, error) {
|
||||||
|
return NewInTextQuery(TargetColumnID, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareTargetsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*Targets, error)) {
|
||||||
|
return sq.Select(
|
||||||
|
TargetColumnID.identifier(),
|
||||||
|
TargetColumnChangeDate.identifier(),
|
||||||
|
TargetColumnResourceOwner.identifier(),
|
||||||
|
TargetColumnSequence.identifier(),
|
||||||
|
TargetColumnName.identifier(),
|
||||||
|
TargetColumnTargetType.identifier(),
|
||||||
|
TargetColumnTimeout.identifier(),
|
||||||
|
TargetColumnURL.identifier(),
|
||||||
|
TargetColumnAsync.identifier(),
|
||||||
|
TargetColumnInterruptOnError.identifier(),
|
||||||
|
countColumn.identifier(),
|
||||||
|
).From(targetTable.identifier()).
|
||||||
|
PlaceholderFormat(sq.Dollar),
|
||||||
|
func(rows *sql.Rows) (*Targets, error) {
|
||||||
|
targets := make([]*Target, 0)
|
||||||
|
var count uint64
|
||||||
|
for rows.Next() {
|
||||||
|
target := new(Target)
|
||||||
|
err := rows.Scan(
|
||||||
|
&target.ID,
|
||||||
|
&target.EventDate,
|
||||||
|
&target.ResourceOwner,
|
||||||
|
&target.Sequence,
|
||||||
|
&target.Name,
|
||||||
|
&target.TargetType,
|
||||||
|
&target.Timeout,
|
||||||
|
&target.URL,
|
||||||
|
&target.Async,
|
||||||
|
&target.InterruptOnError,
|
||||||
|
&count,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
targets = append(targets, target)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, zerrors.ThrowInternal(err, "QUERY-fzwi6cgxos", "Errors.Query.CloseRows")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Targets{
|
||||||
|
Targets: targets,
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: count,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareTargetQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(row *sql.Row) (*Target, error)) {
|
||||||
|
return sq.Select(
|
||||||
|
TargetColumnID.identifier(),
|
||||||
|
TargetColumnChangeDate.identifier(),
|
||||||
|
TargetColumnResourceOwner.identifier(),
|
||||||
|
TargetColumnSequence.identifier(),
|
||||||
|
TargetColumnName.identifier(),
|
||||||
|
TargetColumnTargetType.identifier(),
|
||||||
|
TargetColumnTimeout.identifier(),
|
||||||
|
TargetColumnURL.identifier(),
|
||||||
|
TargetColumnAsync.identifier(),
|
||||||
|
TargetColumnInterruptOnError.identifier(),
|
||||||
|
).From(targetTable.identifier()).
|
||||||
|
PlaceholderFormat(sq.Dollar),
|
||||||
|
func(row *sql.Row) (*Target, error) {
|
||||||
|
target := new(Target)
|
||||||
|
err := row.Scan(
|
||||||
|
&target.ID,
|
||||||
|
&target.EventDate,
|
||||||
|
&target.ResourceOwner,
|
||||||
|
&target.Sequence,
|
||||||
|
&target.Name,
|
||||||
|
&target.TargetType,
|
||||||
|
&target.Timeout,
|
||||||
|
&target.URL,
|
||||||
|
&target.Async,
|
||||||
|
&target.InterruptOnError,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, zerrors.ThrowNotFound(err, "QUERY-hj5oaniyrz", "Errors.Target.NotFound")
|
||||||
|
}
|
||||||
|
return nil, zerrors.ThrowInternal(err, "QUERY-5qhc19sc49", "Errors.Internal")
|
||||||
|
}
|
||||||
|
return target, nil
|
||||||
|
}
|
||||||
|
}
|
301
internal/query/target_test.go
Normal file
301
internal/query/target_test.go
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
package query
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
prepareTargetsStmt = `SELECT projections.targets.id,` +
|
||||||
|
` projections.targets.change_date,` +
|
||||||
|
` projections.targets.resource_owner,` +
|
||||||
|
` projections.targets.sequence,` +
|
||||||
|
` projections.targets.name,` +
|
||||||
|
` projections.targets.target_type,` +
|
||||||
|
` projections.targets.timeout,` +
|
||||||
|
` projections.targets.url,` +
|
||||||
|
` projections.targets.async,` +
|
||||||
|
` projections.targets.interrupt_on_error,` +
|
||||||
|
` COUNT(*) OVER ()` +
|
||||||
|
` FROM projections.targets`
|
||||||
|
prepareTargetsCols = []string{
|
||||||
|
"id",
|
||||||
|
"change_date",
|
||||||
|
"resource_owner",
|
||||||
|
"sequence",
|
||||||
|
"name",
|
||||||
|
"target_type",
|
||||||
|
"timeout",
|
||||||
|
"url",
|
||||||
|
"async",
|
||||||
|
"interrupt_on_error",
|
||||||
|
"count",
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareTargetStmt = `SELECT projections.targets.id,` +
|
||||||
|
` projections.targets.change_date,` +
|
||||||
|
` projections.targets.resource_owner,` +
|
||||||
|
` projections.targets.sequence,` +
|
||||||
|
` projections.targets.name,` +
|
||||||
|
` projections.targets.target_type,` +
|
||||||
|
` projections.targets.timeout,` +
|
||||||
|
` projections.targets.url,` +
|
||||||
|
` projections.targets.async,` +
|
||||||
|
` projections.targets.interrupt_on_error` +
|
||||||
|
` FROM projections.targets`
|
||||||
|
prepareTargetCols = []string{
|
||||||
|
"id",
|
||||||
|
"change_date",
|
||||||
|
"resource_owner",
|
||||||
|
"sequence",
|
||||||
|
"name",
|
||||||
|
"target_type",
|
||||||
|
"timeout",
|
||||||
|
"url",
|
||||||
|
"async",
|
||||||
|
"interrupt_on_error",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_TargetPrepares(t *testing.T) {
|
||||||
|
type want struct {
|
||||||
|
sqlExpectations sqlExpectation
|
||||||
|
err checkErr
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
prepare interface{}
|
||||||
|
want want
|
||||||
|
object interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "prepareTargetsQuery no result",
|
||||||
|
prepare: prepareTargetsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueries(
|
||||||
|
regexp.QuoteMeta(prepareTargetsStmt),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Targets{Targets: []*Target{}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareTargetsQuery one result",
|
||||||
|
prepare: prepareTargetsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueries(
|
||||||
|
regexp.QuoteMeta(prepareTargetsStmt),
|
||||||
|
prepareTargetsCols,
|
||||||
|
[][]driver.Value{
|
||||||
|
{
|
||||||
|
"id",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211109),
|
||||||
|
"target-name",
|
||||||
|
domain.TargetTypeWebhook,
|
||||||
|
1 * time.Second,
|
||||||
|
"https://example.com",
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Targets{
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: 1,
|
||||||
|
},
|
||||||
|
Targets: []*Target{
|
||||||
|
{
|
||||||
|
ID: "id",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211109,
|
||||||
|
},
|
||||||
|
Name: "target-name",
|
||||||
|
TargetType: domain.TargetTypeWebhook,
|
||||||
|
Timeout: 1 * time.Second,
|
||||||
|
URL: "https://example.com",
|
||||||
|
Async: true,
|
||||||
|
InterruptOnError: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareTargetsQuery multiple result",
|
||||||
|
prepare: prepareTargetsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueries(
|
||||||
|
regexp.QuoteMeta(prepareTargetsStmt),
|
||||||
|
prepareTargetsCols,
|
||||||
|
[][]driver.Value{
|
||||||
|
{
|
||||||
|
"id-1",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211109),
|
||||||
|
"target-name1",
|
||||||
|
domain.TargetTypeWebhook,
|
||||||
|
1 * time.Second,
|
||||||
|
"https://example.com",
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id-2",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211110),
|
||||||
|
"target-name2",
|
||||||
|
domain.TargetTypeWebhook,
|
||||||
|
1 * time.Second,
|
||||||
|
"https://example.com",
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Targets{
|
||||||
|
SearchResponse: SearchResponse{
|
||||||
|
Count: 2,
|
||||||
|
},
|
||||||
|
Targets: []*Target{
|
||||||
|
{
|
||||||
|
ID: "id-1",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211109,
|
||||||
|
},
|
||||||
|
Name: "target-name1",
|
||||||
|
TargetType: domain.TargetTypeWebhook,
|
||||||
|
Timeout: 1 * time.Second,
|
||||||
|
URL: "https://example.com",
|
||||||
|
Async: true,
|
||||||
|
InterruptOnError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "id-2",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211110,
|
||||||
|
},
|
||||||
|
Name: "target-name2",
|
||||||
|
TargetType: domain.TargetTypeWebhook,
|
||||||
|
Timeout: 1 * time.Second,
|
||||||
|
URL: "https://example.com",
|
||||||
|
Async: false,
|
||||||
|
InterruptOnError: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareTargetsQuery sql err",
|
||||||
|
prepare: prepareTargetsQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueryErr(
|
||||||
|
regexp.QuoteMeta(prepareTargetsStmt),
|
||||||
|
sql.ErrConnDone,
|
||||||
|
),
|
||||||
|
err: func(err error) (error, bool) {
|
||||||
|
if !errors.Is(err, sql.ErrConnDone) {
|
||||||
|
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||||
|
}
|
||||||
|
return nil, true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
object: (*Target)(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareTargetQuery no result",
|
||||||
|
prepare: prepareTargetQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueriesScanErr(
|
||||||
|
regexp.QuoteMeta(prepareTargetStmt),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
err: func(err error) (error, bool) {
|
||||||
|
if !zerrors.IsNotFound(err) {
|
||||||
|
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||||
|
}
|
||||||
|
return nil, true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
object: (*Target)(nil),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareTargetQuery found",
|
||||||
|
prepare: prepareTargetQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQuery(
|
||||||
|
regexp.QuoteMeta(prepareTargetStmt),
|
||||||
|
prepareTargetCols,
|
||||||
|
[]driver.Value{
|
||||||
|
"id",
|
||||||
|
testNow,
|
||||||
|
"ro",
|
||||||
|
uint64(20211109),
|
||||||
|
"target-name",
|
||||||
|
domain.TargetTypeWebhook,
|
||||||
|
1 * time.Second,
|
||||||
|
"https://example.com",
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
object: &Target{
|
||||||
|
ID: "id",
|
||||||
|
ObjectDetails: domain.ObjectDetails{
|
||||||
|
EventDate: testNow,
|
||||||
|
ResourceOwner: "ro",
|
||||||
|
Sequence: 20211109,
|
||||||
|
},
|
||||||
|
Name: "target-name",
|
||||||
|
TargetType: domain.TargetTypeWebhook,
|
||||||
|
Timeout: 1 * time.Second,
|
||||||
|
URL: "https://example.com",
|
||||||
|
Async: true,
|
||||||
|
InterruptOnError: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "prepareTargetQuery sql err",
|
||||||
|
prepare: prepareTargetQuery,
|
||||||
|
want: want{
|
||||||
|
sqlExpectations: mockQueryErr(
|
||||||
|
regexp.QuoteMeta(prepareTargetStmt),
|
||||||
|
sql.ErrConnDone,
|
||||||
|
),
|
||||||
|
err: func(err error) (error, bool) {
|
||||||
|
if !errors.Is(err, sql.ErrConnDone) {
|
||||||
|
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||||
|
}
|
||||||
|
return nil, true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
object: (*Target)(nil),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err, defaultPrepareArgs...)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,6 @@ package execution
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,9 +15,8 @@ const (
|
|||||||
type SetEvent struct {
|
type SetEvent struct {
|
||||||
*eventstore.BaseEvent `json:"-"`
|
*eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
ExecutionType domain.ExecutionType `json:"executionType"`
|
Targets []string `json:"targets"`
|
||||||
Targets []string `json:"targets"`
|
Includes []string `json:"includes"`
|
||||||
Includes []string `json:"includes"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *SetEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
func (e *SetEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||||
|
@@ -3,7 +3,7 @@ package target
|
|||||||
import "github.com/zitadel/zitadel/internal/eventstore"
|
import "github.com/zitadel/zitadel/internal/eventstore"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
eventstore.RegisterFilterEventMapper(AggregateType, AddedEventType, AddedEventMapper)
|
eventstore.RegisterFilterEventMapper(AggregateType, AddedEventType, eventstore.GenericEventMapper[AddedEvent])
|
||||||
eventstore.RegisterFilterEventMapper(AggregateType, ChangedEventType, ChangedEventMapper)
|
eventstore.RegisterFilterEventMapper(AggregateType, ChangedEventType, eventstore.GenericEventMapper[ChangedEvent])
|
||||||
eventstore.RegisterFilterEventMapper(AggregateType, RemovedEventType, RemovedEventMapper)
|
eventstore.RegisterFilterEventMapper(AggregateType, RemovedEventType, eventstore.GenericEventMapper[RemovedEvent])
|
||||||
}
|
}
|
||||||
|
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -17,7 +16,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AddedEvent struct {
|
type AddedEvent struct {
|
||||||
*eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
TargetType domain.TargetType `json:"targetType"`
|
TargetType domain.TargetType `json:"targetType"`
|
||||||
@@ -28,7 +27,7 @@ type AddedEvent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *AddedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
func (e *AddedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||||
e.BaseEvent = b
|
e.BaseEvent = *b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *AddedEvent) Payload() any {
|
func (e *AddedEvent) Payload() any {
|
||||||
@@ -50,26 +49,14 @@ func NewAddedEvent(
|
|||||||
interruptOnError bool,
|
interruptOnError bool,
|
||||||
) *AddedEvent {
|
) *AddedEvent {
|
||||||
return &AddedEvent{
|
return &AddedEvent{
|
||||||
eventstore.NewBaseEventForPush(
|
*eventstore.NewBaseEventForPush(
|
||||||
ctx, aggregate, AddedEventType,
|
ctx, aggregate, AddedEventType,
|
||||||
),
|
),
|
||||||
name, targetType, url, timeout, async, interruptOnError}
|
name, targetType, url, timeout, async, interruptOnError}
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddedEventMapper(event eventstore.Event) (eventstore.Event, error) {
|
|
||||||
added := &AddedEvent{
|
|
||||||
BaseEvent: eventstore.BaseEventFromRepo(event),
|
|
||||||
}
|
|
||||||
err := event.Unmarshal(added)
|
|
||||||
if err != nil {
|
|
||||||
return nil, zerrors.ThrowInternal(err, "TARGET-fx8f8yfbn1", "unable to unmarshal target added")
|
|
||||||
}
|
|
||||||
|
|
||||||
return added, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChangedEvent struct {
|
type ChangedEvent struct {
|
||||||
*eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
Name *string `json:"name,omitempty"`
|
Name *string `json:"name,omitempty"`
|
||||||
TargetType *domain.TargetType `json:"targetType,omitempty"`
|
TargetType *domain.TargetType `json:"targetType,omitempty"`
|
||||||
@@ -81,6 +68,10 @@ type ChangedEvent struct {
|
|||||||
oldName string
|
oldName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *ChangedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||||
|
e.BaseEvent = *b
|
||||||
|
}
|
||||||
|
|
||||||
func (e *ChangedEvent) Payload() interface{} {
|
func (e *ChangedEvent) Payload() interface{} {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
@@ -101,7 +92,7 @@ func NewChangedEvent(
|
|||||||
changes []Changes,
|
changes []Changes,
|
||||||
) *ChangedEvent {
|
) *ChangedEvent {
|
||||||
changeEvent := &ChangedEvent{
|
changeEvent := &ChangedEvent{
|
||||||
BaseEvent: eventstore.NewBaseEventForPush(
|
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||||
ctx,
|
ctx,
|
||||||
aggregate,
|
aggregate,
|
||||||
ChangedEventType,
|
ChangedEventType,
|
||||||
@@ -152,26 +143,14 @@ func ChangeInterruptOnError(interruptOnError bool) func(event *ChangedEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChangedEventMapper(event eventstore.Event) (eventstore.Event, error) {
|
|
||||||
changed := &ChangedEvent{
|
|
||||||
BaseEvent: eventstore.BaseEventFromRepo(event),
|
|
||||||
}
|
|
||||||
err := event.Unmarshal(changed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, zerrors.ThrowInternal(err, "TARGET-w6402p4ek7", "unable to unmarshal target changed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return changed, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type RemovedEvent struct {
|
type RemovedEvent struct {
|
||||||
*eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *RemovedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
func (e *RemovedEvent) SetBaseEvent(b *eventstore.BaseEvent) {
|
||||||
e.BaseEvent = b
|
e.BaseEvent = *b
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *RemovedEvent) Payload() any {
|
func (e *RemovedEvent) Payload() any {
|
||||||
@@ -183,17 +162,5 @@ func (e *RemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string) *RemovedEvent {
|
func NewRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string) *RemovedEvent {
|
||||||
return &RemovedEvent{eventstore.NewBaseEventForPush(ctx, aggregate, RemovedEventType), name}
|
return &RemovedEvent{*eventstore.NewBaseEventForPush(ctx, aggregate, RemovedEventType), name}
|
||||||
}
|
|
||||||
|
|
||||||
func RemovedEventMapper(event eventstore.Event) (eventstore.Event, error) {
|
|
||||||
removed := &RemovedEvent{
|
|
||||||
BaseEvent: eventstore.BaseEventFromRepo(event),
|
|
||||||
}
|
|
||||||
err := event.Unmarshal(removed)
|
|
||||||
if err != nil {
|
|
||||||
return nil, zerrors.ThrowInternal(err, "TARGET-0kuc12c7bc", "unable to unmarshal target removed")
|
|
||||||
}
|
|
||||||
|
|
||||||
return removed, nil
|
|
||||||
}
|
}
|
||||||
|
@@ -13,23 +13,37 @@ import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
|||||||
|
|
||||||
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution";
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution";
|
||||||
|
|
||||||
message SetConditions{
|
message Execution {
|
||||||
|
string execution_id = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"request.zitadel.session.v2beta.SessionService\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Details provide some base information (such as the last change date) of the target.
|
||||||
|
zitadel.object.v2beta.Details details = 2;
|
||||||
|
// Targets which are called in the defined conditions.
|
||||||
|
repeated string targets = 3;
|
||||||
|
// Included executions with the same condition-types.
|
||||||
|
repeated string includes = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Condition {
|
||||||
// Condition-types under which conditions the execution should happen, only one possible.
|
// Condition-types under which conditions the execution should happen, only one possible.
|
||||||
oneof condition_type {
|
oneof condition_type {
|
||||||
option (validate.required) = true;
|
option (validate.required) = true;
|
||||||
|
|
||||||
// Condition-type to execute if a request on the defined API point happens.
|
// Condition-type to execute if a request on the defined API point happens.
|
||||||
SetRequestExecution request = 1;
|
RequestExecution request = 1;
|
||||||
// Condition-type to execute on response if a request on the defined API point happens.
|
// Condition-type to execute on response if a request on the defined API point happens.
|
||||||
SetResponseExecution response = 2;
|
ResponseExecution response = 2;
|
||||||
// Condition-type to execute if function is used, replaces actions v1.
|
// Condition-type to execute if function is used, replaces actions v1.
|
||||||
string function = 3;
|
string function = 3;
|
||||||
// Condition-type to execute if an event is created in the system.
|
// Condition-type to execute if an event is created in the system.
|
||||||
SetEventExecution event = 4;
|
EventExecution event = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetRequestExecution{
|
message RequestExecution {
|
||||||
// Condition for the request execution, only one possible.
|
// Condition for the request execution, only one possible.
|
||||||
oneof condition{
|
oneof condition{
|
||||||
// GRPC-method as condition.
|
// GRPC-method as condition.
|
||||||
@@ -55,7 +69,7 @@ message SetRequestExecution{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetResponseExecution{
|
message ResponseExecution {
|
||||||
// Condition for the response execution, only one possible.
|
// Condition for the response execution, only one possible.
|
||||||
oneof condition{
|
oneof condition{
|
||||||
// GRPC-method as condition.
|
// GRPC-method as condition.
|
||||||
@@ -81,7 +95,7 @@ message SetResponseExecution{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetEventExecution{
|
message EventExecution{
|
||||||
// Condition for the event execution, only one possible.
|
// Condition for the event execution, only one possible.
|
||||||
oneof condition{
|
oneof condition{
|
||||||
// Event name as condition.
|
// Event name as condition.
|
||||||
|
@@ -10,6 +10,7 @@ import "protoc-gen-openapiv2/options/annotations.proto";
|
|||||||
import "validate/validate.proto";
|
import "validate/validate.proto";
|
||||||
import "zitadel/execution/v3alpha/target.proto";
|
import "zitadel/execution/v3alpha/target.proto";
|
||||||
import "zitadel/execution/v3alpha/execution.proto";
|
import "zitadel/execution/v3alpha/execution.proto";
|
||||||
|
import "zitadel/execution/v3alpha/query.proto";
|
||||||
import "zitadel/object/v2beta/object.proto";
|
import "zitadel/object/v2beta/object.proto";
|
||||||
import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
import "zitadel/protoc_gen_zitadel/v2/options.proto";
|
||||||
|
|
||||||
@@ -187,12 +188,73 @@ service ExecutionService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List targets
|
||||||
|
//
|
||||||
|
// List all matching targets. By default, we will return all targets of your instance.
|
||||||
|
// Make sure to include a limit and sorting for pagination.
|
||||||
|
rpc ListTargets (ListTargetsRequest) returns (ListTargetsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/v3alpha/targets/search"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "execution.target.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
responses: {
|
||||||
|
key: "200";
|
||||||
|
value: {
|
||||||
|
description: "A list of all targets matching the query";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
key: "400";
|
||||||
|
value: {
|
||||||
|
description: "invalid list query";
|
||||||
|
schema: {
|
||||||
|
json_schema: {
|
||||||
|
ref: "#/definitions/rpcStatus";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target by ID
|
||||||
|
//
|
||||||
|
// Returns the target identified by the requested ID.
|
||||||
|
rpc GetTargetByID (GetTargetByIDRequest) returns (GetTargetByIDResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
get: "/v3alpha/targets/{target_id}"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "execution.target.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
responses: {
|
||||||
|
key: "200"
|
||||||
|
value: {
|
||||||
|
description: "Target successfully retrieved";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Set an execution
|
// Set an execution
|
||||||
//
|
//
|
||||||
// Set an execution to call a previously defined target or include the targets of a previously defined execution.
|
// Set an execution to call a previously defined target or include the targets of a previously defined execution.
|
||||||
rpc SetExecution (SetExecutionRequest) returns (SetExecutionResponse) {
|
rpc SetExecution (SetExecutionRequest) returns (SetExecutionResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post: "/v3alpha/executions"
|
put: "/v3alpha/executions"
|
||||||
body: "*"
|
body: "*"
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -236,6 +298,44 @@ service ExecutionService {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List executions
|
||||||
|
//
|
||||||
|
// List all matching executions. By default, we will return all executions of your instance.
|
||||||
|
// Make sure to include a limit and sorting for pagination.
|
||||||
|
rpc ListExecutions (ListExecutionsRequest) returns (ListExecutionsResponse) {
|
||||||
|
option (google.api.http) = {
|
||||||
|
post: "/v3alpha/executions/search"
|
||||||
|
body: "*"
|
||||||
|
};
|
||||||
|
|
||||||
|
option (zitadel.protoc_gen_zitadel.v2.options) = {
|
||||||
|
auth_option: {
|
||||||
|
permission: "execution.read"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {
|
||||||
|
responses: {
|
||||||
|
key: "200";
|
||||||
|
value: {
|
||||||
|
description: "A list of all executions matching the query";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
key: "400";
|
||||||
|
value: {
|
||||||
|
description: "invalid list query";
|
||||||
|
schema: {
|
||||||
|
json_schema: {
|
||||||
|
ref: "#/definitions/rpcStatus";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// List all available functions
|
// List all available functions
|
||||||
//
|
//
|
||||||
// List all available functions which can be used as condition for executions.
|
// List all available functions which can be used as condition for executions.
|
||||||
@@ -412,9 +512,48 @@ message DeleteTargetResponse {
|
|||||||
zitadel.object.v2beta.Details details = 1;
|
zitadel.object.v2beta.Details details = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListTargetsRequest {
|
||||||
|
// list limitations and ordering.
|
||||||
|
zitadel.object.v2beta.ListQuery query = 1;
|
||||||
|
// the field the result is sorted.
|
||||||
|
zitadel.execution.v3alpha.TargetFieldName sorting_column = 2 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"FIELD_NAME_SCHEMA_TYPE\""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Define the criteria to query for.
|
||||||
|
repeated zitadel.execution.v3alpha.TargetSearchQuery queries = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListTargetsResponse {
|
||||||
|
// Details provides information about the returned result including total amount found.
|
||||||
|
zitadel.object.v2beta.ListDetails details = 1;
|
||||||
|
// States by which field the results are sorted.
|
||||||
|
zitadel.execution.v3alpha.TargetFieldName sorting_column = 2;
|
||||||
|
// The result contains the user schemas, which matched the queries.
|
||||||
|
repeated zitadel.execution.v3alpha.Target result = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetTargetByIDRequest {
|
||||||
|
// unique identifier of the target.
|
||||||
|
string target_id = 1 [
|
||||||
|
(validate.rules).string = {min_len: 1, max_len: 200},
|
||||||
|
(google.api.field_behavior) = REQUIRED,
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
min_length: 1,
|
||||||
|
max_length: 200,
|
||||||
|
example: "\"69629026806489455\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetTargetByIDResponse {
|
||||||
|
zitadel.execution.v3alpha.Target target = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message SetExecutionRequest {
|
message SetExecutionRequest {
|
||||||
// Defines the condition type and content of the condition for execution.
|
// Defines the condition type and content of the condition for execution.
|
||||||
SetConditions condition = 1;
|
Condition condition = 1;
|
||||||
// Defines the execution targets which are defined as a different resource, which are called in the defined conditions.
|
// Defines the execution targets which are defined as a different resource, which are called in the defined conditions.
|
||||||
repeated string targets = 2;
|
repeated string targets = 2;
|
||||||
// Defines other executions as included with the same condition-types.
|
// Defines other executions as included with the same condition-types.
|
||||||
@@ -428,7 +567,7 @@ message SetExecutionResponse {
|
|||||||
|
|
||||||
message DeleteExecutionRequest {
|
message DeleteExecutionRequest {
|
||||||
// Unique identifier of the execution.
|
// Unique identifier of the execution.
|
||||||
SetConditions condition = 1;
|
Condition condition = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message DeleteExecutionResponse {
|
message DeleteExecutionResponse {
|
||||||
@@ -436,6 +575,20 @@ message DeleteExecutionResponse {
|
|||||||
zitadel.object.v2beta.Details details = 1;
|
zitadel.object.v2beta.Details details = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ListExecutionsRequest {
|
||||||
|
// list limitations and ordering.
|
||||||
|
zitadel.object.v2beta.ListQuery query = 1;
|
||||||
|
// Define the criteria to query for.
|
||||||
|
repeated zitadel.execution.v3alpha.SearchQuery queries = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ListExecutionsResponse {
|
||||||
|
// Details provides information about the returned result including total amount found.
|
||||||
|
zitadel.object.v2beta.ListDetails details = 1;
|
||||||
|
// The result contains the executions, which matched the queries.
|
||||||
|
repeated zitadel.execution.v3alpha.Execution result = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message ListExecutionFunctionsRequest{}
|
message ListExecutionFunctionsRequest{}
|
||||||
message ListExecutionFunctionsResponse{
|
message ListExecutionFunctionsResponse{
|
||||||
// All available methods
|
// All available methods
|
||||||
|
110
proto/zitadel/execution/v3alpha/query.proto
Normal file
110
proto/zitadel/execution/v3alpha/query.proto
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package zitadel.execution.v3alpha;
|
||||||
|
|
||||||
|
option go_package = "github.com/zitadel/zitadel/pkg/grpc/execution/v3alpha;execution";
|
||||||
|
|
||||||
|
import "google/api/field_behavior.proto";
|
||||||
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
|
import "validate/validate.proto";
|
||||||
|
import "zitadel/object/v2beta/object.proto";
|
||||||
|
import "zitadel/execution/v3alpha/execution.proto";
|
||||||
|
|
||||||
|
message SearchQuery {
|
||||||
|
oneof query {
|
||||||
|
option (validate.required) = true;
|
||||||
|
|
||||||
|
InConditionsQuery in_conditions_query = 1;
|
||||||
|
ExecutionTypeQuery execution_type_query = 2;
|
||||||
|
TargetQuery target_query = 3;
|
||||||
|
IncludeQuery include_query = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message InConditionsQuery {
|
||||||
|
// Defines the conditions to query for.
|
||||||
|
repeated Condition conditions = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ExecutionTypeQuery {
|
||||||
|
// Defines the type to query for.
|
||||||
|
ExecutionType execution_type = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TargetQuery {
|
||||||
|
// Defines the id to query for.
|
||||||
|
string target_id = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "the id of the targets to include"
|
||||||
|
example: "\"69629023906488334\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message IncludeQuery {
|
||||||
|
// Defines the include to query for.
|
||||||
|
string include = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "the id of the include"
|
||||||
|
example: "\"request.zitadel.session.v2beta.SessionService\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message TargetSearchQuery {
|
||||||
|
oneof query {
|
||||||
|
option (validate.required) = true;
|
||||||
|
|
||||||
|
TargetNameQuery target_name_query = 1;
|
||||||
|
InTargetIDsQuery in_target_ids_query = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message TargetNameQuery {
|
||||||
|
// Defines the name of the target to query for.
|
||||||
|
string target_name = 1 [
|
||||||
|
(validate.rules).string = {max_len: 200},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
max_length: 200;
|
||||||
|
example: "\"ip_allow_list\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Defines which text comparison method used for the name query.
|
||||||
|
zitadel.object.v2beta.TextQueryMethod method = 2 [
|
||||||
|
(validate.rules).enum.defined_only = true,
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "defines which text equality method is used";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message InTargetIDsQuery {
|
||||||
|
// Defines the ids to query for.
|
||||||
|
repeated string target_ids = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "the ids of the targets to include"
|
||||||
|
example: "[\"69629023906488334\",\"69622366012355662\"]";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ExecutionType {
|
||||||
|
EXECUTION_TYPE_UNSPECIFIED = 0;
|
||||||
|
EXECUTION_TYPE_REQUEST = 1;
|
||||||
|
EXECUTION_TYPE_RESPONSE = 2;
|
||||||
|
EXECUTION_TYPE_EVENT = 3;
|
||||||
|
EXECUTION_TYPE_FUNCTION = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TargetFieldName {
|
||||||
|
FIELD_NAME_UNSPECIFIED = 0;
|
||||||
|
FIELD_NAME_ID = 1;
|
||||||
|
FIELD_NAME_CREATION_DATE = 2;
|
||||||
|
FIELD_NAME_CHANGE_DATE = 3;
|
||||||
|
FIELD_NAME_NAME = 4;
|
||||||
|
FIELD_NAME_TARGET_TYPE = 5;
|
||||||
|
FIELD_NAME_URL = 6;
|
||||||
|
FIELD_NAME_TIMEOUT = 7;
|
||||||
|
FIELD_NAME_ASYNC = 8;
|
||||||
|
FIELD_NAME_INTERRUPT_ON_ERROR = 9;
|
||||||
|
}
|
@@ -35,4 +35,39 @@ message SetRESTRequestResponse {
|
|||||||
example: "\"https://example.com/hooks/ip_check\"";
|
example: "\"https://example.com/hooks/ip_check\"";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
message Target {
|
||||||
|
// ID is the read-only unique identifier of the target.
|
||||||
|
string target_id = 1 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"69629012906488334\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Details provide some base information (such as the last change date) of the target.
|
||||||
|
zitadel.object.v2beta.Details details = 2;
|
||||||
|
|
||||||
|
// Unique name of the target.
|
||||||
|
string name = 3 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"ip_allow_list\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
// Defines the target type and how the response of the target is treated.
|
||||||
|
oneof target_type {
|
||||||
|
SetRESTWebhook rest_webhook = 4;
|
||||||
|
SetRESTRequestResponse rest_request_response = 5;
|
||||||
|
}
|
||||||
|
// Timeout defines the duration until ZITADEL cancels the execution.
|
||||||
|
google.protobuf.Duration timeout = 6 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
example: "\"10s\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
oneof execution_type {
|
||||||
|
// Set the execution to run asynchronously.
|
||||||
|
bool is_async = 7;
|
||||||
|
// Define if any error stops the whole execution. By default the process continues as normal.
|
||||||
|
bool interrupt_on_error = 8;
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user