mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:57:32 +00:00
fix: add user metadata to the features (#2179)
* fix: add user metadata to the features * fix: remove user metadata * fix: add test * fix: add test
This commit is contained in:
@@ -28,6 +28,7 @@ type FeaturesWriteModel struct {
|
||||
CustomDomain bool
|
||||
CustomText bool
|
||||
PrivacyPolicy bool
|
||||
MetadataUser bool
|
||||
}
|
||||
|
||||
func (wm *FeaturesWriteModel) Reduce() error {
|
||||
@@ -86,6 +87,9 @@ func (wm *FeaturesWriteModel) Reduce() error {
|
||||
if e.CustomText != nil {
|
||||
wm.CustomText = *e.CustomText
|
||||
}
|
||||
if e.MetadataUser != nil {
|
||||
wm.MetadataUser = *e.MetadataUser
|
||||
}
|
||||
case *features.FeaturesRemovedEvent:
|
||||
wm.State = domain.FeaturesStateRemoved
|
||||
}
|
||||
|
@@ -51,6 +51,7 @@ func (c *Commands) setDefaultFeatures(ctx context.Context, existingFeatures *IAM
|
||||
features.CustomDomain,
|
||||
features.CustomText,
|
||||
features.PrivacyPolicy,
|
||||
features.MetadataUser,
|
||||
)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
|
@@ -68,7 +68,8 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
labelPolicyWatermark,
|
||||
customDomain,
|
||||
customText,
|
||||
privacyPolicy bool,
|
||||
privacyPolicy,
|
||||
metadataUser bool,
|
||||
) (*iam.FeaturesSetEvent, bool) {
|
||||
|
||||
changes := make([]features.FeaturesChanges, 0)
|
||||
@@ -121,6 +122,9 @@ func (wm *IAMFeaturesWriteModel) NewSetEvent(
|
||||
if wm.PrivacyPolicy != privacyPolicy {
|
||||
changes = append(changes, features.ChangePrivacyPolicy(privacyPolicy))
|
||||
}
|
||||
if wm.MetadataUser != metadataUser {
|
||||
changes = append(changes, features.ChangeMetadataUser(metadataUser))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
|
@@ -25,6 +25,8 @@ func (wm *MetadataWriteModel) Reduce() error {
|
||||
wm.State = domain.MetadataStateActive
|
||||
case *metadata.RemovedEvent:
|
||||
wm.State = domain.MetadataStateRemoved
|
||||
case *metadata.RemovedAllEvent:
|
||||
wm.State = domain.MetadataStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
@@ -43,6 +45,8 @@ func (wm *MetadataListWriteModel) Reduce() error {
|
||||
wm.metadataList[e.Key] = e.Value
|
||||
case *metadata.RemovedEvent:
|
||||
delete(wm.metadataList, e.Key)
|
||||
case *metadata.RemovedAllEvent:
|
||||
wm.metadataList = make(map[string][]byte)
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
|
@@ -42,6 +42,7 @@ func (c *Commands) SetOrgFeatures(ctx context.Context, resourceOwner string, fea
|
||||
features.CustomDomain,
|
||||
features.CustomText,
|
||||
features.PrivacyPolicy,
|
||||
features.MetadataUser,
|
||||
)
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "Features-GE4h2", "Errors.Features.NotChanged")
|
||||
@@ -146,6 +147,15 @@ func (c *Commands) ensureOrgSettingsToFeatures(ctx context.Context, orgID string
|
||||
events = append(events, removePrivacyPolicyEvent)
|
||||
}
|
||||
}
|
||||
if !features.MetadataUser {
|
||||
removeOrgUserMetadatas, err := c.removeUserMetadataFromOrg(ctx, orgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(removeOrgUserMetadatas) > 0 {
|
||||
events = append(events, removeOrgUserMetadatas...)
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
|
@@ -75,7 +75,8 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
labelPolicyWatermark,
|
||||
customDomain,
|
||||
customText,
|
||||
privacyPolicy bool,
|
||||
privacyPolicy,
|
||||
metadataUser bool,
|
||||
) (*org.FeaturesSetEvent, bool) {
|
||||
|
||||
changes := make([]features.FeaturesChanges, 0)
|
||||
@@ -131,6 +132,9 @@ func (wm *OrgFeaturesWriteModel) NewSetEvent(
|
||||
if wm.PrivacyPolicy != privacyPolicy {
|
||||
changes = append(changes, features.ChangePrivacyPolicy(privacyPolicy))
|
||||
}
|
||||
if wm.MetadataUser != metadataUser {
|
||||
changes = append(changes, features.ChangeMetadataUser(metadataUser))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
return nil, false
|
||||
|
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/caos/zitadel/internal/repository/features"
|
||||
"github.com/caos/zitadel/internal/repository/iam"
|
||||
"github.com/caos/zitadel/internal/repository/org"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
"github.com/caos/zitadel/internal/static"
|
||||
"github.com/caos/zitadel/internal/static/mock"
|
||||
)
|
||||
@@ -99,6 +100,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -130,6 +132,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -249,6 +252,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@@ -278,6 +282,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
CustomDomain: false,
|
||||
CustomText: false,
|
||||
PrivacyPolicy: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -420,6 +425,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@@ -454,6 +460,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -603,6 +610,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@@ -640,6 +648,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -796,6 +805,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@@ -836,6 +846,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -1044,6 +1055,7 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
@@ -1095,6 +1107,171 @@ func TestCommandSide_SetOrgFeatures(t *testing.T) {
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
want: &domain.ObjectDetails{
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "set with default policies, usermetadata, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(
|
||||
context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"org1",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLoginPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
domain.PasswordlessTypeAllowed,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewPasswordComplexityPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
8,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewLabelPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"primary",
|
||||
"secondary",
|
||||
"warn",
|
||||
"font",
|
||||
"primary-dark",
|
||||
"secondary-dark",
|
||||
"warn-dark",
|
||||
"font-dark",
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
org.NewOrgAddedEvent(
|
||||
context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"org1",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewDomainAddedEvent(
|
||||
context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"org1.iam-domain",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewDomainVerifiedEvent(
|
||||
context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"org1.iam-domain",
|
||||
),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
org.NewDomainPrimarySetEvent(
|
||||
context.Background(),
|
||||
&org.NewAggregate("org1", "org1").Aggregate,
|
||||
"org1.iam-domain",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewCustomTextSetEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
domain.InitCodeMessageType,
|
||||
domain.MessageSubject,
|
||||
"text",
|
||||
language.English,
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
iam.NewPrivacyPolicyAddedEvent(
|
||||
context.Background(),
|
||||
&iam.NewAggregate().Aggregate,
|
||||
"toslink",
|
||||
"privacylink",
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
user.NewMetadataSetEvent(
|
||||
context.Background(),
|
||||
&user.NewAggregate("user1", "org1").Aggregate,
|
||||
"key",
|
||||
[]byte("value"),
|
||||
),
|
||||
),
|
||||
),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
user.NewMetadataRemovedAllEvent(context.Background(), &user.NewAggregate("user1", "org1").Aggregate),
|
||||
),
|
||||
eventFromEventPusher(
|
||||
newFeaturesSetEvent(context.Background(), "org1", "Test", domain.FeaturesStateActive, time.Hour),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
iamDomain: "iam-domain",
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
features: &domain.Features{
|
||||
TierName: "Test",
|
||||
State: domain.FeaturesStateActive,
|
||||
AuditLogRetention: time.Hour,
|
||||
LoginPolicyFactors: false,
|
||||
LoginPolicyIDP: false,
|
||||
LoginPolicyPasswordless: false,
|
||||
LoginPolicyRegistration: false,
|
||||
LoginPolicyUsernameLogin: false,
|
||||
LoginPolicyPasswordReset: false,
|
||||
PasswordComplexityPolicy: false,
|
||||
LabelPolicyPrivateLabel: false,
|
||||
LabelPolicyWatermark: false,
|
||||
CustomDomain: false,
|
||||
CustomText: false,
|
||||
PrivacyPolicy: false,
|
||||
MetadataUser: false,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -1285,6 +1462,7 @@ func TestCommandSide_RemoveOrgFeatures(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
[]*repository.Event{
|
||||
eventFromEventPusher(
|
||||
|
@@ -149,6 +149,24 @@ func (c *Commands) BulkRemoveUserMetadata(ctx context.Context, userID, resourceO
|
||||
return writeModelToObjectDetails(&removeMetadata.WriteModel), nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeUserMetadataFromOrg(ctx context.Context, resourceOwner string) ([]eventstore.EventPusher, error) {
|
||||
existingUserMetadata, err := c.getUserMetadataByOrgListModelByID(ctx, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(existingUserMetadata.UserMetadata) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
events := make([]eventstore.EventPusher, 0)
|
||||
for key, value := range existingUserMetadata.UserMetadata {
|
||||
if len(value) == 0 {
|
||||
continue
|
||||
}
|
||||
events = append(events, user.NewMetadataRemovedAllEvent(ctx, &user.NewAggregate(key, resourceOwner).Aggregate))
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (c *Commands) removeUserMetadata(ctx context.Context, userAgg *eventstore.Aggregate, metadataKey string) (pusher eventstore.EventPusher, err error) {
|
||||
pusher = user.NewMetadataRemovedEvent(
|
||||
ctx,
|
||||
@@ -175,3 +193,12 @@ func (c *Commands) getUserMetadataListModelByID(ctx context.Context, userID, res
|
||||
}
|
||||
return userMetadataWriteModel, nil
|
||||
}
|
||||
|
||||
func (c *Commands) getUserMetadataByOrgListModelByID(ctx context.Context, resourceOwner string) (*UserMetadataByOrgListWriteModel, error) {
|
||||
userMetadataWriteModel := NewUserMetadataByOrgListWriteModel(resourceOwner)
|
||||
err := c.eventstore.FilterToQueryReducer(ctx, userMetadataWriteModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return userMetadataWriteModel, nil
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/metadata"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
)
|
||||
|
||||
@@ -28,6 +29,8 @@ func (wm *UserMetadataWriteModel) AppendEvents(events ...eventstore.EventReader)
|
||||
wm.MetadataWriteModel.AppendEvents(&e.SetEvent)
|
||||
case *user.MetadataRemovedEvent:
|
||||
wm.MetadataWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
case *user.MetadataRemovedAllEvent:
|
||||
wm.MetadataWriteModel.AppendEvents(&e.RemovedAllEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +47,8 @@ func (wm *UserMetadataWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
AggregateTypes(user.AggregateType).
|
||||
EventTypes(
|
||||
user.MetadataSetType,
|
||||
user.MetadataRemovedType).
|
||||
user.MetadataRemovedType,
|
||||
user.MetadataRemovedAllType).
|
||||
Builder()
|
||||
}
|
||||
|
||||
@@ -71,6 +75,8 @@ func (wm *UserMetadataListWriteModel) AppendEvents(events ...eventstore.EventRea
|
||||
wm.MetadataListWriteModel.AppendEvents(&e.SetEvent)
|
||||
case *user.MetadataRemovedEvent:
|
||||
wm.MetadataListWriteModel.AppendEvents(&e.RemovedEvent)
|
||||
case *user.MetadataRemovedAllEvent:
|
||||
wm.MetadataListWriteModel.AppendEvents(&e.RemovedAllEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +93,69 @@ func (wm *UserMetadataListWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
AggregateTypes(user.AggregateType).
|
||||
EventTypes(
|
||||
user.MetadataSetType,
|
||||
user.MetadataRemovedType).
|
||||
user.MetadataRemovedType,
|
||||
user.MetadataRemovedAllType).
|
||||
Builder()
|
||||
}
|
||||
|
||||
type UserMetadataByOrgListWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
resourceOwner string
|
||||
UserMetadata map[string]map[string][]byte
|
||||
}
|
||||
|
||||
func NewUserMetadataByOrgListWriteModel(resourceOwner string) *UserMetadataByOrgListWriteModel {
|
||||
return &UserMetadataByOrgListWriteModel{
|
||||
resourceOwner: resourceOwner,
|
||||
UserMetadata: make(map[string]map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *UserMetadataByOrgListWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *user.MetadataSetEvent:
|
||||
wm.WriteModel.AppendEvents(&e.SetEvent)
|
||||
case *user.MetadataRemovedEvent:
|
||||
wm.WriteModel.AppendEvents(&e.RemovedEvent)
|
||||
case *user.MetadataRemovedAllEvent:
|
||||
wm.WriteModel.AppendEvents(&e.RemovedAllEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *UserMetadataByOrgListWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *metadata.SetEvent:
|
||||
if val, ok := wm.UserMetadata[e.Aggregate().ID]; ok {
|
||||
val[e.Key] = e.Value
|
||||
} else {
|
||||
wm.UserMetadata[e.Aggregate().ID] = map[string][]byte{
|
||||
e.Key: e.Value,
|
||||
}
|
||||
}
|
||||
case *metadata.RemovedEvent:
|
||||
if val, ok := wm.UserMetadata[e.Aggregate().ID]; ok {
|
||||
delete(val, e.Key)
|
||||
}
|
||||
case *metadata.RemovedAllEvent:
|
||||
if _, ok := wm.UserMetadata[e.Aggregate().ID]; ok {
|
||||
delete(wm.UserMetadata, e.Aggregate().ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *UserMetadataByOrgListWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(user.AggregateType).
|
||||
EventTypes(
|
||||
user.MetadataSetType,
|
||||
user.MetadataRemovedType,
|
||||
user.MetadataRemovedAllType).
|
||||
Builder()
|
||||
}
|
||||
|
Reference in New Issue
Block a user