mirror of
https://github.com/zitadel/zitadel.git
synced 2025-07-31 08:13:57 +00:00
feat: limit amount of active actions (#3143)
* max actions * fix: max allowed actions * fix: max allowed actions * fix tests
This commit is contained in:
parent
585ebf9a81
commit
1367a2e139
@ -2564,6 +2564,8 @@ This is an empty request
|
||||
| custom_text_login | bool | - | |
|
||||
| lockout_policy | bool | - | |
|
||||
| actions | bool | - | |
|
||||
| actions_allowed | zitadel.features.v1.ActionsAllowed | - | |
|
||||
| max_actions | int32 | - | |
|
||||
|
||||
|
||||
|
||||
@ -2754,6 +2756,8 @@ This is an empty request
|
||||
| custom_text_login | bool | - | |
|
||||
| lockout_policy | bool | - | |
|
||||
| actions | bool | - | |
|
||||
| actions_allowed | zitadel.features.v1.ActionsAllowed | - | |
|
||||
| max_actions | int32 | - | |
|
||||
|
||||
|
||||
|
||||
|
@ -2758,6 +2758,30 @@ Change JWT identity provider configuration of the organisation
|
||||
PUT: /actions/{id}
|
||||
|
||||
|
||||
### DeactivateAction
|
||||
|
||||
> **rpc** DeactivateAction([DeactivateActionRequest](#deactivateactionrequest))
|
||||
[DeactivateActionResponse](#deactivateactionresponse)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
POST: /actions/{id}/_deactivate
|
||||
|
||||
|
||||
### ReactivateAction
|
||||
|
||||
> **rpc** ReactivateAction([ReactivateActionRequest](#reactivateactionrequest))
|
||||
[ReactivateActionResponse](#reactivateactionresponse)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
POST: /actions/{id}/_reactivate
|
||||
|
||||
|
||||
### DeleteAction
|
||||
|
||||
> **rpc** DeleteAction([DeleteActionRequest](#deleteactionrequest))
|
||||
|
@ -60,6 +60,10 @@ func (s *Server) ResetOrgFeatures(ctx context.Context, req *admin_pb.ResetOrgFea
|
||||
}
|
||||
|
||||
func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest) *domain.Features {
|
||||
actionsAllowed := features_grpc.ActionsAllowedToDomain(req.ActionsAllowed)
|
||||
if req.Actions {
|
||||
actionsAllowed = domain.ActionsAllowedUnlimited
|
||||
}
|
||||
return &domain.Features{
|
||||
TierName: req.TierName,
|
||||
TierDescription: req.Description,
|
||||
@ -79,11 +83,16 @@ func setDefaultFeaturesRequestToDomain(req *admin_pb.SetDefaultFeaturesRequest)
|
||||
CustomTextLogin: req.CustomTextLogin || req.CustomText,
|
||||
CustomTextMessage: req.CustomTextMessage,
|
||||
LockoutPolicy: req.LockoutPolicy,
|
||||
Actions: req.Actions,
|
||||
ActionsAllowed: actionsAllowed,
|
||||
MaxActions: int(req.MaxActions),
|
||||
}
|
||||
}
|
||||
|
||||
func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.Features {
|
||||
actionsAllowed := features_grpc.ActionsAllowedToDomain(req.ActionsAllowed)
|
||||
if req.Actions {
|
||||
actionsAllowed = domain.ActionsAllowedUnlimited
|
||||
}
|
||||
return &domain.Features{
|
||||
TierName: req.TierName,
|
||||
TierDescription: req.Description,
|
||||
@ -105,6 +114,7 @@ func setOrgFeaturesRequestToDomain(req *admin_pb.SetOrgFeaturesRequest) *domain.
|
||||
CustomTextLogin: req.CustomTextLogin || req.CustomText,
|
||||
CustomTextMessage: req.CustomTextMessage,
|
||||
LockoutPolicy: req.LockoutPolicy,
|
||||
Actions: req.Actions,
|
||||
ActionsAllowed: actionsAllowed,
|
||||
MaxActions: int(req.MaxActions),
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,9 @@ func ModelFeaturesToPb(features *query.Features) *features_pb.Features {
|
||||
CustomTextLogin: features.CustomTextLogin,
|
||||
MetadataUser: features.MetadataUser,
|
||||
LockoutPolicy: features.LockoutPolicy,
|
||||
Actions: features.Actions,
|
||||
Actions: features.ActionsAllowed != domain.ActionsNotAllowed,
|
||||
ActionsAllowed: ActionsAllowedToPb(features.ActionsAllowed),
|
||||
MaxActions: features.MaxActions,
|
||||
Details: object_grpc.ChangeToDetailsPb(
|
||||
features.Sequence,
|
||||
features.ChangeDate,
|
||||
@ -78,3 +80,29 @@ func FeaturesStateToDomain(status features_pb.FeaturesState) domain.FeaturesStat
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func ActionsAllowedToDomain(allowed features_pb.ActionsAllowed) domain.ActionsAllowed {
|
||||
switch allowed {
|
||||
case features_pb.ActionsAllowed_ACTIONS_ALLOWED_NOT_ALLOWED:
|
||||
return domain.ActionsNotAllowed
|
||||
case features_pb.ActionsAllowed_ACTIONS_ALLOWED_MAX:
|
||||
return domain.ActionsMaxAllowed
|
||||
case features_pb.ActionsAllowed_ACTIONS_ALLOWED_UNLIMITED:
|
||||
return domain.ActionsAllowedUnlimited
|
||||
default:
|
||||
return domain.ActionsNotAllowed
|
||||
}
|
||||
}
|
||||
|
||||
func ActionsAllowedToPb(allowed domain.ActionsAllowed) features_pb.ActionsAllowed {
|
||||
switch allowed {
|
||||
case domain.ActionsNotAllowed:
|
||||
return features_pb.ActionsAllowed_ACTIONS_ALLOWED_NOT_ALLOWED
|
||||
case domain.ActionsMaxAllowed:
|
||||
return features_pb.ActionsAllowed_ACTIONS_ALLOWED_MAX
|
||||
case domain.ActionsAllowedUnlimited:
|
||||
return features_pb.ActionsAllowed_ACTIONS_ALLOWED_UNLIMITED
|
||||
default:
|
||||
return features_pb.ActionsAllowed_ACTIONS_ALLOWED_NOT_ALLOWED
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ func checkFeatures(features *query.Features, requiredFeatures ...string) error {
|
||||
continue
|
||||
}
|
||||
if requiredFeature == domain.FeatureActions {
|
||||
if !features.Actions {
|
||||
if features.ActionsAllowed == domain.ActionsNotAllowed {
|
||||
return MissingFeatureErr(requiredFeature)
|
||||
}
|
||||
continue
|
||||
|
@ -31,7 +31,8 @@ type FeaturesWriteModel struct {
|
||||
CustomTextMessage bool
|
||||
CustomTextLogin bool
|
||||
LockoutPolicy bool
|
||||
Actions bool
|
||||
ActionsAllowed domain.ActionsAllowed
|
||||
MaxActions int
|
||||
}
|
||||
|
||||
func (wm *FeaturesWriteModel) Reduce() error {
|
||||
@ -103,7 +104,16 @@ func (wm *FeaturesWriteModel) Reduce() error {
|
||||
wm.LockoutPolicy = *e.LockoutPolicy
|
||||
}
|
||||
if e.Actions != nil {
|
||||
wm.Actions = *e.Actions
|
||||
wm.ActionsAllowed = domain.ActionsNotAllowed
|
||||
if *e.Actions {
|
||||
wm.ActionsAllowed = domain.ActionsAllowedUnlimited
|
||||
}
|
||||
}
|
||||
if e.ActionsAllowed != nil {
|
||||
wm.ActionsAllowed = *e.ActionsAllowed
|
||||
}
|
||||
if e.MaxActions != nil {
|
||||
wm.MaxActions = *e.MaxActions
|
||||
}
|
||||
case *features.FeaturesRemovedEvent:
|
||||
wm.State = domain.FeaturesStateRemoved
|
||||
|
@ -195,6 +195,7 @@ func writeModelToFeatures(wm *FeaturesWriteModel) *domain.Features {
|
||||
CustomTextMessage: wm.CustomTextMessage,
|
||||
CustomTextLogin: wm.CustomTextLogin,
|
||||
LockoutPolicy: wm.LockoutPolicy,
|
||||
Actions: wm.Actions,
|
||||
ActionsAllowed: wm.ActionsAllowed,
|
||||
MaxActions: wm.MaxActions,
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,8 @@ func (c *Commands) setDefaultFeatures(ctx context.Context, existingFeatures *IAM
|
||||
features.CustomTextMessage,
|
||||
features.CustomTextLogin,
|
||||
features.LockoutPolicy,
|
||||
features.Actions,
|
||||
features.ActionsAllowed,
|
||||
features.MaxActions,
|
||||
)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
|
@ -72,8 +72,9 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
metadataUser,
|
||||
customTextMessage,
|
||||
customTextLogin,
|
||||
lockoutPolicy,
|
||||
actions bool,
|
||||
lockoutPolicy bool,
|
||||
actionsAllowed domain.ActionsAllowed,
|
||||
maxActions int,
|
||||
) (*iam.FeaturesSetEvent, bool) {
|
||||
|
||||
changes := make([]features.FeaturesChanges, 0)
|
||||
@ -138,8 +139,11 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
if wm.LockoutPolicy != lockoutPolicy {
|
||||
changes = append(changes, features.ChangeLockoutPolicy(lockoutPolicy))
|
||||
}
|
||||
if wm.Actions != actions {
|
||||
changes = append(changes, features.ChangeActions(actions))
|
||||
if wm.ActionsAllowed != actionsAllowed {
|
||||
changes = append(changes, features.ChangeActionsAllowed(actionsAllowed))
|
||||
}
|
||||
if wm.MaxActions != maxActions {
|
||||
changes = append(changes, features.ChangeMaxActions(maxActions))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
@ -14,6 +15,10 @@ func (c *Commands) AddAction(ctx context.Context, addAction *domain.Action, reso
|
||||
if !addAction.IsValid() {
|
||||
return "", nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-eg2gf", "Errors.Action.Invalid")
|
||||
}
|
||||
err = c.checkAdditionalActionAllowed(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
addAction.AggregateID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
@ -39,6 +44,27 @@ func (c *Commands) AddAction(ctx context.Context, addAction *domain.Action, reso
|
||||
return actionModel.AggregateID, writeModelToObjectDetails(&actionModel.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkAdditionalActionAllowed(ctx context.Context, resourceOwner string) error {
|
||||
features, err := c.getOrgFeaturesOrDefault(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingActions, err := c.getActionsByOrgWriteModelByID(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
activeActions := make([]*ActionWriteModel, 0, len(existingActions.Actions))
|
||||
for _, existingAction := range existingActions.Actions {
|
||||
if existingAction.State == domain.ActionStateActive {
|
||||
activeActions = append(activeActions, existingAction)
|
||||
}
|
||||
}
|
||||
if len(activeActions) < features.MaxActions {
|
||||
return nil
|
||||
}
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dfwg2", "Errors.Action.MaxAllowed")
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeAction(ctx context.Context, actionChange *domain.Action, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
if !actionChange.IsValid() || actionChange.AggregateID == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-Df2f3", "Errors.Action.Invalid")
|
||||
@ -119,6 +145,11 @@ func (c *Commands) ReactivateAction(ctx context.Context, actionID string, resour
|
||||
if existingAction.State != domain.ActionStateInactive {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-J53zh", "Errors.Action.NotInactive")
|
||||
}
|
||||
err = c.checkAdditionalActionAllowed(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actionAgg := ActionAggregateFromWriteModel(&existingAction.WriteModel)
|
||||
events := []eventstore.Command{
|
||||
action.NewReactivatedEvent(ctx, actionAgg),
|
||||
@ -174,9 +205,34 @@ func (c *Commands) removeActionsFromOrg(ctx context.Context, resourceOwner strin
|
||||
return nil, nil
|
||||
}
|
||||
events := make([]eventstore.Command, 0, len(existingActions.Actions))
|
||||
for id, name := range existingActions.Actions {
|
||||
for id, existingAction := range existingActions.Actions {
|
||||
actionAgg := NewActionAggregate(id, resourceOwner)
|
||||
events = append(events, action.NewRemovedEvent(ctx, actionAgg, name))
|
||||
events = append(events, action.NewRemovedEvent(ctx, actionAgg, existingAction.Name))
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) deactivateNotAllowedActionsFromOrg(ctx context.Context, resourceOwner string, maxAllowed int) ([]eventstore.Command, error) {
|
||||
existingActions, err := c.getActionsByOrgWriteModelByID(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
activeActions := make([]*ActionWriteModel, 0, len(existingActions.Actions))
|
||||
for _, existingAction := range existingActions.Actions {
|
||||
if existingAction.State == domain.ActionStateActive {
|
||||
activeActions = append(activeActions, existingAction)
|
||||
}
|
||||
}
|
||||
if len(activeActions) <= maxAllowed {
|
||||
return nil, nil
|
||||
}
|
||||
sort.Slice(activeActions, func(i, j int) bool {
|
||||
return activeActions[i].WriteModel.ChangeDate.Before(activeActions[j].WriteModel.ChangeDate)
|
||||
})
|
||||
events := make([]eventstore.Command, 0, len(existingActions.Actions))
|
||||
for i := maxAllowed; i < len(activeActions); i++ {
|
||||
actionAgg := NewActionAggregate(activeActions[i].AggregateID, resourceOwner)
|
||||
events = append(events, action.NewDeactivatedEvent(ctx, actionAgg))
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ func (wm *ActionExistsModel) Query() *eventstore.SearchQueryBuilder {
|
||||
type ActionsListByOrgModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
Actions map[string]string
|
||||
Actions map[string]*ActionWriteModel
|
||||
}
|
||||
|
||||
func NewActionsListByOrgModel(resourceOwner string) *ActionsListByOrgModel {
|
||||
@ -167,7 +167,7 @@ func NewActionsListByOrgModel(resourceOwner string) *ActionsListByOrgModel {
|
||||
WriteModel: eventstore.WriteModel{
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Actions: make(map[string]string),
|
||||
Actions: make(map[string]*ActionWriteModel),
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,7 +175,18 @@ func (wm *ActionsListByOrgModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *action.AddedEvent:
|
||||
wm.Actions[e.Aggregate().ID] = e.Name
|
||||
wm.Actions[e.Aggregate().ID] = &ActionWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: e.Aggregate().ID,
|
||||
ChangeDate: e.CreationDate(),
|
||||
},
|
||||
Name: e.Name,
|
||||
State: domain.ActionStateActive,
|
||||
}
|
||||
case *action.DeactivatedEvent:
|
||||
wm.Actions[e.Aggregate().ID].State = domain.ActionStateInactive
|
||||
case *action.ReactivatedEvent:
|
||||
wm.Actions[e.Aggregate().ID].State = domain.ActionStateActive
|
||||
case *action.RemovedEvent:
|
||||
delete(wm.Actions, e.Aggregate().ID)
|
||||
}
|
||||
@ -189,6 +200,8 @@ func (wm *ActionsListByOrgModel) Query() *eventstore.SearchQueryBuilder {
|
||||
AddQuery().
|
||||
AggregateTypes(action.AggregateType).
|
||||
EventTypes(action.AddedEventType,
|
||||
action.DeactivatedEventType,
|
||||
action.ReactivatedEventType,
|
||||
action.RemovedEventType).
|
||||
Builder()
|
||||
}
|
||||
|
@ -4,6 +4,10 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/caos/zitadel/internal/repository/features"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
@ -13,7 +17,6 @@ import (
|
||||
"github.com/caos/zitadel/internal/id/mock"
|
||||
"github.com/caos/zitadel/internal/repository/action"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCommands_AddAction(t *testing.T) {
|
||||
@ -53,10 +56,76 @@ func TestCommands_AddAction(t *testing.T) {
|
||||
err: errors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
"no additional allowed, error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
func() eventstore.Command {
|
||||
e, _ := org.NewFeaturesSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeMaxActions(1),
|
||||
},
|
||||
)
|
||||
return e
|
||||
}(),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
"name",
|
||||
"name() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
addAction: &domain.Action{
|
||||
Name: "name",
|
||||
Script: "name() {};",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res{
|
||||
err: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
"unique constraint failed, error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
func() eventstore.Command {
|
||||
e, _ := org.NewFeaturesSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeMaxActions(2),
|
||||
},
|
||||
)
|
||||
return e
|
||||
}(),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
"name",
|
||||
"name() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPushFailed(
|
||||
errors.ThrowPreconditionFailed(nil, "id", "name already exists"),
|
||||
[]*repository.Event{
|
||||
@ -91,33 +160,57 @@ func TestCommands_AddAction(t *testing.T) {
|
||||
"push ok",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
func() eventstore.Command {
|
||||
e, _ := org.NewFeaturesSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeMaxActions(2),
|
||||
},
|
||||
)
|
||||
return e
|
||||
}(),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
"name",
|
||||
"name() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
"name",
|
||||
"name() {};",
|
||||
&action.NewAggregate("id2", "org1").Aggregate,
|
||||
"name2",
|
||||
"name2() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraint(action.NewAddActionNameUniqueConstraint("name", "org1")),
|
||||
uniqueConstraintsFromEventConstraint(action.NewAddActionNameUniqueConstraint("name2", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: mock.ExpectID(t, "id1"),
|
||||
idGenerator: mock.ExpectID(t, "id2"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
addAction: &domain.Action{
|
||||
Name: "name",
|
||||
Script: "name() {};",
|
||||
Name: "name2",
|
||||
Script: "name2() {};",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res{
|
||||
id: "id1",
|
||||
id: "id2",
|
||||
details: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
@ -570,10 +663,94 @@ func TestCommands_ReactivateAction(t *testing.T) {
|
||||
err: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
"no additional allowed, error",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
"name",
|
||||
"name() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
action.NewDeactivatedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
func() eventstore.Command {
|
||||
e, _ := org.NewFeaturesSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeMaxActions(1),
|
||||
},
|
||||
)
|
||||
return e
|
||||
}(),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id2", "org1").Aggregate,
|
||||
"name2",
|
||||
"name2() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
actionID: "id1",
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res{
|
||||
err: errors.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
"reactivate ok",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
"name",
|
||||
"name() {};",
|
||||
0,
|
||||
false,
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
action.NewDeactivatedEvent(context.Background(),
|
||||
&action.NewAggregate("id1", "org1").Aggregate,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
func() eventstore.Command {
|
||||
e, _ := org.NewFeaturesSetEvent(context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
[]features.FeaturesChanges{
|
||||
features.ChangeMaxActions(1),
|
||||
},
|
||||
)
|
||||
return e
|
||||
}(),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
action.NewAddedEvent(context.Background(),
|
||||
|
@ -45,7 +45,8 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
features.CustomTextMessage,
|
||||
features.CustomTextLogin,
|
||||
features.LockoutPolicy,
|
||||
features.Actions,
|
||||
features.ActionsAllowed,
|
||||
features.MaxActions,
|
||||
)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
@ -177,7 +178,7 @@ func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string
|
||||
events = append(events, removeOrgUserMetadatas...)
|
||||
}
|
||||
}
|
||||
if !features.Actions {
|
||||
if features.ActionsAllowed == domain.ActionsNotAllowed {
|
||||
removeOrgActions, err := c.removeActionsFromOrg(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -186,6 +187,15 @@ func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string
|
||||
events = append(events, removeOrgActions...)
|
||||
}
|
||||
}
|
||||
if features.ActionsAllowed == domain.ActionsMaxAllowed {
|
||||
deactivateActions, err := c.deactivateNotAllowedActionsFromOrg(ctx, orgID, features.MaxActions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(deactivateActions) > 0 {
|
||||
events = append(events, deactivateActions...)
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
@ -351,3 +361,21 @@ func (c *Commands) setAllowedLabelPolicy(ctx context.Context, orgID string, feat
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) getOrgFeaturesOrDefault(ctx context.Context, orgID string) (*domain.Features, error) {
|
||||
existingFeatures := NewOrgFeaturesWriteModel(orgID)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, existingFeatures)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingFeatures.State != domain.FeaturesStateUnspecified && existingFeatures.State != domain.FeaturesStateRemoved {
|
||||
return writeModelToFeatures(&existingFeatures.FeaturesWriteModel), nil
|
||||
}
|
||||
|
||||
existingIAMFeatures := NewIAMFeaturesWriteModel()
|
||||
err = c.eventstore.FilterToQueryReducer(ctx, existingIAMFeatures)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return writeModelToFeatures(&existingIAMFeatures.FeaturesWriteModel), nil
|
||||
}
|
||||
|
@ -78,8 +78,9 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
metadataUser,
|
||||
customTextMessage,
|
||||
customTextLogin,
|
||||
lockoutPolicy,
|
||||
actions bool,
|
||||
lockoutPolicy bool,
|
||||
actionsAllowed domain.ActionsAllowed,
|
||||
maxActions int,
|
||||
) (*org.FeaturesSetEvent, bool) {
|
||||
|
||||
changes := make([]features.FeaturesChanges, 0)
|
||||
@ -144,8 +145,11 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
if wm.LockoutPolicy != lockoutPolicy {
|
||||
changes = append(changes, features.ChangeLockoutPolicy(lockoutPolicy))
|
||||
}
|
||||
if wm.Actions != actions {
|
||||
changes = append(changes, features.ChangeActions(actions))
|
||||
if wm.ActionsAllowed != actionsAllowed {
|
||||
changes = append(changes, features.ChangeActionsAllowed(actionsAllowed))
|
||||
}
|
||||
if wm.MaxActions != maxActions {
|
||||
changes = append(changes, features.ChangeMaxActions(maxActions))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
|
@ -308,7 +308,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
PrivacyPolicy: false,
|
||||
MetadataUser: false,
|
||||
LockoutPolicy: false,
|
||||
Actions: false,
|
||||
ActionsAllowed: domain.ActionsNotAllowed,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -512,7 +512,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
MetadataUser: false,
|
||||
PrivacyPolicy: false,
|
||||
LockoutPolicy: false,
|
||||
Actions: false,
|
||||
ActionsAllowed: domain.ActionsNotAllowed,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -726,7 +726,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
MetadataUser: false,
|
||||
PrivacyPolicy: false,
|
||||
LockoutPolicy: false,
|
||||
Actions: false,
|
||||
ActionsAllowed: domain.ActionsNotAllowed,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -950,7 +950,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
MetadataUser: false,
|
||||
PrivacyPolicy: false,
|
||||
LockoutPolicy: false,
|
||||
Actions: false,
|
||||
ActionsAllowed: domain.ActionsNotAllowed,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -1243,7 +1243,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
MetadataUser: false,
|
||||
PrivacyPolicy: false,
|
||||
LockoutPolicy: false,
|
||||
Actions: false,
|
||||
ActionsAllowed: domain.ActionsNotAllowed,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -1433,7 +1433,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
PrivacyPolicy: false,
|
||||
MetadataUser: false,
|
||||
LockoutPolicy: false,
|
||||
Actions: false,
|
||||
ActionsAllowed: domain.ActionsNotAllowed,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
|
@ -37,3 +37,11 @@ func (s ActionState) Valid() bool {
|
||||
func (s ActionState) Exists() bool {
|
||||
return s != ActionStateUnspecified && s != ActionStateRemoved
|
||||
}
|
||||
|
||||
type ActionsAllowed int32
|
||||
|
||||
const (
|
||||
ActionsNotAllowed ActionsAllowed = iota
|
||||
ActionsMaxAllowed
|
||||
ActionsAllowedUnlimited
|
||||
)
|
||||
|
@ -54,7 +54,8 @@ type Features struct {
|
||||
PrivacyPolicy bool
|
||||
MetadataUser bool
|
||||
LockoutPolicy bool
|
||||
Actions bool
|
||||
ActionsAllowed ActionsAllowed
|
||||
MaxActions int
|
||||
}
|
||||
|
||||
type FeaturesState int32
|
||||
|
@ -67,13 +67,14 @@ func (q *Queries) GetFlow(ctx context.Context, flowType domain.FlowType, orgID s
|
||||
return scan(rows)
|
||||
}
|
||||
|
||||
func (q *Queries) GetActionsByFlowAndTriggerType(ctx context.Context, flowType domain.FlowType, triggerType domain.TriggerType, orgID string) ([]*Action, error) {
|
||||
func (q *Queries) GetActiveActionsByFlowAndTriggerType(ctx context.Context, flowType domain.FlowType, triggerType domain.TriggerType, orgID string) ([]*Action, error) {
|
||||
stmt, scan := prepareTriggerActionsQuery()
|
||||
query, args, err := stmt.Where(
|
||||
sq.Eq{
|
||||
FlowsTriggersColumnFlowType.identifier(): flowType,
|
||||
FlowsTriggersColumnTriggerType.identifier(): triggerType,
|
||||
FlowsTriggersColumnResourceOwner.identifier(): orgID,
|
||||
ActionColumnState.identifier(): domain.ActionStateActive,
|
||||
},
|
||||
).ToSql()
|
||||
if err != nil {
|
||||
@ -135,7 +136,7 @@ func prepareTriggerActionsQuery() (sq.SelectBuilder, func(*sql.Rows) ([]*Action,
|
||||
ActionColumnCreationDate.identifier(),
|
||||
ActionColumnChangeDate.identifier(),
|
||||
ActionColumnResourceOwner.identifier(),
|
||||
//ActionColumnState.identifier(),
|
||||
ActionColumnState.identifier(),
|
||||
ActionColumnSequence.identifier(),
|
||||
ActionColumnName.identifier(),
|
||||
ActionColumnScript.identifier(),
|
||||
@ -152,7 +153,7 @@ func prepareTriggerActionsQuery() (sq.SelectBuilder, func(*sql.Rows) ([]*Action,
|
||||
&action.CreationDate,
|
||||
&action.ChangeDate,
|
||||
&action.ResourceOwner,
|
||||
//&action.State, //TODO: state in next release
|
||||
&action.State,
|
||||
&action.Sequence,
|
||||
&action.Name,
|
||||
&action.Script,
|
||||
@ -177,7 +178,7 @@ func prepareFlowQuery() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
ActionColumnCreationDate.identifier(),
|
||||
ActionColumnChangeDate.identifier(),
|
||||
ActionColumnResourceOwner.identifier(),
|
||||
//ActionColumnState.identifier(),
|
||||
ActionColumnState.identifier(),
|
||||
ActionColumnSequence.identifier(),
|
||||
ActionColumnName.identifier(),
|
||||
ActionColumnScript.identifier(),
|
||||
@ -199,6 +200,7 @@ func prepareFlowQuery() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
actionCreationDate pq.NullTime
|
||||
actionChangeDate pq.NullTime
|
||||
actionResourceOwner sql.NullString
|
||||
actionState sql.NullInt32
|
||||
actionSequence sql.NullInt64
|
||||
actionName sql.NullString
|
||||
actionScript sql.NullString
|
||||
@ -212,7 +214,7 @@ func prepareFlowQuery() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
&actionCreationDate,
|
||||
&actionChangeDate,
|
||||
&actionResourceOwner,
|
||||
//&action.State, //TODO: state in next release
|
||||
&actionState,
|
||||
&actionSequence,
|
||||
&actionName,
|
||||
&actionScript,
|
||||
@ -232,6 +234,7 @@ func prepareFlowQuery() (sq.SelectBuilder, func(*sql.Rows) (*Flow, error)) {
|
||||
CreationDate: actionCreationDate.Time,
|
||||
ChangeDate: actionChangeDate.Time,
|
||||
ResourceOwner: actionResourceOwner.String,
|
||||
State: domain.ActionState(actionState.Int32),
|
||||
Sequence: uint64(actionSequence.Int64),
|
||||
Name: actionName.String,
|
||||
Script: actionScript.String,
|
||||
|
@ -31,6 +31,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script,`+
|
||||
@ -54,6 +55,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script,`+
|
||||
@ -67,6 +69,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
@ -80,6 +83,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.ActionStateActive,
|
||||
uint64(20211115),
|
||||
"action-name",
|
||||
"script",
|
||||
@ -99,6 +103,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.ActionStateActive,
|
||||
Sequence: 20211115,
|
||||
Name: "action-name",
|
||||
Script: "script",
|
||||
@ -116,6 +121,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script,`+
|
||||
@ -129,6 +135,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
@ -142,6 +149,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.ActionStateActive,
|
||||
uint64(20211115),
|
||||
"action-name-pre",
|
||||
"script",
|
||||
@ -154,6 +162,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.ActionStateActive,
|
||||
uint64(20211115),
|
||||
"action-name-post",
|
||||
"script",
|
||||
@ -173,6 +182,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.ActionStateActive,
|
||||
Sequence: 20211115,
|
||||
Name: "action-name-pre",
|
||||
Script: "script",
|
||||
@ -184,6 +194,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.ActionStateActive,
|
||||
Sequence: 20211115,
|
||||
Name: "action-name-post",
|
||||
Script: "script",
|
||||
@ -201,6 +212,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script,`+
|
||||
@ -214,6 +226,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
@ -230,6 +243,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
domain.TriggerTypePostCreation,
|
||||
uint64(20211109),
|
||||
domain.FlowTypeExternalAuthentication,
|
||||
@ -251,6 +265,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script,`+
|
||||
@ -279,6 +294,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script`+
|
||||
@ -299,6 +315,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script`+
|
||||
@ -309,6 +326,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
@ -319,6 +337,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.AddressStateActive,
|
||||
uint64(20211115),
|
||||
"action-name",
|
||||
"script",
|
||||
@ -332,6 +351,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.ActionStateActive,
|
||||
Sequence: 20211115,
|
||||
Name: "action-name",
|
||||
Script: "script",
|
||||
@ -347,6 +367,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script`+
|
||||
@ -357,6 +378,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"resource_owner",
|
||||
"state",
|
||||
"sequence",
|
||||
"name",
|
||||
"script",
|
||||
@ -367,6 +389,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.AddressStateActive,
|
||||
uint64(20211115),
|
||||
"action-name-1",
|
||||
"script",
|
||||
@ -376,6 +399,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
testNow,
|
||||
testNow,
|
||||
"ro",
|
||||
domain.ActionStateActive,
|
||||
uint64(20211115),
|
||||
"action-name-2",
|
||||
"script",
|
||||
@ -389,6 +413,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.ActionStateActive,
|
||||
Sequence: 20211115,
|
||||
Name: "action-name-1",
|
||||
Script: "script",
|
||||
@ -398,6 +423,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
CreationDate: testNow,
|
||||
ChangeDate: testNow,
|
||||
ResourceOwner: "ro",
|
||||
State: domain.ActionStateActive,
|
||||
Sequence: 20211115,
|
||||
Name: "action-name-2",
|
||||
Script: "script",
|
||||
@ -413,6 +439,7 @@ func Test_FlowPrepares(t *testing.T) {
|
||||
` zitadel.projections.actions.creation_date,`+
|
||||
` zitadel.projections.actions.change_date,`+
|
||||
` zitadel.projections.actions.resource_owner,`+
|
||||
` zitadel.projections.actions.action_state,`+
|
||||
` zitadel.projections.actions.sequence,`+
|
||||
` zitadel.projections.actions.name,`+
|
||||
` zitadel.projections.actions.script`+
|
||||
|
@ -38,7 +38,8 @@ type Features struct {
|
||||
CustomTextMessage bool
|
||||
CustomTextLogin bool
|
||||
LockoutPolicy bool
|
||||
Actions bool
|
||||
ActionsAllowed domain.ActionsAllowed
|
||||
MaxActions int32
|
||||
}
|
||||
|
||||
var (
|
||||
@ -141,8 +142,12 @@ var (
|
||||
name: projection.FeatureLockoutPolicyCol,
|
||||
table: featureTable,
|
||||
}
|
||||
FeatureActions = Column{
|
||||
name: projection.FeatureActionsCol,
|
||||
FeatureActionsAllowed = Column{
|
||||
name: projection.FeatureActionsAllowedCol,
|
||||
table: featureTable,
|
||||
}
|
||||
FeatureMaxActions = Column{
|
||||
name: projection.FeatureMaxActionsCol,
|
||||
table: featureTable,
|
||||
}
|
||||
)
|
||||
@ -207,7 +212,8 @@ func prepareFeaturesQuery() (sq.SelectBuilder, func(*sql.Row) (*Features, error)
|
||||
FeatureCustomTextMessage.identifier(),
|
||||
FeatureCustomTextLogin.identifier(),
|
||||
FeatureLockoutPolicy.identifier(),
|
||||
FeatureActions.identifier(),
|
||||
FeatureActionsAllowed.identifier(),
|
||||
FeatureMaxActions.identifier(),
|
||||
).From(featureTable.identifier()).PlaceholderFormat(sq.Dollar),
|
||||
func(row *sql.Row) (*Features, error) {
|
||||
p := new(Features)
|
||||
@ -239,7 +245,8 @@ func prepareFeaturesQuery() (sq.SelectBuilder, func(*sql.Row) (*Features, error)
|
||||
&p.CustomTextMessage,
|
||||
&p.CustomTextLogin,
|
||||
&p.LockoutPolicy,
|
||||
&p.Actions,
|
||||
&p.ActionsAllowed,
|
||||
&p.MaxActions,
|
||||
)
|
||||
if err != nil {
|
||||
if errs.Is(err, sql.ErrNoRows) {
|
||||
@ -301,7 +308,7 @@ func (f *Features) EnabledFeatureTypes() []string {
|
||||
if f.LockoutPolicy {
|
||||
list = append(list, domain.FeatureLockoutPolicy)
|
||||
}
|
||||
if f.Actions {
|
||||
if f.ActionsAllowed != domain.ActionsNotAllowed {
|
||||
list = append(list, domain.FeatureActions)
|
||||
}
|
||||
return list
|
||||
|
@ -53,7 +53,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
` zitadel.projections.features.custom_text_message,`+
|
||||
` zitadel.projections.features.custom_text_login,`+
|
||||
` zitadel.projections.features.lockout_policy,`+
|
||||
` zitadel.projections.features.actions`+
|
||||
` zitadel.projections.features.actions_allowed,`+
|
||||
` zitadel.projections.features.max_actions`+
|
||||
` FROM zitadel.projections.features`),
|
||||
nil,
|
||||
nil,
|
||||
@ -96,7 +97,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
` zitadel.projections.features.custom_text_message,`+
|
||||
` zitadel.projections.features.custom_text_login,`+
|
||||
` zitadel.projections.features.lockout_policy,`+
|
||||
` zitadel.projections.features.actions`+
|
||||
` zitadel.projections.features.actions_allowed,`+
|
||||
` zitadel.projections.features.max_actions`+
|
||||
` FROM zitadel.projections.features`),
|
||||
[]string{
|
||||
"aggregate_id",
|
||||
@ -123,7 +125,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
"custom_text_message",
|
||||
"custom_text_login",
|
||||
"lockout_policy",
|
||||
"actions",
|
||||
"actions_allowed",
|
||||
"max_actions",
|
||||
},
|
||||
[]driver.Value{
|
||||
"aggregate-id",
|
||||
@ -150,7 +153,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.ActionsMaxAllowed,
|
||||
10,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -179,7 +183,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
CustomTextMessage: true,
|
||||
CustomTextLogin: true,
|
||||
LockoutPolicy: true,
|
||||
Actions: true,
|
||||
ActionsAllowed: domain.ActionsMaxAllowed,
|
||||
MaxActions: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -211,7 +216,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
` zitadel.projections.features.custom_text_message,`+
|
||||
` zitadel.projections.features.custom_text_login,`+
|
||||
` zitadel.projections.features.lockout_policy,`+
|
||||
` zitadel.projections.features.actions`+
|
||||
` zitadel.projections.features.actions_allowed,`+
|
||||
` zitadel.projections.features.max_actions`+
|
||||
` FROM zitadel.projections.features`),
|
||||
[]string{
|
||||
"aggregate_id",
|
||||
@ -238,7 +244,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
"custom_text_message",
|
||||
"custom_text_login",
|
||||
"lockout_policy",
|
||||
"actions",
|
||||
"actions_allowed",
|
||||
"max_actions",
|
||||
},
|
||||
[]driver.Value{
|
||||
"aggregate-id",
|
||||
@ -265,7 +272,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.ActionsMaxAllowed,
|
||||
10,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -294,7 +302,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
CustomTextMessage: true,
|
||||
CustomTextLogin: true,
|
||||
LockoutPolicy: true,
|
||||
Actions: true,
|
||||
ActionsAllowed: domain.ActionsMaxAllowed,
|
||||
MaxActions: 10,
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -326,7 +335,8 @@ func Test_FeaturesPrepares(t *testing.T) {
|
||||
` zitadel.projections.features.custom_text_message,`+
|
||||
` zitadel.projections.features.custom_text_login,`+
|
||||
` zitadel.projections.features.lockout_policy,`+
|
||||
` zitadel.projections.features.actions`+
|
||||
` zitadel.projections.features.actions_allowed,`+
|
||||
` zitadel.projections.features.max_actions`+
|
||||
` FROM zitadel.projections.features`),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/handler"
|
||||
@ -82,7 +84,8 @@ const (
|
||||
FeatureCustomTextMessageCol = "custom_text_message"
|
||||
FeatureCustomTextLoginCol = "custom_text_login"
|
||||
FeatureLockoutPolicyCol = "lockout_policy"
|
||||
FeatureActionsCol = "actions"
|
||||
FeatureActionsAllowedCol = "actions_allowed"
|
||||
FeatureMaxActionsCol = "max_actions"
|
||||
)
|
||||
|
||||
func (p *FeatureProjection) reduceFeatureSet(event eventstore.Event) (*handler.Statement, error) {
|
||||
@ -173,7 +176,17 @@ func (p *FeatureProjection) reduceFeatureSet(event eventstore.Event) (*handler.S
|
||||
cols = append(cols, handler.NewCol(FeatureLockoutPolicyCol, *featureEvent.LockoutPolicy))
|
||||
}
|
||||
if featureEvent.Actions != nil {
|
||||
cols = append(cols, handler.NewCol(FeatureActionsCol, *featureEvent.Actions))
|
||||
actionsAllowed := domain.ActionsNotAllowed
|
||||
if *featureEvent.Actions {
|
||||
actionsAllowed = domain.ActionsAllowedUnlimited
|
||||
}
|
||||
cols = append(cols, handler.NewCol(FeatureActionsAllowedCol, actionsAllowed))
|
||||
}
|
||||
if featureEvent.ActionsAllowed != nil {
|
||||
cols = append(cols, handler.NewCol(FeatureActionsAllowedCol, *featureEvent.ActionsAllowed))
|
||||
}
|
||||
if featureEvent.MaxActions != nil {
|
||||
cols = append(cols, handler.NewCol(FeatureMaxActionsCol, *featureEvent.MaxActions))
|
||||
}
|
||||
return crdb.NewUpsertStatement(
|
||||
&featureEvent,
|
||||
|
@ -50,7 +50,8 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
"customTextMessage": true,
|
||||
"customTextLogin": true,
|
||||
"lockoutPolicy": true,
|
||||
"actions": true
|
||||
"actionsAllowed": 1,
|
||||
"maxActions": 10
|
||||
}`),
|
||||
), org.FeaturesSetEventMapper),
|
||||
},
|
||||
@ -63,7 +64,7 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)",
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed, max_actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@ -89,7 +90,8 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.ActionsMaxAllowed,
|
||||
10,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -136,7 +138,7 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)",
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@ -162,7 +164,7 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.ActionsAllowedUnlimited,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -266,7 +268,7 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)",
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@ -292,7 +294,7 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.ActionsAllowedUnlimited,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -327,7 +329,8 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
"customTextMessage": true,
|
||||
"customTextLogin": true,
|
||||
"lockoutPolicy": true,
|
||||
"actions": true
|
||||
"actionsAllowed": 1,
|
||||
"maxActions": 10
|
||||
}`),
|
||||
), iam.FeaturesSetEventMapper),
|
||||
},
|
||||
@ -339,7 +342,7 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
executer: &testExecuter{
|
||||
executions: []execution{
|
||||
{
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)",
|
||||
expectedStmt: "UPSERT INTO zitadel.projections.features (aggregate_id, change_date, sequence, is_default, tier_name, tier_description, state, state_description, audit_log_retention, login_policy_factors, login_policy_idp, login_policy_passwordless, login_policy_registration, login_policy_username_login, login_policy_password_reset, password_complexity_policy, label_policy_private_label, label_policy_watermark, custom_domain, privacy_policy, metadata_user, custom_text_message, custom_text_login, lockout_policy, actions_allowed, max_actions) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26)",
|
||||
expectedArgs: []interface{}{
|
||||
"agg-id",
|
||||
anyArg{},
|
||||
@ -365,7 +368,8 @@ func TestFeatureProjection_reduces(t *testing.T) {
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
domain.ActionsMaxAllowed,
|
||||
10,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -19,28 +19,30 @@ const (
|
||||
type FeaturesSetEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
TierName *string `json:"tierName,omitempty"`
|
||||
TierDescription *string `json:"tierDescription,omitempty"`
|
||||
State *domain.FeaturesState `json:"state,omitempty"`
|
||||
StateDescription *string `json:"stateDescription,omitempty"`
|
||||
AuditLogRetention *time.Duration `json:"auditLogRetention,omitempty"`
|
||||
LoginPolicyFactors *bool `json:"loginPolicyFactors,omitempty"`
|
||||
LoginPolicyIDP *bool `json:"loginPolicyIDP,omitempty"`
|
||||
LoginPolicyPasswordless *bool `json:"loginPolicyPasswordless,omitempty"`
|
||||
LoginPolicyRegistration *bool `json:"loginPolicyRegistration,omitempty"`
|
||||
LoginPolicyUsernameLogin *bool `json:"loginPolicyUsernameLogin,omitempty"`
|
||||
LoginPolicyPasswordReset *bool `json:"loginPolicyPasswordReset,omitempty"`
|
||||
PasswordComplexityPolicy *bool `json:"passwordComplexityPolicy,omitempty"`
|
||||
LabelPolicy *bool `json:"labelPolicy,omitempty"`
|
||||
LabelPolicyPrivateLabel *bool `json:"labelPolicyPrivateLabel,omitempty"`
|
||||
LabelPolicyWatermark *bool `json:"labelPolicyWatermark,omitempty"`
|
||||
CustomDomain *bool `json:"customDomain,omitempty"`
|
||||
PrivacyPolicy *bool `json:"privacyPolicy,omitempty"`
|
||||
MetadataUser *bool `json:"metadataUser,omitempty"`
|
||||
CustomTextMessage *bool `json:"customTextMessage,omitempty"`
|
||||
CustomTextLogin *bool `json:"customTextLogin,omitempty"`
|
||||
LockoutPolicy *bool `json:"lockoutPolicy,omitempty"`
|
||||
Actions *bool `json:"actions,omitempty"`
|
||||
TierName *string `json:"tierName,omitempty"`
|
||||
TierDescription *string `json:"tierDescription,omitempty"`
|
||||
State *domain.FeaturesState `json:"state,omitempty"`
|
||||
StateDescription *string `json:"stateDescription,omitempty"`
|
||||
AuditLogRetention *time.Duration `json:"auditLogRetention,omitempty"`
|
||||
LoginPolicyFactors *bool `json:"loginPolicyFactors,omitempty"`
|
||||
LoginPolicyIDP *bool `json:"loginPolicyIDP,omitempty"`
|
||||
LoginPolicyPasswordless *bool `json:"loginPolicyPasswordless,omitempty"`
|
||||
LoginPolicyRegistration *bool `json:"loginPolicyRegistration,omitempty"`
|
||||
LoginPolicyUsernameLogin *bool `json:"loginPolicyUsernameLogin,omitempty"`
|
||||
LoginPolicyPasswordReset *bool `json:"loginPolicyPasswordReset,omitempty"`
|
||||
PasswordComplexityPolicy *bool `json:"passwordComplexityPolicy,omitempty"`
|
||||
LabelPolicy *bool `json:"labelPolicy,omitempty"`
|
||||
LabelPolicyPrivateLabel *bool `json:"labelPolicyPrivateLabel,omitempty"`
|
||||
LabelPolicyWatermark *bool `json:"labelPolicyWatermark,omitempty"`
|
||||
CustomDomain *bool `json:"customDomain,omitempty"`
|
||||
PrivacyPolicy *bool `json:"privacyPolicy,omitempty"`
|
||||
MetadataUser *bool `json:"metadataUser,omitempty"`
|
||||
CustomTextMessage *bool `json:"customTextMessage,omitempty"`
|
||||
CustomTextLogin *bool `json:"customTextLogin,omitempty"`
|
||||
LockoutPolicy *bool `json:"lockoutPolicy,omitempty"`
|
||||
Actions *bool `json:"actions,omitempty"`
|
||||
ActionsAllowed *domain.ActionsAllowed `json:"actionsAllowed,omitempty"`
|
||||
MaxActions *int `json:"maxActions,omitempty"`
|
||||
}
|
||||
|
||||
func (e *FeaturesSetEvent) Data() interface{} {
|
||||
@ -189,9 +191,15 @@ func ChangeLockoutPolicy(lockoutPolicy bool) func(event *FeaturesSetEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeActions(actions bool) func(event *FeaturesSetEvent) {
|
||||
func ChangeActionsAllowed(allowedType domain.ActionsAllowed) func(event *FeaturesSetEvent) {
|
||||
return func(e *FeaturesSetEvent) {
|
||||
e.Actions = &actions
|
||||
e.ActionsAllowed = &allowedType
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeMaxActions(maxActions int) func(event *FeaturesSetEvent) {
|
||||
return func(e *FeaturesSetEvent) {
|
||||
e.MaxActions = &maxActions
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,6 +377,7 @@ Errors:
|
||||
NotFound: Action wurde nicht gefunden
|
||||
NotActive: Action ist nicht aktiv
|
||||
NotInactive: Action ist nicht inaktiv
|
||||
MaxAllowed: Keine weitern aktiven Actions mehr erlaubt
|
||||
Flow:
|
||||
FlowTypeMissing: FlowType fehlt
|
||||
Empty: Flow ist bereits leer
|
||||
|
@ -377,6 +377,7 @@ Errors:
|
||||
NotFound: Action not found
|
||||
NotActive: Action is not active
|
||||
NotInactive: Action is not inactive
|
||||
MaxAllowed: No additional active Actions allowed
|
||||
Flow:
|
||||
FlowTypeMissing: FlowType missing
|
||||
Empty: Flow is already empty
|
||||
|
@ -375,6 +375,7 @@ Errors:
|
||||
NotFound: L'azione non trovata
|
||||
NotActive: L'azione non è attiva
|
||||
NotInactive: L'azione non è inattiva
|
||||
MaxAllowed: Non sono permesse altre azioni attive
|
||||
Flow:
|
||||
FlowTypeMissing: FlowType mancante
|
||||
Empty: Flow è già vuoto
|
||||
|
@ -22,7 +22,7 @@ func (l *Login) customExternalUserMapping(ctx context.Context, user *domain.Exte
|
||||
}
|
||||
resourceOwner = iam.GlobalOrgID
|
||||
}
|
||||
triggerActions, err := l.query.GetActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner)
|
||||
triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(ctx, domain.FlowTypeExternalAuthentication, domain.TriggerTypePostAuthentication, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -38,7 +38,7 @@ func (l *Login) customExternalUserMapping(ctx context.Context, user *domain.Exte
|
||||
}
|
||||
|
||||
func (l *Login) customExternalUserToLoginUserMapping(user *domain.Human, tokens *oidc.Tokens, req *domain.AuthRequest, config *iam_model.IDPConfigView, metadata []*domain.Metadata, resourceOwner string) (*domain.Human, []*domain.Metadata, error) {
|
||||
triggerActions, err := l.query.GetActionsByFlowAndTriggerType(context.TODO(), domain.FlowTypeExternalAuthentication, domain.TriggerTypePreCreation, resourceOwner)
|
||||
triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(context.TODO(), domain.FlowTypeExternalAuthentication, domain.TriggerTypePreCreation, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -54,7 +54,7 @@ func (l *Login) customExternalUserToLoginUserMapping(user *domain.Human, tokens
|
||||
}
|
||||
|
||||
func (l *Login) customGrants(userID string, tokens *oidc.Tokens, req *domain.AuthRequest, config *iam_model.IDPConfigView, resourceOwner string) ([]*domain.UserGrant, error) {
|
||||
triggerActions, err := l.query.GetActionsByFlowAndTriggerType(context.TODO(), domain.FlowTypeExternalAuthentication, domain.TriggerTypePostCreation, resourceOwner)
|
||||
triggerActions, err := l.query.GetActiveActionsByFlowAndTriggerType(context.TODO(), domain.FlowTypeExternalAuthentication, domain.TriggerTypePostCreation, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
5
migrations/cockroach/V1.109__features_max_actions.sql
Normal file
5
migrations/cockroach/V1.109__features_max_actions.sql
Normal file
@ -0,0 +1,5 @@
|
||||
alter table zitadel.projections.features
|
||||
ADD COLUMN actions_allowed INT2 default 0,
|
||||
ADD COLUMN max_actions INT8 default 0;
|
||||
|
||||
update zitadel.projections.features set actions_allowed = 2 where actions = true;
|
@ -2822,6 +2822,8 @@ message SetDefaultFeaturesRequest {
|
||||
bool custom_text_login = 21;
|
||||
bool lockout_policy = 22;
|
||||
bool actions = 23;
|
||||
zitadel.features.v1.ActionsAllowed actions_allowed = 24;
|
||||
int32 max_actions = 25;
|
||||
}
|
||||
|
||||
message SetDefaultFeaturesResponse {
|
||||
@ -2862,6 +2864,8 @@ message SetOrgFeaturesRequest {
|
||||
bool custom_text_login = 22;
|
||||
bool lockout_policy = 23;
|
||||
bool actions = 24;
|
||||
zitadel.features.v1.ActionsAllowed actions_allowed = 25;
|
||||
int32 max_actions = 26;
|
||||
}
|
||||
|
||||
message SetOrgFeaturesResponse {
|
||||
|
@ -31,6 +31,8 @@ message Features {
|
||||
bool custom_text_login = 20;
|
||||
bool lockout_policy = 21;
|
||||
bool actions = 22;
|
||||
ActionsAllowed actions_allowed = 23;
|
||||
int32 max_actions = 24;
|
||||
}
|
||||
|
||||
message FeatureTier {
|
||||
@ -47,3 +49,9 @@ enum FeaturesState {
|
||||
FEATURES_STATE_CANCELED = 2;
|
||||
FEATURES_STATE_GRANDFATHERED = 3;
|
||||
}
|
||||
|
||||
enum ActionsAllowed {
|
||||
ACTIONS_ALLOWED_NOT_ALLOWED = 0;
|
||||
ACTIONS_ALLOWED_MAX = 1;
|
||||
ACTIONS_ALLOWED_UNLIMITED = 2;
|
||||
}
|
||||
|
@ -2794,30 +2794,29 @@ service ManagementService {
|
||||
};
|
||||
}
|
||||
|
||||
//TODO: enable in next release
|
||||
// rpc DeactivateAction(DeactivateActionRequest) returns (DeactivateActionResponse) {
|
||||
// option (google.api.http) = {
|
||||
// post: "/actions/{id}/_deactivate"
|
||||
// body: "*"
|
||||
// };
|
||||
//
|
||||
// option (zitadel.v1.auth_option) = {
|
||||
// permission: "org.action.write"
|
||||
// feature: "actions"
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// rpc ReactivateAction(ReactivateActionRequest) returns (ReactivateActionResponse) {
|
||||
// option (google.api.http) = {
|
||||
// post: "/actions/{id}/_reactivate"
|
||||
// body: "*"
|
||||
// };
|
||||
//
|
||||
// option (zitadel.v1.auth_option) = {
|
||||
// permission: "org.action.write"
|
||||
// feature: "actions"
|
||||
// };
|
||||
// }
|
||||
rpc DeactivateAction(DeactivateActionRequest) returns (DeactivateActionResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/actions/{id}/_deactivate"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.action.write"
|
||||
feature: "actions"
|
||||
};
|
||||
}
|
||||
|
||||
rpc ReactivateAction(ReactivateActionRequest) returns (ReactivateActionResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/actions/{id}/_reactivate"
|
||||
body: "*"
|
||||
};
|
||||
|
||||
option (zitadel.v1.auth_option) = {
|
||||
permission: "org.action.write"
|
||||
feature: "actions"
|
||||
};
|
||||
}
|
||||
|
||||
rpc DeleteAction(DeleteActionRequest) returns (DeleteActionResponse) {
|
||||
option (google.api.http) = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user