diff --git a/cmd/zitadel/setup.yaml b/cmd/zitadel/setup.yaml index 8d143838e4..ea627a4ddc 100644 --- a/cmd/zitadel/setup.yaml +++ b/cmd/zitadel/setup.yaml @@ -179,3 +179,5 @@ SetUp: Greeting: Hello {{.FirstName}} {{.LastName}}, Text: The domain {{.Domain}} has been claimed by an organisation. Your current user {{.Username}} is not part of this organisation. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login. ButtonText: Login + Step11: + MigrateV1EventstoreToV2: true diff --git a/internal/setup/config.go b/internal/setup/config.go index e5ce1e4487..b2f8d25374 100644 --- a/internal/setup/config.go +++ b/internal/setup/config.go @@ -6,16 +6,17 @@ import ( ) type IAMSetUp struct { - Step1 *command.Step1 - Step2 *command.Step2 - Step3 *command.Step3 - Step4 *command.Step4 - Step5 *command.Step5 - Step6 *command.Step6 - Step7 *command.Step7 - Step8 *command.Step8 - Step9 *command.Step9 + Step1 *command.Step1 + Step2 *command.Step2 + Step3 *command.Step3 + Step4 *command.Step4 + Step5 *command.Step5 + Step6 *command.Step6 + Step7 *command.Step7 + Step8 *command.Step8 + Step9 *command.Step9 Step10 *command.Step10 + Step11 *command.Step11 } func (setup *IAMSetUp) Steps(currentDone domain.Step) ([]command.Step, error) { @@ -32,6 +33,7 @@ func (setup *IAMSetUp) Steps(currentDone domain.Step) ([]command.Step, error) { setup.Step8, setup.Step9, setup.Step10, + setup.Step11, } { if step.Step() <= currentDone { continue diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 26238d216d..3e6472808c 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -290,6 +290,8 @@ Errors: NotInactive: Benutzer Berechtigung ist nicht deaktiviert NoPermissionForProject: Benutzer hat keine Rechte auf diesem Projekt RoleKeyNotFound: Rolle konnte nicht gefunden werden + Member: + AlreadyExists: Member existiert bereits IDPConfig: AlreadyExists: IDP Konfiguration mit diesem Name existiert bereits Changes: diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 5afca93faf..8c2a785e77 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -286,6 +286,8 @@ Errors: NotInactive: User grant is not deactivated NoPermissionForProject: User has no permissions on this project RoleKeyNotFound: Role not found + Member: + AlreadyExists: Member already exists IDPConfig: AlreadyExists: IDP Configuration with this name already exists Changes: diff --git a/internal/v2/command/iam_idp_config.go b/internal/v2/command/iam_idp_config.go index 404ed3f072..d172d0e8c6 100644 --- a/internal/v2/command/iam_idp_config.go +++ b/internal/v2/command/iam_idp_config.go @@ -66,7 +66,7 @@ func (r *CommandSide) ChangeDefaultIDPConfig(ctx context.Context, config *domain return nil, caos_errs.ThrowNotFound(nil, "IAM-4M9so", "Errors.IAM.IDPConfig.NotExisting") } - changedEvent, hasChanged := existingIDP.NewChangedEvent(ctx, config.IDPConfigID, config.Name, config.StylingType) + changedEvent, hasChanged := existingIDP.NewChangedEvent(ctx, existingIDP.ResourceOwner, config.IDPConfigID, config.Name, config.StylingType) if !hasChanged { return nil, caos_errs.ThrowPreconditionFailed(nil, "IAM-4M9vs", "Errors.IAM.LabelPolicy.NotChanged") } diff --git a/internal/v2/command/iam_idp_config_model.go b/internal/v2/command/iam_idp_config_model.go index 34b3d9ab3e..c1f3c19ba7 100644 --- a/internal/v2/command/iam_idp_config_model.go +++ b/internal/v2/command/iam_idp_config_model.go @@ -84,13 +84,16 @@ func (wm *IAMIDPConfigWriteModel) AppendAndReduce(events ...eventstore.EventRead func (wm *IAMIDPConfigWriteModel) NewChangedEvent( ctx context.Context, + resourceOwner, configID, name string, stylingType domain.IDPConfigStylingType, ) (*iam.IDPConfigChangedEvent, bool) { changes := make([]idpconfig.IDPConfigChanges, 0) + oldName := "" if wm.Name != name { + oldName = wm.Name changes = append(changes, idpconfig.ChangeName(name)) } if stylingType.Valid() && wm.StylingType != stylingType { @@ -99,7 +102,7 @@ func (wm *IAMIDPConfigWriteModel) NewChangedEvent( if len(changes) == 0 { return nil, false } - changeEvent, err := iam.NewIDPConfigChangedEvent(ctx, configID, changes) + changeEvent, err := iam.NewIDPConfigChangedEvent(ctx, resourceOwner, configID, oldName, changes) if err != nil { return nil, false } diff --git a/internal/v2/command/iam_member.go b/internal/v2/command/iam_member.go index da078f7787..fd3f330700 100644 --- a/internal/v2/command/iam_member.go +++ b/internal/v2/command/iam_member.go @@ -42,7 +42,7 @@ func (r *CommandSide) addIAMMember(ctx context.Context, iamAgg *iam_repo.Aggrega return errors.ThrowAlreadyExists(nil, "IAM-sdgQ4", "Errors.IAM.Member.AlreadyExists") } - iamAgg.PushEvents(iam_repo.NewMemberAddedEvent(ctx, member.UserID, member.Roles...)) + iamAgg.PushEvents(iam_repo.NewMemberAddedEvent(ctx, iamAgg.ID(), member.UserID, member.Roles...)) return nil } @@ -89,7 +89,7 @@ func (r *CommandSide) RemoveIAMMember(ctx context.Context, userID string) error } iamAgg := IAMAggregateFromWriteModel(&m.MemberWriteModel.WriteModel) - iamAgg.PushEvents(iam_repo.NewMemberRemovedEvent(ctx, userID)) + iamAgg.PushEvents(iam_repo.NewMemberRemovedEvent(ctx, iamAgg.ID(), userID)) return r.eventstore.PushAggregate(ctx, m, iamAgg) } diff --git a/internal/v2/command/iam_model.go b/internal/v2/command/iam_model.go index b7dcbfc4e9..8993581220 100644 --- a/internal/v2/command/iam_model.go +++ b/internal/v2/command/iam_model.go @@ -27,14 +27,6 @@ func NewIAMWriteModel() *IAMWriteModel { func (wm *IAMWriteModel) AppendEvents(events ...eventstore.EventReader) { wm.WriteModel.AppendEvents(events...) - //for _, event := range events { - // switch e := event.(type) { - // case *iam.LabelPolicyAddedEvent: - // wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyAddedEvent) - // case *iam.LabelPolicyChangedEvent: - // wm.LabelPolicyWriteModel.AppendEvents(&e.LabelPolicyChangedEvent) - // } - //} } func (wm *IAMWriteModel) Reduce() error { @@ -61,17 +53,6 @@ func (wm *IAMWriteModel) Query() *eventstore.SearchQueryBuilder { ResourceOwner(wm.ResourceOwner) } -// -//func (wm *IAMLabelPolicyWriteModel) HasChanged(primaryColor, secondaryColor string) bool { -// if primaryColor != "" && wm.PrimaryColor != primaryColor { -// return true -// } -// if secondaryColor != "" && wm.SecondaryColor != secondaryColor { -// return true -// } -// return false -//} - func IAMAggregateFromWriteModel(wm *eventstore.WriteModel) *iam.Aggregate { return &iam.Aggregate{ Aggregate: *eventstore.AggregateFromWriteModel(wm, iam.AggregateType, iam.AggregateVersion), diff --git a/internal/v2/command/org_idp_config.go b/internal/v2/command/org_idp_config.go index 6e19ab913f..c38d9a43af 100644 --- a/internal/v2/command/org_idp_config.go +++ b/internal/v2/command/org_idp_config.go @@ -67,7 +67,13 @@ func (r *CommandSide) ChangeIDPConfig(ctx context.Context, config *domain.IDPCon return nil, caos_errs.ThrowNotFound(nil, "Org-4M9so", "Errors.Org.IDPConfig.NotExisting") } - changedEvent, hasChanged := existingIDP.NewChangedEvent(ctx, config.IDPConfigID, config.Name, config.StylingType) + changedEvent, hasChanged := existingIDP.NewChangedEvent( + ctx, + existingIDP.ResourceOwner, + config.IDPConfigID, + config.Name, + config.StylingType) + if !hasChanged { return nil, caos_errs.ThrowPreconditionFailed(nil, "Org-4M9vs", "Errors.Org.LabelPolicy.NotChanged") } diff --git a/internal/v2/command/org_idp_config_model.go b/internal/v2/command/org_idp_config_model.go index 19770d262d..6004d4850c 100644 --- a/internal/v2/command/org_idp_config_model.go +++ b/internal/v2/command/org_idp_config_model.go @@ -84,13 +84,16 @@ func (wm *OrgIDPConfigWriteModel) AppendAndReduce(events ...eventstore.EventRead func (wm *OrgIDPConfigWriteModel) NewChangedEvent( ctx context.Context, + resourceOwner, configID, name string, stylingType domain.IDPConfigStylingType, ) (*org.IDPConfigChangedEvent, bool) { changes := make([]idpconfig.IDPConfigChanges, 0) + oldName := "" if wm.Name != name { + oldName = wm.Name changes = append(changes, idpconfig.ChangeName(name)) } if stylingType.Valid() && wm.StylingType != stylingType { @@ -99,7 +102,7 @@ func (wm *OrgIDPConfigWriteModel) NewChangedEvent( if len(changes) == 0 { return nil, false } - changeEvent, err := org.NewIDPConfigChangedEvent(ctx, configID, changes) + changeEvent, err := org.NewIDPConfigChangedEvent(ctx, resourceOwner, configID, oldName, changes) if err != nil { return nil, false } diff --git a/internal/v2/command/org_member.go b/internal/v2/command/org_member.go index f377d7a7e4..f7e2ea49ca 100644 --- a/internal/v2/command/org_member.go +++ b/internal/v2/command/org_member.go @@ -42,7 +42,7 @@ func (r *CommandSide) addOrgMember(ctx context.Context, orgAgg *org.Aggregate, a return errors.ThrowAlreadyExists(nil, "Org-PtXi1", "Errors.Org.Member.AlreadyExists") } - orgAgg.PushEvents(org.NewMemberAddedEvent(ctx, member.UserID, member.Roles...)) + orgAgg.PushEvents(org.NewMemberAddedEvent(ctx, orgAgg.ID(), member.UserID, member.Roles...)) return nil } @@ -89,7 +89,7 @@ func (r *CommandSide) RemoveOrgMember(ctx context.Context, orgID, userID string) } orgAgg := OrgAggregateFromWriteModel(&m.MemberWriteModel.WriteModel) - orgAgg.PushEvents(org.NewMemberRemovedEvent(ctx, userID)) + orgAgg.PushEvents(org.NewMemberRemovedEvent(ctx, orgAgg.ID(), userID)) return r.eventstore.PushAggregate(ctx, m, orgAgg) } diff --git a/internal/v2/command/project.go b/internal/v2/command/project.go index 45d1668ed8..983dc7fed3 100644 --- a/internal/v2/command/project.go +++ b/internal/v2/command/project.go @@ -84,7 +84,7 @@ func (r *CommandSide) ChangeProject(ctx context.Context, projectChange *domain.P return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound") } - changedEvent, hasChanged, err := existingProject.NewChangedEvent(ctx, projectChange.Name, projectChange.ProjectRoleAssertion, projectChange.ProjectRoleCheck) + changedEvent, hasChanged, err := existingProject.NewChangedEvent(ctx, existingProject.ResourceOwner, projectChange.Name, projectChange.ProjectRoleAssertion, projectChange.ProjectRoleCheck) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (r *CommandSide) ReactivateProject(ctx context.Context, projectID string, r } projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel) - projectAgg.PushEvents(project.NewProjectDeactivatedEvent(ctx)) + projectAgg.PushEvents(project.NewProjectReactivatedEvent(ctx)) return r.eventstore.PushAggregate(ctx, existingProject, projectAgg) } diff --git a/internal/v2/command/project_grant.go b/internal/v2/command/project_grant.go index 8d5d0d3ac7..53a8737196 100644 --- a/internal/v2/command/project_grant.go +++ b/internal/v2/command/project_grant.go @@ -8,7 +8,6 @@ import ( "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/project" - "github.com/caos/zitadel/internal/v2/repository/usergrant" "reflect" ) @@ -123,7 +122,7 @@ func (r *CommandSide) removeRoleFromProjectGrant(ctx context.Context, projectAgg ) } else { projectAgg.PushEvents( - usergrant.NewUserGrantCascadeChangedEvent(ctx, existingProjectGrant.RoleKeys), + project.NewGrantCascadeChangedEvent(ctx, projectGrantID, existingProjectGrant.RoleKeys), ) } diff --git a/internal/v2/command/project_member.go b/internal/v2/command/project_member.go index 346a40dd6a..24b5ed351e 100644 --- a/internal/v2/command/project_member.go +++ b/internal/v2/command/project_member.go @@ -46,7 +46,7 @@ func (r *CommandSide) addProjectMember(ctx context.Context, projectAgg *project. return errors.ThrowAlreadyExists(nil, "PROJECT-PtXi1", "Errors.Project.Member.AlreadyExists") } - projectAgg.PushEvents(project.NewProjectMemberAddedEvent(ctx, member.UserID, member.Roles...)) + projectAgg.PushEvents(project.NewProjectMemberAddedEvent(ctx, projectAgg.ID(), member.UserID, member.Roles...)) return nil } @@ -93,7 +93,7 @@ func (r *CommandSide) RemoveProjectMember(ctx context.Context, projectID, userID } projectAgg := ProjectAggregateFromWriteModel(&m.MemberWriteModel.WriteModel) - projectAgg.PushEvents(project.NewProjectMemberRemovedEvent(ctx, userID)) + projectAgg.PushEvents(project.NewProjectMemberRemovedEvent(ctx, projectAgg.ID(), userID)) return r.eventstore.PushAggregate(ctx, m, projectAgg) } diff --git a/internal/v2/command/project_model.go b/internal/v2/command/project_model.go index 1106fdd829..28dd702663 100644 --- a/internal/v2/command/project_model.go +++ b/internal/v2/command/project_model.go @@ -72,6 +72,7 @@ func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder { func (wm *ProjectWriteModel) NewChangedEvent( ctx context.Context, + resourceOwner, name string, projectRoleAssertion, projectRoleCheck bool, @@ -79,7 +80,9 @@ func (wm *ProjectWriteModel) NewChangedEvent( changes := make([]project.ProjectChanges, 0) var err error + oldName := "" if wm.Name != name { + oldName = wm.Name changes = append(changes, project.ChangeName(name)) } if wm.ProjectRoleAssertion != projectRoleAssertion { @@ -91,7 +94,7 @@ func (wm *ProjectWriteModel) NewChangedEvent( if len(changes) == 0 { return nil, false, nil } - changeEvent, err := project.NewProjectChangeEvent(ctx, changes) + changeEvent, err := project.NewProjectChangeEvent(ctx, resourceOwner, oldName, changes) if err != nil { return nil, false, err } diff --git a/internal/v2/command/project_role.go b/internal/v2/command/project_role.go index 1568feea40..74b74fd317 100644 --- a/internal/v2/command/project_role.go +++ b/internal/v2/command/project_role.go @@ -51,7 +51,6 @@ func (r *CommandSide) addProjectRoles(ctx context.Context, projectAgg *project.A projectRole.DisplayName, projectRole.Group, projectID, - resourceOwner, ), ) } @@ -107,7 +106,7 @@ func (r *CommandSide) RemoveProjectRole(ctx context.Context, projectID, key, res } aggregates := make([]eventstore.Aggregater, 0) projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel) - projectAgg.PushEvents(project.NewRoleRemovedEvent(ctx, key, projectID, existingRole.ResourceOwner)) + projectAgg.PushEvents(project.NewRoleRemovedEvent(ctx, key, projectID)) for _, projectGrantID := range cascadingProjectGrantIds { _, err = r.removeRoleFromProjectGrant(ctx, projectAgg, projectID, projectGrantID, key, true) if err != nil { diff --git a/internal/v2/command/setup_step11.go b/internal/v2/command/setup_step11.go new file mode 100644 index 0000000000..ec47cc131b --- /dev/null +++ b/internal/v2/command/setup_step11.go @@ -0,0 +1,35 @@ +package command + +import ( + "context" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/v2/domain" + iam_repo "github.com/caos/zitadel/internal/v2/repository/iam" +) + +type Step11 struct { + MigrateV1EventstoreToV2 bool +} + +func (s *Step11) Step() domain.Step { + return domain.Step11 +} + +func (s *Step11) execute(ctx context.Context, commandSide *CommandSide) error { + return commandSide.SetupStep11(ctx, s) +} + +func (r *CommandSide) SetupStep11(ctx context.Context, step *Step11) error { + fn := func(iam *IAMWriteModel) (*iam_repo.Aggregate, error) { + iamAgg := IAMAggregateFromWriteModel(&iam.WriteModel) + uniqueConstraints := NewUniqueConstraintReadModel(ctx, r) + err := r.eventstore.FilterToQueryReducer(ctx, uniqueConstraints) + if err != nil { + return nil, err + } + iamAgg.PushEvents(iam_repo.NewMigrateUniqueConstraintEvent(ctx, uniqueConstraints.UniqueConstraints)) + logging.Log("SETUP-M9fsd").Info("migrate v1 eventstore to v2") + return iamAgg, nil + } + return r.setup(ctx, step, fn) +} diff --git a/internal/v2/command/unique_constraints_model.go b/internal/v2/command/unique_constraints_model.go new file mode 100644 index 0000000000..c61f8f4d81 --- /dev/null +++ b/internal/v2/command/unique_constraints_model.go @@ -0,0 +1,255 @@ +package command + +import ( + "context" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/iam" + "github.com/caos/zitadel/internal/v2/repository/idpconfig" + "github.com/caos/zitadel/internal/v2/repository/member" + "github.com/caos/zitadel/internal/v2/repository/org" + "github.com/caos/zitadel/internal/v2/repository/policy" + "github.com/caos/zitadel/internal/v2/repository/project" + "github.com/caos/zitadel/internal/v2/repository/user" + "github.com/caos/zitadel/internal/v2/repository/usergrant" +) + +type UniqueConstraintReadModel struct { + eventstore.WriteModel + + UniqueConstraints []*domain.UniqueConstraintMigration + commandProvider commandProvider + ctx context.Context +} + +type commandProvider interface { + getOrgIAMPolicy(ctx context.Context, orgID string) (*domain.OrgIAMPolicy, error) +} + +func NewUniqueConstraintReadModel(ctx context.Context, provider commandProvider) *UniqueConstraintReadModel { + return &UniqueConstraintReadModel{ + ctx: ctx, + commandProvider: provider, + } +} + +func (rm *UniqueConstraintReadModel) AppendEvents(events ...eventstore.EventReader) { + rm.WriteModel.AppendEvents(events...) +} + +func (rm *UniqueConstraintReadModel) Reduce() error { + for _, event := range rm.Events { + switch e := event.(type) { + case *org.OrgAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), org.NewAddOrgNameUniqueConstraint(e.Name)) + case *org.OrgChangedEvent: + rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), org.NewAddOrgNameUniqueConstraint(e.Name)) + case *org.DomainVerificationAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), org.NewAddOrgNameUniqueConstraint(e.Domain)) + case *org.DomainRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), org.UniqueOrgDomain) + case *iam.IDPConfigAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.ResourceOwner())) + case *iam.IDPConfigChangedEvent: + rm.changeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.ResourceOwner())) + case *iam.IDPConfigRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.UniqueIDPConfigNameType) + case *org.IDPConfigAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.ResourceOwner())) + case *org.IDPConfigChangedEvent: + rm.changeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.ResourceOwner())) + case *org.IDPConfigRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.ConfigID, idpconfig.UniqueIDPConfigNameType) + case *iam.MailTextAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.AggregateID(), e.MailTextType, e.Language)) + case *org.MailTextAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.MailTextType+e.Language, policy.NewAddMailTextUniqueConstraint(e.AggregateID(), e.MailTextType, e.Language)) + case *org.MailTextRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.MailTextType+e.Language, policy.UniqueMailText) + case *project.ProjectAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), project.NewAddProjectNameUniqueConstraint(e.Name, e.ResourceOwner())) + case *project.ProjectChangeEvent: + rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), project.NewAddProjectNameUniqueConstraint(*e.Name, e.ResourceOwner())) + case *project.ProjectRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), project.UniqueProjectnameType) + case *project.ApplicationAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.AggregateID())) + case *project.ApplicationChangedEvent: + rm.changeUniqueConstraint(e.AggregateID(), e.AppID, project.NewAddApplicationUniqueConstraint(e.Name, e.AggregateID())) + case *project.ApplicationRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.AppID, project.UniqueAppNameType) + case *project.GrantAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.GrantID, project.NewAddProjectGrantUniqueConstraint(e.GrantedOrgID, e.AggregateID())) + case *project.GrantRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.GrantID, project.UniqueGrantType) + case *project.GrantMemberAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.GrantID+e.UserID, project.NewAddProjectGrantMemberUniqueConstraint(e.AggregateID(), e.UserID, e.GrantID)) + case *project.GrantMemberRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.GrantID+e.UserID, project.UniqueProjectGrantMemberType) + case *project.RoleAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.Key, project.NewAddProjectRoleUniqueConstraint(e.Key, e.AggregateID())) + case *project.RoleRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.Key, project.UniqueRoleType) + case *user.HumanAddedEvent: + policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner()) + if err != nil { + logging.Log("COMMAND-0k9Gs").WithError(err).Error("could not read policy for human added event unique constraint") + continue + } + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain)) + case *user.HumanRegisteredEvent: + policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner()) + if err != nil { + logging.Log("COMMAND-m9fod").WithError(err).Error("could not read policy for human registered event unique constraint") + continue + } + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain)) + case *user.MachineAddedEvent: + policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner()) + if err != nil { + logging.Log("COMMAND-2n8vs").WithError(err).Error("could not read policy for machine added event unique constraint") + continue + } + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain)) + case *user.UserRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), user.UniqueUsername) + case *user.UsernameChangedEvent: + policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner()) + if err != nil { + logging.Log("COMMAND-5n8gk").WithError(err).Error("could not read policy for username changed event unique constraint") + continue + } + rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain)) + case *user.DomainClaimedEvent: + policy, err := rm.commandProvider.getOrgIAMPolicy(rm.ctx, e.ResourceOwner()) + if err != nil { + logging.Log("COMMAND-xb8uf").WithError(err).Error("could not read policy for domain claimed event unique constraint") + continue + } + rm.changeUniqueConstraint(e.AggregateID(), e.AggregateID(), user.NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), policy.UserLoginMustBeDomain)) + case *user.HumanExternalIDPAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.IDPConfigID+e.ExternalUserID, user.NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)) + case *user.HumanExternalIDPRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType) + case *user.HumanExternalIDPCascadeRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.IDPConfigID+e.ExternalUserID, user.UniqueExternalIDPType) + case *usergrant.UserGrantAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.AggregateID(), usergrant.NewAddUserGrantUniqueConstraint(e.ResourceOwner(), e.UserID, e.ProjectID, e.ProjectGrantID)) + case *usergrant.UserGrantRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), usergrant.UniqueUserGrant) + case *usergrant.UserGrantCascadeRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.AggregateID(), usergrant.UniqueUserGrant) + case *iam.MemberAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.UserID, member.NewAddMemberUniqueConstraint(e.AggregateID(), e.UserID)) + case *iam.MemberRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.UserID, member.UniqueMember) + case *org.MemberAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.UserID, member.NewAddMemberUniqueConstraint(e.AggregateID(), e.UserID)) + case *org.MemberRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.UserID, member.UniqueMember) + case *project.MemberAddedEvent: + rm.addUniqueConstraint(e.AggregateID(), e.UserID, member.NewAddMemberUniqueConstraint(e.AggregateID(), e.UserID)) + case *project.MemberRemovedEvent: + rm.removeUniqueConstraint(e.AggregateID(), e.UserID, member.UniqueMember) + } + } + return nil +} + +func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + AggregateIDs(rm.AggregateID). + ResourceOwner(rm.ResourceOwner). + EventTypes( + org.OrgAddedEventType, + org.OrgChangedEventType, + org.OrgDomainVerifiedEventType, + org.OrgDomainRemovedEventType, + iam.IDPConfigAddedEventType, + iam.IDPConfigChangedEventType, + iam.IDPConfigRemovedEventType, + org.IDPConfigAddedEventType, + org.IDPConfigChangedEventType, + org.IDPConfigRemovedEventType, + iam.MailTextAddedEventType, + org.MailTextAddedEventType, + org.MailTextRemovedEventType, + project.ProjectAddedType, + project.ProjectChangedType, + project.ProjectRemovedType, + project.ApplicationAddedType, + project.ApplicationChangedType, + project.ApplicationRemovedType, + project.GrantAddedType, + project.GrantRemovedType, + project.GrantMemberAddedType, + project.GrantMemberRemovedType, + project.RoleAddedType, + project.RoleRemovedType, + user.HumanAddedType, + user.HumanRegisteredType, + user.MachineAddedEventType, + user.UserUserNameChangedType, + user.UserDomainClaimedType, + user.UserRemovedType, + user.HumanExternalIDPAddedType, + user.HumanExternalIDPRemovedType, + user.HumanExternalIDPCascadeRemovedType, + usergrant.UserGrantAddedType, + usergrant.UserGrantRemovedType, + usergrant.UserGrantCascadeRemovedType, + iam.MemberAddedEventType, + iam.MemberRemovedEventType, + org.MemberAddedEventType, + org.MemberRemovedEventType, + project.MemberAddedType, + project.MemberRemovedType, + ) +} + +func (rm *UniqueConstraintReadModel) getUniqueConstraint(aggregateID, objectID, constraintType string) *domain.UniqueConstraintMigration { + for _, uniqueConstraint := range rm.UniqueConstraints { + if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraintType { + return uniqueConstraint + } + } + return nil +} + +func (rm *UniqueConstraintReadModel) addUniqueConstraint(aggregateID, objectID string, constraint *eventstore.EventUniqueConstraint) { + migrateUniqueConstraint := &domain.UniqueConstraintMigration{ + AggregateID: aggregateID, + ObjectID: objectID, + UniqueType: constraint.UniqueType, + UniqueField: constraint.UniqueField, + ErrorMessage: constraint.ErrorMessage, + } + rm.UniqueConstraints = append(rm.UniqueConstraints, migrateUniqueConstraint) +} + +func (rm *UniqueConstraintReadModel) changeUniqueConstraint(aggregateID, objectID string, constraint *eventstore.EventUniqueConstraint) { + for i, uniqueConstraint := range rm.UniqueConstraints { + if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraint.UniqueType { + rm.UniqueConstraints[i] = &domain.UniqueConstraintMigration{ + AggregateID: aggregateID, + ObjectID: objectID, + UniqueType: constraint.UniqueType, + UniqueField: constraint.UniqueField, + ErrorMessage: constraint.ErrorMessage, + } + return + } + } +} + +func (rm *UniqueConstraintReadModel) removeUniqueConstraint(aggregateID, objectID, constraintType string) { + for i, uniqueConstraint := range rm.UniqueConstraints { + if uniqueConstraint.AggregateID == aggregateID && uniqueConstraint.ObjectID == objectID && uniqueConstraint.UniqueType == constraintType { + copy(rm.UniqueConstraints[i:], rm.UniqueConstraints[i+1:]) + rm.UniqueConstraints[len(rm.UniqueConstraints)-1] = nil + rm.UniqueConstraints = rm.UniqueConstraints[:len(rm.UniqueConstraints)-1] + return + } + } +} diff --git a/internal/v2/command/user.go b/internal/v2/command/user.go index 8e7a9bda42..a4b2ca41e0 100644 --- a/internal/v2/command/user.go +++ b/internal/v2/command/user.go @@ -218,11 +218,16 @@ func (r *CommandSide) userDomainClaimed(ctx context.Context, userID string) (_ * changedUserGrant := NewUserWriteModel(userID, existingUser.ResourceOwner) userAgg := UserAggregateFromWriteModel(&changedUserGrant.WriteModel) + orgIAMPolicy, err := r.getOrgIAMPolicy(ctx, existingUser.ResourceOwner) + if err != nil { + return nil, nil, err + } + id, err := r.idGenerator.Next() if err != nil { return nil, nil, err } - userAgg.PushEvents(user.NewDomainClaimedEvent(ctx, fmt.Sprintf("%s@temporary.%s", id, r.iamDomain))) + userAgg.PushEvents(user.NewDomainClaimedEvent(ctx, fmt.Sprintf("%s@temporary.%s", id, r.iamDomain), existingUser.UserName, orgIAMPolicy.UserLoginMustBeDomain)) return userAgg, changedUserGrant, nil } diff --git a/internal/v2/command/user_grant.go b/internal/v2/command/user_grant.go index 160389873d..e83108c946 100644 --- a/internal/v2/command/user_grant.go +++ b/internal/v2/command/user_grant.go @@ -251,11 +251,21 @@ func (r *CommandSide) removeUserGrant(ctx context.Context, grantID, resourceOwne userGrantAgg := UserGrantAggregateFromWriteModel(&removeUserGrant.WriteModel) if !cascade { userGrantAgg.PushEvents( - usergrant.NewUserGrantRemovedEvent(ctx, existingUserGrant.ResourceOwner, existingUserGrant.UserID, existingUserGrant.ProjectID), + usergrant.NewUserGrantRemovedEvent( + ctx, + existingUserGrant.ResourceOwner, + existingUserGrant.UserID, + existingUserGrant.ProjectID, + existingUserGrant.ProjectGrantID), ) } else { userGrantAgg.PushEvents( - usergrant.NewUserGrantCascadeRemovedEvent(ctx, existingUserGrant.ResourceOwner, existingUserGrant.UserID, existingUserGrant.ProjectID), + usergrant.NewUserGrantCascadeRemovedEvent( + ctx, + existingUserGrant.ResourceOwner, + existingUserGrant.UserID, + existingUserGrant.ProjectID, + existingUserGrant.ProjectGrantID), ) } diff --git a/internal/v2/command/user_human_externalidp_model.go b/internal/v2/command/user_human_externalidp_model.go index cde992a8d8..4551df2b3c 100644 --- a/internal/v2/command/user_human_externalidp_model.go +++ b/internal/v2/command/user_human_externalidp_model.go @@ -37,7 +37,7 @@ func (wm *HumanExternalIDPWriteModel) Reduce() error { case *user.HumanExternalIDPAddedEvent: wm.IDPConfigID = e.IDPConfigID wm.DisplayName = e.DisplayName - wm.ExternalUserID = e.UserID + wm.ExternalUserID = e.ExternalUserID wm.State = domain.ExternalIDPStateActive case *user.HumanExternalIDPRemovedEvent: wm.State = domain.ExternalIDPStateRemoved diff --git a/internal/v2/domain/step.go b/internal/v2/domain/step.go index 4b87ed5294..05a6d884ff 100644 --- a/internal/v2/domain/step.go +++ b/internal/v2/domain/step.go @@ -13,6 +13,7 @@ const ( Step8 Step9 Step10 + Step11 //StepCount marks the the length of possible steps (StepCount-1 == last possible step) StepCount ) diff --git a/internal/v2/domain/unique_constraint_migration.go b/internal/v2/domain/unique_constraint_migration.go new file mode 100644 index 0000000000..f699e68ae3 --- /dev/null +++ b/internal/v2/domain/unique_constraint_migration.go @@ -0,0 +1,9 @@ +package domain + +type UniqueConstraintMigration struct { + AggregateID string + ObjectID string + UniqueType string + UniqueField string + ErrorMessage string +} diff --git a/internal/v2/repository/iam/eventstore.go b/internal/v2/repository/iam/eventstore.go index f57efa2568..4a239fdad4 100644 --- a/internal/v2/repository/iam/eventstore.go +++ b/internal/v2/repository/iam/eventstore.go @@ -9,6 +9,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(SetupDoneEventType, SetupStepMapper). RegisterFilterEventMapper(GlobalOrgSetEventType, GlobalOrgSetMapper). RegisterFilterEventMapper(ProjectSetEventType, ProjectSetMapper). + RegisterFilterEventMapper(UniqueConstraintsMigratedEventType, MigrateUniqueConstraintEventMapper). RegisterFilterEventMapper(LabelPolicyAddedEventType, LabelPolicyAddedEventMapper). RegisterFilterEventMapper(LabelPolicyChangedEventType, LabelPolicyChangedEventMapper). RegisterFilterEventMapper(LoginPolicyAddedEventType, LoginPolicyAddedEventMapper). @@ -33,6 +34,10 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(LoginPolicyIDPProviderAddedEventType, IdentityProviderAddedEventMapper). RegisterFilterEventMapper(LoginPolicyIDPProviderRemovedEventType, IdentityProviderRemovedEventMapper). RegisterFilterEventMapper(LoginPolicyIDPProviderCascadeRemovedEventType, IdentityProviderCascadeRemovedEventMapper). + RegisterFilterEventMapper(LoginPolicySecondFactorAddedEventType, SecondFactorAddedEventMapper). + RegisterFilterEventMapper(LoginPolicySecondFactorRemovedEventType, SecondFactorRemovedEventMapper). + RegisterFilterEventMapper(LoginPolicyMultiFactorAddedEventType, MultiFactorAddedEventMapper). + RegisterFilterEventMapper(LoginPolicyMultiFactorRemovedEventType, MultiFactorRemovedEventMapper). RegisterFilterEventMapper(MailTemplateAddedEventType, MailTemplateAddedEventMapper). RegisterFilterEventMapper(MailTemplateChangedEventType, MailTemplateChangedEventMapper). RegisterFilterEventMapper(MailTextAddedEventType, MailTextAddedEventMapper). diff --git a/internal/v2/repository/iam/idp_config.go b/internal/v2/repository/iam/idp_config.go index 9bf4edf08c..b01a6b8a3f 100644 --- a/internal/v2/repository/iam/idp_config.go +++ b/internal/v2/repository/iam/idp_config.go @@ -59,12 +59,15 @@ type IDPConfigChangedEvent struct { func NewIDPConfigChangedEvent( ctx context.Context, - configID string, + resourceOwner, + configID, + oldName string, changes []idpconfig.IDPConfigChanges, ) (*IDPConfigChangedEvent, error) { changeEvent, err := idpconfig.NewIDPConfigChangedEvent( - eventstore.NewBaseEventForPush(ctx, IDPConfigChangedEventType), + eventstore.NewBaseEventForPushWithResourceOwner(ctx, IDPConfigChangedEventType, resourceOwner), configID, + oldName, changes, ) if err != nil { diff --git a/internal/v2/repository/iam/member.go b/internal/v2/repository/iam/member.go index 59961bc790..412a294ea3 100644 --- a/internal/v2/repository/iam/member.go +++ b/internal/v2/repository/iam/member.go @@ -19,6 +19,7 @@ type MemberAddedEvent struct { func NewMemberAddedEvent( ctx context.Context, + aggregateID, userID string, roles ...string, ) *MemberAddedEvent { @@ -29,6 +30,7 @@ func NewMemberAddedEvent( ctx, MemberAddedEventType, ), + aggregateID, userID, roles..., ), @@ -80,6 +82,7 @@ type MemberRemovedEvent struct { func NewMemberRemovedEvent( ctx context.Context, + aggregateID, userID string, ) *MemberRemovedEvent { @@ -89,6 +92,7 @@ func NewMemberRemovedEvent( ctx, MemberRemovedEventType, ), + aggregateID, userID, ), } diff --git a/internal/v2/repository/iam/migrate_unique_constraints.go b/internal/v2/repository/iam/migrate_unique_constraints.go new file mode 100644 index 0000000000..f7ee3cd51d --- /dev/null +++ b/internal/v2/repository/iam/migrate_unique_constraints.go @@ -0,0 +1,54 @@ +package iam + +import ( + "context" + "github.com/caos/zitadel/internal/v2/domain" + + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/eventstore/v2/repository" +) + +const ( + UniqueConstraintsMigratedEventType eventstore.EventType = "iam.unique.constraints.migrated" +) + +type MigrateUniqueConstraintEvent struct { + eventstore.BaseEvent `json:"-"` + + uniqueConstraintMigrations []*domain.UniqueConstraintMigration `json:"-"` +} + +func NewAddMigrateUniqueConstraint(uniqueMigration *domain.UniqueConstraintMigration) *eventstore.EventUniqueConstraint { + return eventstore.NewAddEventUniqueConstraint( + uniqueMigration.UniqueType, + uniqueMigration.UniqueField, + uniqueMigration.ErrorMessage) +} + +func (e *MigrateUniqueConstraintEvent) Data() interface{} { + return nil +} + +func (e *MigrateUniqueConstraintEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + constraints := make([]*eventstore.EventUniqueConstraint, len(e.uniqueConstraintMigrations)) + for i, uniqueMigration := range e.uniqueConstraintMigrations { + constraints[i] = NewAddMigrateUniqueConstraint(uniqueMigration) + } + return constraints +} + +func NewMigrateUniqueConstraintEvent(ctx context.Context, uniqueConstraintMigrations []*domain.UniqueConstraintMigration) *MigrateUniqueConstraintEvent { + return &MigrateUniqueConstraintEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + UniqueConstraintsMigratedEventType, + ), + uniqueConstraintMigrations: uniqueConstraintMigrations, + } +} + +func MigrateUniqueConstraintEventMapper(event *repository.Event) (eventstore.EventReader, error) { + return &MigrateUniqueConstraintEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + }, nil +} diff --git a/internal/v2/repository/iam/policy_login_factors.go b/internal/v2/repository/iam/policy_login_factors.go index 93f1336673..ca7151d3d7 100644 --- a/internal/v2/repository/iam/policy_login_factors.go +++ b/internal/v2/repository/iam/policy_login_factors.go @@ -31,7 +31,7 @@ func NewLoginPolicySecondFactorAddedEvent( } } -func SecondFactorAddedEventEventMapper(event *repository.Event) (eventstore.EventReader, error) { +func SecondFactorAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { e, err := policy.SecondFactorAddedEventMapper(event) if err != nil { return nil, err @@ -58,7 +58,7 @@ func NewLoginPolicySecondFactorRemovedEvent( } } -func SecondFactorRemovedEventEventMapper(event *repository.Event) (eventstore.EventReader, error) { +func SecondFactorRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) { e, err := policy.SecondFactorRemovedEventMapper(event) if err != nil { return nil, err @@ -84,7 +84,7 @@ func NewLoginPolicyMultiFactorAddedEvent( } } -func MultiFactorAddedEventEventMapper(event *repository.Event) (eventstore.EventReader, error) { +func MultiFactorAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { e, err := policy.MultiFactorAddedEventMapper(event) if err != nil { return nil, err @@ -111,7 +111,7 @@ func NewLoginPolicyMultiFactorRemovedEvent( } } -func MultiFactorRemovedEventEventMapper(event *repository.Event) (eventstore.EventReader, error) { +func MultiFactorRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) { e, err := policy.MultiFactorRemovedEventMapper(event) if err != nil { return nil, err diff --git a/internal/v2/repository/idpconfig/idp_config.go b/internal/v2/repository/idpconfig/idp_config.go index 3b8779af3e..1a7d2acd3e 100644 --- a/internal/v2/repository/idpconfig/idp_config.go +++ b/internal/v2/repository/idpconfig/idp_config.go @@ -10,19 +10,19 @@ import ( ) const ( - uniqueIDPConfigNameType = "idp_config_names" + UniqueIDPConfigNameType = "idp_config_names" ) func NewAddIDPConfigNameUniqueConstraint(idpConfigName, resourceOwner string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueIDPConfigNameType, + UniqueIDPConfigNameType, idpConfigName+resourceOwner, "Errors.IDPConfig.AlreadyExists") } func NewRemoveIDPConfigNameUniqueConstraint(idpConfigName, resourceOwner string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueIDPConfigNameType, + UniqueIDPConfigNameType, idpConfigName+resourceOwner) } @@ -78,6 +78,7 @@ type IDPConfigChangedEvent struct { ConfigID string `json:"idpConfigId"` Name *string `json:"name,omitempty"` StylingType *domain.IDPConfigStylingType `json:"stylingType,omitempty"` + oldName string `json:"-"` } func (e *IDPConfigChangedEvent) Data() interface{} { @@ -85,12 +86,19 @@ func (e *IDPConfigChangedEvent) Data() interface{} { } func (e *IDPConfigChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil + if e.oldName == "" { + return nil + } + return []*eventstore.EventUniqueConstraint{ + NewRemoveIDPConfigNameUniqueConstraint(e.oldName, e.ResourceOwner()), + NewAddIDPConfigNameUniqueConstraint(*e.Name, e.ResourceOwner()), + } } func NewIDPConfigChangedEvent( base *eventstore.BaseEvent, - configID string, + configID, + oldName string, changes []IDPConfigChanges, ) (*IDPConfigChangedEvent, error) { if len(changes) == 0 { @@ -99,6 +107,7 @@ func NewIDPConfigChangedEvent( changeEvent := &IDPConfigChangedEvent{ BaseEvent: *base, ConfigID: configID, + oldName: oldName, } for _, change := range changes { change(changeEvent) diff --git a/internal/v2/repository/member/events.go b/internal/v2/repository/member/events.go index 2118285dfa..177c021335 100644 --- a/internal/v2/repository/member/events.go +++ b/internal/v2/repository/member/events.go @@ -2,22 +2,39 @@ package member import ( "encoding/json" + "fmt" "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/eventstore/v2/repository" ) const ( + UniqueMember = "member" AddedEventType = "member.added" ChangedEventType = "member.changed" RemovedEventType = "member.removed" ) +func NewAddMemberUniqueConstraint(aggregateID, userID string) *eventstore.EventUniqueConstraint { + return eventstore.NewAddEventUniqueConstraint( + UniqueMember, + fmt.Sprintf("%s:%s", aggregateID, userID), + "Errors.Member.AlreadyExists") +} + +func NewRemoveMemberUniqueConstraint(aggregateID, userID string) *eventstore.EventUniqueConstraint { + return eventstore.NewRemoveEventUniqueConstraint( + UniqueMember, + fmt.Sprintf("%s:%s", aggregateID, userID), + ) +} + type MemberAddedEvent struct { eventstore.BaseEvent `json:"-"` - Roles []string `json:"roles"` - UserID string `json:"userId"` + Roles []string `json:"roles"` + UserID string `json:"userId"` + aggregateID string } func (e *MemberAddedEvent) Data() interface{} { @@ -25,19 +42,21 @@ func (e *MemberAddedEvent) Data() interface{} { } func (e *MemberAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil + return []*eventstore.EventUniqueConstraint{NewAddMemberUniqueConstraint(e.aggregateID, e.UserID)} } func NewMemberAddedEvent( base *eventstore.BaseEvent, + aggregateID, userID string, roles ...string, ) *MemberAddedEvent { return &MemberAddedEvent{ - BaseEvent: *base, - Roles: roles, - UserID: userID, + BaseEvent: *base, + aggregateID: aggregateID, + Roles: roles, + UserID: userID, } } @@ -97,7 +116,8 @@ func ChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) type MemberRemovedEvent struct { eventstore.BaseEvent `json:"-"` - UserID string `json:"userId"` + UserID string `json:"userId"` + aggregateID string } func (e *MemberRemovedEvent) Data() interface{} { @@ -105,17 +125,19 @@ func (e *MemberRemovedEvent) Data() interface{} { } func (e *MemberRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil + return []*eventstore.EventUniqueConstraint{NewRemoveMemberUniqueConstraint(e.aggregateID, e.UserID)} } func NewRemovedEvent( base *eventstore.BaseEvent, + aggregateID, userID string, ) *MemberRemovedEvent { return &MemberRemovedEvent{ - BaseEvent: *base, - UserID: userID, + BaseEvent: *base, + aggregateID: aggregateID, + UserID: userID, } } diff --git a/internal/v2/repository/org/domain.go b/internal/v2/repository/org/domain.go index 4c92c33eed..3640ddf485 100644 --- a/internal/v2/repository/org/domain.go +++ b/internal/v2/repository/org/domain.go @@ -12,7 +12,7 @@ import ( ) const ( - uniqueOrgDomain = "org_domain" + UniqueOrgDomain = "org_domain" domainEventPrefix = orgEventTypePrefix + "domain." OrgDomainAddedEventType = domainEventPrefix + "added" OrgDomainVerificationAddedEventType = domainEventPrefix + "verification.added" @@ -24,14 +24,14 @@ const ( func NewAddOrgDomainUniqueConstraint(orgDomain string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueOrgDomain, + UniqueOrgDomain, orgDomain, "Errors.Org.Domain.AlreadyExists") } func NewRemoveOrgDomainUniqueConstraint(orgDomain string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueOrgDomain, + UniqueOrgDomain, orgDomain) } @@ -84,7 +84,7 @@ func (e *DomainVerificationAddedEvent) Data() interface{} { } func (e *DomainVerificationAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewAddOrgDomainUniqueConstraint(e.Domain)} + return nil } func NewDomainVerificationAddedEvent( @@ -162,7 +162,7 @@ func (e *DomainVerifiedEvent) Data() interface{} { } func (e *DomainVerifiedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil + return []*eventstore.EventUniqueConstraint{NewAddOrgDomainUniqueConstraint(e.Domain)} } func NewDomainVerifiedEvent(ctx context.Context, domain string) *DomainVerifiedEvent { diff --git a/internal/v2/repository/org/eventstore.go b/internal/v2/repository/org/eventstore.go index 3e0f83cadf..d02707957d 100644 --- a/internal/v2/repository/org/eventstore.go +++ b/internal/v2/repository/org/eventstore.go @@ -49,5 +49,12 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(MailTemplateRemovedEventType, MailTemplateRemovedEventMapper). RegisterFilterEventMapper(MailTextAddedEventType, MailTextAddedEventMapper). RegisterFilterEventMapper(MailTextChangedEventType, MailTextChangedEventMapper). - RegisterFilterEventMapper(MailTextRemovedEventType, MailTextRemovedEventMapper) + RegisterFilterEventMapper(MailTextRemovedEventType, MailTextRemovedEventMapper). + RegisterFilterEventMapper(IDPConfigAddedEventType, IDPConfigAddedEventMapper). + RegisterFilterEventMapper(IDPConfigChangedEventType, IDPConfigChangedEventMapper). + RegisterFilterEventMapper(IDPConfigRemovedEventType, IDPConfigRemovedEventMapper). + RegisterFilterEventMapper(IDPConfigDeactivatedEventType, IDPConfigDeactivatedEventMapper). + RegisterFilterEventMapper(IDPConfigReactivatedEventType, IDPConfigReactivatedEventMapper). + RegisterFilterEventMapper(IDPOIDCConfigAddedEventType, IDPOIDCConfigAddedEventMapper). + RegisterFilterEventMapper(IDPOIDCConfigChangedEventType, IDPOIDCConfigChangedEventMapper) } diff --git a/internal/v2/repository/org/idp_config.go b/internal/v2/repository/org/idp_config.go index 21882186ae..efd137d0bb 100644 --- a/internal/v2/repository/org/idp_config.go +++ b/internal/v2/repository/org/idp_config.go @@ -59,12 +59,15 @@ type IDPConfigChangedEvent struct { func NewIDPConfigChangedEvent( ctx context.Context, - configID string, + resourceOwner, + configID, + oldName string, changes []idpconfig.IDPConfigChanges, ) (*IDPConfigChangedEvent, error) { changeEvent, err := idpconfig.NewIDPConfigChangedEvent( - eventstore.NewBaseEventForPush(ctx, IDPConfigChangedEventType), + eventstore.NewBaseEventForPushWithResourceOwner(ctx, IDPConfigChangedEventType, resourceOwner), configID, + oldName, changes, ) if err != nil { diff --git a/internal/v2/repository/org/member.go b/internal/v2/repository/org/member.go index c808005141..dccffa83df 100644 --- a/internal/v2/repository/org/member.go +++ b/internal/v2/repository/org/member.go @@ -19,6 +19,7 @@ type MemberAddedEvent struct { func NewMemberAddedEvent( ctx context.Context, + aggregateID, userID string, roles ...string, ) *MemberAddedEvent { @@ -28,6 +29,7 @@ func NewMemberAddedEvent( ctx, MemberAddedEventType, ), + aggregateID, userID, roles..., ), @@ -80,6 +82,7 @@ type MemberRemovedEvent struct { func NewMemberRemovedEvent( ctx context.Context, + aggregateID, userID string, ) *MemberRemovedEvent { @@ -89,6 +92,7 @@ func NewMemberRemovedEvent( ctx, MemberRemovedEventType, ), + aggregateID, userID, ), } diff --git a/internal/v2/repository/org/org.go b/internal/v2/repository/org/org.go index ee6a4f18ce..6b7b8597d5 100644 --- a/internal/v2/repository/org/org.go +++ b/internal/v2/repository/org/org.go @@ -70,7 +70,8 @@ func OrgAddedEventMapper(event *repository.Event) (eventstore.EventReader, error type OrgChangedEvent struct { eventstore.BaseEvent `json:"-"` - Name string `json:"name,omitempty"` + Name string `json:"name,omitempty"` + oldName string `json:"-"` } func (e *OrgChangedEvent) Data() interface{} { @@ -78,16 +79,20 @@ func (e *OrgChangedEvent) Data() interface{} { } func (e *OrgChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil + return []*eventstore.EventUniqueConstraint{ + NewRemoveOrgDomainUniqueConstraint(e.oldName), + NewAddOrgNameUniqueConstraint(e.Name), + } } -func NewOrgChangedEvent(ctx context.Context, name string) *OrgChangedEvent { +func NewOrgChangedEvent(ctx context.Context, oldName, newName string) *OrgChangedEvent { return &OrgChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, OrgChangedEventType, ), - Name: name, + Name: newName, + oldName: oldName, } } diff --git a/internal/v2/repository/policy/mail_text.go b/internal/v2/repository/policy/mail_text.go index 3f0a17fbb2..564921c634 100644 --- a/internal/v2/repository/policy/mail_text.go +++ b/internal/v2/repository/policy/mail_text.go @@ -9,7 +9,7 @@ import ( ) const ( - uniqueMailText = "mail_text" + UniqueMailText = "mail_text" mailTextPolicyPrefix = mailPolicyPrefix + "text." MailTextPolicyAddedEventType = mailTextPolicyPrefix + "added" MailTextPolicyChangedEventType = mailTextPolicyPrefix + "changed" @@ -18,14 +18,14 @@ const ( func NewAddMailTextUniqueConstraint(aggregateID, mailTextType, langugage string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueMailText, + UniqueMailText, fmt.Sprintf("%v:%v:%v", aggregateID, mailTextType, langugage), "Errors.Org.AlreadyExists") } func NewRemoveMailTextUniqueConstraint(aggregateID, mailTextType, langugage string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueMailText, + UniqueMailText, fmt.Sprintf("%v:%v:%v", aggregateID, mailTextType, langugage)) } diff --git a/internal/v2/repository/project/application.go b/internal/v2/repository/project/application.go index 18b977ebd3..35ddb7662b 100644 --- a/internal/v2/repository/project/application.go +++ b/internal/v2/repository/project/application.go @@ -11,7 +11,7 @@ import ( ) const ( - uniqueAppNameType = "appname" + UniqueAppNameType = "appname" applicationEventTypePrefix = projectEventTypePrefix + "application." ApplicationAddedType = applicationEventTypePrefix + "added" ApplicationChangedType = applicationEventTypePrefix + "changed" @@ -22,14 +22,14 @@ const ( func NewAddApplicationUniqueConstraint(name, projectID string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueAppNameType, + UniqueAppNameType, fmt.Sprintf("%s:%s", name, projectID), "Errors.Project.App.AlreadyExists") } func NewRemoveApplicationUniqueConstraint(name, projectID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueAppNameType, + UniqueAppNameType, fmt.Sprintf("%s:%s", name, projectID)) } diff --git a/internal/v2/repository/project/eventstore.go b/internal/v2/repository/project/eventstore.go index ee5c632365..9da51d47ec 100644 --- a/internal/v2/repository/project/eventstore.go +++ b/internal/v2/repository/project/eventstore.go @@ -18,7 +18,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(RoleRemovedType, RoleRemovedEventMapper). RegisterFilterEventMapper(GrantAddedType, GrantAddedEventMapper). RegisterFilterEventMapper(GrantChangedType, GrantChangedEventMapper). - RegisterFilterEventMapper(GrantCascadeChangedType, GrantChangedEventMapper). + RegisterFilterEventMapper(GrantCascadeChangedType, GrantCascadeChangedEventMapper). RegisterFilterEventMapper(GrantDeactivatedType, GrantDeactivateEventMapper). RegisterFilterEventMapper(GrantReactivatedType, GrantReactivatedEventMapper). RegisterFilterEventMapper(GrantRemovedType, GrantRemovedEventMapper). @@ -26,7 +26,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(GrantMemberChangedType, GrantMemberChangedEventMapper). RegisterFilterEventMapper(GrantMemberRemovedType, GrantMemberRemovedEventMapper). RegisterFilterEventMapper(ApplicationAddedType, ApplicationAddedEventMapper). - RegisterFilterEventMapper(ApplicationChangedType, ApplicationAddedEventMapper). + RegisterFilterEventMapper(ApplicationChangedType, ApplicationChangedEventMapper). RegisterFilterEventMapper(ApplicationRemovedType, ApplicationRemovedEventMapper). RegisterFilterEventMapper(ApplicationDeactivatedType, ApplicationDeactivatedEventMapper). RegisterFilterEventMapper(ApplicationReactivatedType, ApplicationReactivatedEventMapper). diff --git a/internal/v2/repository/project/grant.go b/internal/v2/repository/project/grant.go index 45d3dc9021..4611bb9b8c 100644 --- a/internal/v2/repository/project/grant.go +++ b/internal/v2/repository/project/grant.go @@ -10,7 +10,7 @@ import ( ) var ( - uniqueGrantType = "project_Grant" + UniqueGrantType = "project_grant" grantEventTypePrefix = projectEventTypePrefix + "grant." GrantAddedType = grantEventTypePrefix + "added" GrantChangedType = grantEventTypePrefix + "changed" @@ -22,14 +22,14 @@ var ( func NewAddProjectGrantUniqueConstraint(grantedOrgID, projectID string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueRoleType, + UniqueRoleType, fmt.Sprintf("%s:%s", grantedOrgID, projectID), "Errors.Project.Grant.AlreadyExists") } func NewRemoveProjectGrantUniqueConstraint(grantedOrgID, projectID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueRoleType, + UniqueRoleType, fmt.Sprintf("%s:%s", grantedOrgID, projectID)) } diff --git a/internal/v2/repository/project/grant_member.go b/internal/v2/repository/project/grant_member.go index 99a65297e8..a9e56304e4 100644 --- a/internal/v2/repository/project/grant_member.go +++ b/internal/v2/repository/project/grant_member.go @@ -11,22 +11,22 @@ import ( ) var ( - uniqueProjectGrantType = "project_grant" - GrantMemberAddedType = grantEventTypePrefix + member.AddedEventType - GrantMemberChangedType = grantEventTypePrefix + member.ChangedEventType - GrantMemberRemovedType = grantEventTypePrefix + member.RemovedEventType + UniqueProjectGrantMemberType = "project_grant_member" + GrantMemberAddedType = grantEventTypePrefix + member.AddedEventType + GrantMemberChangedType = grantEventTypePrefix + member.ChangedEventType + GrantMemberRemovedType = grantEventTypePrefix + member.RemovedEventType ) func NewAddProjectGrantMemberUniqueConstraint(projectID, userID, grantID string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueProjectGrantType, + UniqueProjectGrantMemberType, fmt.Sprintf("%s:%s:%s", projectID, userID, grantID), "Errors.Project.Member.AlreadyExists") } func NewRemoveProjectGrantMemberUniqueConstraint(projectID, userID, grantID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueProjectGrantType, + UniqueProjectGrantMemberType, fmt.Sprintf("%s:%s:%s", projectID, userID, grantID), ) } diff --git a/internal/v2/repository/project/member.go b/internal/v2/repository/project/member.go index 447e8a1e91..c1b4411d49 100644 --- a/internal/v2/repository/project/member.go +++ b/internal/v2/repository/project/member.go @@ -19,6 +19,7 @@ type MemberAddedEvent struct { func NewProjectMemberAddedEvent( ctx context.Context, + aggregateID, userID string, roles ...string, ) *MemberAddedEvent { @@ -28,6 +29,7 @@ func NewProjectMemberAddedEvent( ctx, MemberAddedType, ), + aggregateID, userID, roles..., ), @@ -80,6 +82,7 @@ type MemberRemovedEvent struct { func NewProjectMemberRemovedEvent( ctx context.Context, + aggregateID, userID string, ) *MemberRemovedEvent { @@ -89,6 +92,7 @@ func NewProjectMemberRemovedEvent( ctx, MemberRemovedType, ), + aggregateID, userID, ), } diff --git a/internal/v2/repository/project/project.go b/internal/v2/repository/project/project.go index 5f20563934..838e4b0723 100644 --- a/internal/v2/repository/project/project.go +++ b/internal/v2/repository/project/project.go @@ -10,7 +10,7 @@ import ( ) const ( - uniqueProjectnameType = "project_names" + UniqueProjectnameType = "project_names" projectEventTypePrefix = eventstore.EventType("project.") ProjectAddedType = projectEventTypePrefix + "added" ProjectChangedType = projectEventTypePrefix + "changed" @@ -21,14 +21,14 @@ const ( func NewAddProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueProjectnameType, + UniqueProjectnameType, projectName+resourceOwner, "Errors.Project.AlreadyExists") } func NewRemoveProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueProjectnameType, + UniqueProjectnameType, projectName+resourceOwner) } @@ -78,6 +78,7 @@ type ProjectChangeEvent struct { Name *string `json:"name,omitempty"` ProjectRoleAssertion *bool `json:"projectRoleAssertion,omitempty"` ProjectRoleCheck *bool `json:"projectRoleCheck,omitempty"` + oldName string } func (e *ProjectChangeEvent) Data() interface{} { @@ -85,19 +86,27 @@ func (e *ProjectChangeEvent) Data() interface{} { } func (e *ProjectChangeEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + if e.oldName != "" { + return []*eventstore.EventUniqueConstraint{ + NewRemoveProjectNameUniqueConstraint(e.oldName, e.ResourceOwner()), + NewAddProjectNameUniqueConstraint(*e.Name, e.ResourceOwner()), + } + } return nil } func NewProjectChangeEvent( ctx context.Context, + resourceOwner, oldName string, changes []ProjectChanges) (*ProjectChangeEvent, error) { if len(changes) == 0 { return nil, errors.ThrowPreconditionFailed(nil, "PROJECT-mV9xc", "Errors.NoChangesFound") } changeEvent := &ProjectChangeEvent{ - BaseEvent: *eventstore.NewBaseEventForPush( + BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner( ctx, ProjectChangedType, + resourceOwner, ), } for _, change := range changes { diff --git a/internal/v2/repository/project/role.go b/internal/v2/repository/project/role.go index 7f78bae90a..e68e86b8bd 100644 --- a/internal/v2/repository/project/role.go +++ b/internal/v2/repository/project/role.go @@ -10,24 +10,24 @@ import ( ) var ( - uniqueRoleType = "project_role" + UniqueRoleType = "project_role" roleEventTypePrefix = projectEventTypePrefix + "role." RoleAddedType = roleEventTypePrefix + "added" RoleChangedType = roleEventTypePrefix + "changed" RoleRemovedType = roleEventTypePrefix + "removed" ) -func NewAddProjectRoleUniqueConstraint(roleKey, projectID, resourceOwner string) *eventstore.EventUniqueConstraint { +func NewAddProjectRoleUniqueConstraint(roleKey, projectID string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueRoleType, - fmt.Sprintf("%s:%s:%s", roleKey, projectID, resourceOwner), + UniqueRoleType, + fmt.Sprintf("%s:%s", roleKey, projectID), "Errors.Project.Role.AlreadyExists") } -func NewRemoveProjectRoleUniqueConstraint(roleKey, projectID, resourceOwner string) *eventstore.EventUniqueConstraint { +func NewRemoveProjectRoleUniqueConstraint(roleKey, projectID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueRoleType, - fmt.Sprintf("%s:%s:%s", roleKey, projectID, resourceOwner)) + UniqueRoleType, + fmt.Sprintf("%s:%s", roleKey, projectID)) } type RoleAddedEvent struct { @@ -44,15 +44,14 @@ func (e *RoleAddedEvent) Data() interface{} { } func (e *RoleAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewAddProjectRoleUniqueConstraint(e.Key, e.projectID, e.ResourceOwner())} + return []*eventstore.EventUniqueConstraint{NewAddProjectRoleUniqueConstraint(e.Key, e.projectID)} } -func NewRoleAddedEvent(ctx context.Context, key, displayName, group, projectID, resourceOwner string) *RoleAddedEvent { +func NewRoleAddedEvent(ctx context.Context, key, displayName, group, projectID string) *RoleAddedEvent { return &RoleAddedEvent{ - BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner( + BaseEvent: *eventstore.NewBaseEventForPush( ctx, RoleAddedType, - resourceOwner, ), Key: key, DisplayName: displayName, @@ -144,7 +143,7 @@ type RoleRemovedEvent struct { eventstore.BaseEvent `json:"-"` Key string `json:"key,omitempty"` - projectID string + projectID string `json:"-"` } func (e *RoleRemovedEvent) Data() interface{} { @@ -152,15 +151,14 @@ func (e *RoleRemovedEvent) Data() interface{} { } func (e *RoleRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewRemoveProjectRoleUniqueConstraint(e.Key, e.projectID, e.ResourceOwner())} + return []*eventstore.EventUniqueConstraint{NewRemoveProjectRoleUniqueConstraint(e.Key, e.projectID)} } -func NewRoleRemovedEvent(ctx context.Context, key, projectID, resourceOwner string) *RoleRemovedEvent { +func NewRoleRemovedEvent(ctx context.Context, key, projectID string) *RoleRemovedEvent { return &RoleRemovedEvent{ - BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner( + BaseEvent: *eventstore.NewBaseEventForPush( ctx, RoleRemovedType, - resourceOwner, ), Key: key, projectID: projectID, diff --git a/internal/v2/repository/user/eventstore.go b/internal/v2/repository/user/eventstore.go index a3d50f3865..b0758c39eb 100644 --- a/internal/v2/repository/user/eventstore.go +++ b/internal/v2/repository/user/eventstore.go @@ -43,7 +43,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(UserRemovedType, UserRemovedEventMapper). RegisterFilterEventMapper(UserTokenAddedType, UserTokenAddedEventMapper). RegisterFilterEventMapper(UserDomainClaimedType, DomainClaimedEventMapper). - RegisterFilterEventMapper(UserDomainClaimedSentType, DomainClaimedEventMapper). + RegisterFilterEventMapper(UserDomainClaimedSentType, DomainClaimedSentEventMapper). RegisterFilterEventMapper(UserUserNameChangedType, UsernameChangedEventMapper). RegisterFilterEventMapper(HumanAddedType, HumanAddedEventMapper). RegisterFilterEventMapper(HumanRegisteredType, HumanRegisteredEventMapper). diff --git a/internal/v2/repository/user/human_external_idp.go b/internal/v2/repository/user/human_external_idp.go index 8c8bf8cc54..c38b1f17bb 100644 --- a/internal/v2/repository/user/human_external_idp.go +++ b/internal/v2/repository/user/human_external_idp.go @@ -9,7 +9,7 @@ import ( ) const ( - uniqueExternalIDPType = "external_idps" + UniqueExternalIDPType = "external_idps" externalIDPEventPrefix = humanEventPrefix + "externalidp." externalLoginEventPrefix = humanEventPrefix + "externallogin." @@ -22,23 +22,23 @@ const ( func NewAddExternalIDPUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueExternalIDPType, + UniqueExternalIDPType, idpConfigID+externalUserID, "Errors.User.ExternalIDP.AlreadyExists") } func NewRemoveExternalIDPUniqueConstraint(idpConfigID, externalUserID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueExternalIDPType, + UniqueExternalIDPType, idpConfigID+externalUserID) } type HumanExternalIDPAddedEvent struct { eventstore.BaseEvent `json:"-"` - IDPConfigID string `json:"idpConfigId,omitempty"` - UserID string `json:"userId,omitempty"` - DisplayName string `json:"displayName,omitempty"` + IDPConfigID string `json:"idpConfigId,omitempty"` + ExternalUserID string `json:"userId,omitempty"` + DisplayName string `json:"displayName,omitempty"` } func (e *HumanExternalIDPAddedEvent) Data() interface{} { @@ -46,7 +46,7 @@ func (e *HumanExternalIDPAddedEvent) Data() interface{} { } func (e *HumanExternalIDPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.UserID)} + return []*eventstore.EventUniqueConstraint{NewAddExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)} } func NewHumanExternalIDPAddedEvent(ctx context.Context, idpConfigID, displayName, externalUserID string) *HumanExternalIDPAddedEvent { @@ -55,9 +55,9 @@ func NewHumanExternalIDPAddedEvent(ctx context.Context, idpConfigID, displayName ctx, HumanExternalIDPAddedType, ), - IDPConfigID: idpConfigID, - DisplayName: displayName, - UserID: externalUserID, + IDPConfigID: idpConfigID, + DisplayName: displayName, + ExternalUserID: externalUserID, } } @@ -77,8 +77,8 @@ func HumanExternalIDPAddedEventMapper(event *repository.Event) (eventstore.Event type HumanExternalIDPRemovedEvent struct { eventstore.BaseEvent `json:"-"` - IDPConfigID string `json:"idpConfigId"` - UserID string `json:"userId,omitempty"` + IDPConfigID string `json:"idpConfigId"` + ExternalUserID string `json:"userId,omitempty"` } func (e *HumanExternalIDPRemovedEvent) Data() interface{} { @@ -86,7 +86,7 @@ func (e *HumanExternalIDPRemovedEvent) Data() interface{} { } func (e *HumanExternalIDPRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.UserID)} + return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)} } func NewHumanExternalIDPRemovedEvent(ctx context.Context, idpConfigID, externalUserID string) *HumanExternalIDPRemovedEvent { @@ -95,8 +95,8 @@ func NewHumanExternalIDPRemovedEvent(ctx context.Context, idpConfigID, externalU ctx, HumanExternalIDPRemovedType, ), - IDPConfigID: idpConfigID, - UserID: externalUserID, + IDPConfigID: idpConfigID, + ExternalUserID: externalUserID, } } @@ -116,8 +116,8 @@ func HumanExternalIDPRemovedEventMapper(event *repository.Event) (eventstore.Eve type HumanExternalIDPCascadeRemovedEvent struct { eventstore.BaseEvent `json:"-"` - IDPConfigID string `json:"idpConfigId"` - UserID string `json:"userId,omitempty"` + IDPConfigID string `json:"idpConfigId"` + ExternalUserID string `json:"userId,omitempty"` } func (e *HumanExternalIDPCascadeRemovedEvent) Data() interface{} { @@ -125,7 +125,7 @@ func (e *HumanExternalIDPCascadeRemovedEvent) Data() interface{} { } func (e *HumanExternalIDPCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.UserID)} + return []*eventstore.EventUniqueConstraint{NewRemoveExternalIDPUniqueConstraint(e.IDPConfigID, e.ExternalUserID)} } func NewHumanExternalIDPCascadeRemovedEvent(ctx context.Context, idpConfigID, externalUserID string) *HumanExternalIDPCascadeRemovedEvent { @@ -134,8 +134,8 @@ func NewHumanExternalIDPCascadeRemovedEvent(ctx context.Context, idpConfigID, ex ctx, HumanExternalIDPCascadeRemovedType, ), - IDPConfigID: idpConfigID, - UserID: externalUserID, + IDPConfigID: idpConfigID, + ExternalUserID: externalUserID, } } diff --git a/internal/v2/repository/user/user.go b/internal/v2/repository/user/user.go index b02dad50ad..367964536a 100644 --- a/internal/v2/repository/user/user.go +++ b/internal/v2/repository/user/user.go @@ -10,7 +10,7 @@ import ( ) const ( - uniqueUsername = "usernames" + UniqueUsername = "usernames" userEventTypePrefix = eventstore.EventType("user.") UserLockedType = userEventTypePrefix + "locked" UserUnlockedType = userEventTypePrefix + "unlocked" @@ -29,7 +29,7 @@ func NewAddUsernameUniqueConstraint(userName, resourceOwner string, userLoginMus uniqueUserName = userName + resourceOwner } return eventstore.NewAddEventUniqueConstraint( - uniqueUsername, + UniqueUsername, uniqueUserName, "Errors.User.AlreadyExists") } @@ -40,7 +40,7 @@ func NewRemoveUsernameUniqueConstraint(userName, resourceOwner string, userLogin uniqueUserName = userName + resourceOwner } return eventstore.NewRemoveEventUniqueConstraint( - uniqueUsername, + UniqueUsername, uniqueUserName) } @@ -245,7 +245,9 @@ func UserTokenAddedEventMapper(event *repository.Event) (eventstore.EventReader, type DomainClaimedEvent struct { eventstore.BaseEvent `json:"-"` - UserName string `json:"userName"` + UserName string `json:"userName"` + oldUserName string `json:"-"` + userLoginMustBeDomain bool `json:"-"` } func (e *DomainClaimedEvent) Data() interface{} { @@ -253,19 +255,26 @@ func (e *DomainClaimedEvent) Data() interface{} { } func (e *DomainClaimedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return nil + return []*eventstore.EventUniqueConstraint{ + NewRemoveUsernameUniqueConstraint(e.oldUserName, e.ResourceOwner(), e.userLoginMustBeDomain), + NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.userLoginMustBeDomain), + } } func NewDomainClaimedEvent( ctx context.Context, - userName string, + userName, + oldUserName string, + userLoginMustBeDomain bool, ) *DomainClaimedEvent { return &DomainClaimedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, UserDomainClaimedType, ), - UserName: userName, + UserName: userName, + oldUserName: oldUserName, + userLoginMustBeDomain: userLoginMustBeDomain, } } @@ -314,8 +323,8 @@ type UsernameChangedEvent struct { eventstore.BaseEvent `json:"-"` UserName string `json:"userName"` - OldUserName string - UserLoginMustBeDomain bool + oldUserName string `json:"-"` + userLoginMustBeDomain bool `json:"-"` } func (e *UsernameChangedEvent) Data() interface{} { @@ -324,8 +333,8 @@ func (e *UsernameChangedEvent) Data() interface{} { func (e *UsernameChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { return []*eventstore.EventUniqueConstraint{ - NewRemoveUsernameUniqueConstraint(e.OldUserName, e.ResourceOwner(), e.UserLoginMustBeDomain), - NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.UserLoginMustBeDomain), + NewRemoveUsernameUniqueConstraint(e.oldUserName, e.ResourceOwner(), e.userLoginMustBeDomain), + NewAddUsernameUniqueConstraint(e.UserName, e.ResourceOwner(), e.userLoginMustBeDomain), } } @@ -341,8 +350,8 @@ func NewUsernameChangedEvent( UserUserNameChangedType, ), UserName: newUserName, - OldUserName: oldUserName, - UserLoginMustBeDomain: userLoginMustBeDomain, + oldUserName: oldUserName, + userLoginMustBeDomain: userLoginMustBeDomain, } } diff --git a/internal/v2/repository/usergrant/user_grant.go b/internal/v2/repository/usergrant/user_grant.go index 0ca5a40f64..f216a934ef 100644 --- a/internal/v2/repository/usergrant/user_grant.go +++ b/internal/v2/repository/usergrant/user_grant.go @@ -10,7 +10,7 @@ import ( ) const ( - uniqueUserGrant = "user_grant" + UniqueUserGrant = "user_grant" userGrantEventTypePrefix = eventstore.EventType("user.grant.") UserGrantAddedType = userGrantEventTypePrefix + "added" UserGrantChangedType = userGrantEventTypePrefix + "changed" @@ -21,17 +21,17 @@ const ( UserGrantReactivatedType = userGrantEventTypePrefix + "reactivated" ) -func NewAddUserGrantUniqueConstraint(resourceOwner, userID, projectID string) *eventstore.EventUniqueConstraint { +func NewAddUserGrantUniqueConstraint(resourceOwner, userID, projectID, projectGrantID string) *eventstore.EventUniqueConstraint { return eventstore.NewAddEventUniqueConstraint( - uniqueUserGrant, - fmt.Sprintf("%s:%s:%s", resourceOwner, userID, projectID), + UniqueUserGrant, + fmt.Sprintf("%s:%s:%s:%v", resourceOwner, userID, projectID, projectGrantID), "Errors.UserGrant.AlreadyExists") } -func NewRemoveUserGrantUniqueConstraint(resourceOwner, userID, projectID string) *eventstore.EventUniqueConstraint { +func NewRemoveUserGrantUniqueConstraint(resourceOwner, userID, projectID, projectGrantID string) *eventstore.EventUniqueConstraint { return eventstore.NewRemoveEventUniqueConstraint( - uniqueUserGrant, - fmt.Sprintf("%s:%s:%s", resourceOwner, userID, projectID)) + UniqueUserGrant, + fmt.Sprintf("%s:%s:%s:%S", resourceOwner, userID, projectID, projectGrantID)) } type UserGrantAddedEvent struct { @@ -48,7 +48,7 @@ func (e *UserGrantAddedEvent) Data() interface{} { } func (e *UserGrantAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewAddUserGrantUniqueConstraint(e.ResourceOwner(), e.UserID, e.ProjectID)} + return []*eventstore.EventUniqueConstraint{NewAddUserGrantUniqueConstraint(e.ResourceOwner(), e.UserID, e.ProjectID, e.ProjectGrantID)} } func NewUserGrantAddedEvent( @@ -162,8 +162,9 @@ func UserGrantCascadeChangedEventMapper(event *repository.Event) (eventstore.Eve type UserGrantRemovedEvent struct { eventstore.BaseEvent `json:"-"` - userID string - projectID string + userID string `json:"-"` + projectID string `json:"-"` + projectGrantID string `json:"-"` } func (e *UserGrantRemovedEvent) Data() interface{} { @@ -171,18 +172,19 @@ func (e *UserGrantRemovedEvent) Data() interface{} { } func (e *UserGrantRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewRemoveUserGrantUniqueConstraint(e.ResourceOwner(), e.userID, e.projectID)} + return []*eventstore.EventUniqueConstraint{NewRemoveUserGrantUniqueConstraint(e.ResourceOwner(), e.userID, e.projectID, e.projectGrantID)} } -func NewUserGrantRemovedEvent(ctx context.Context, resourceOwner, userID, projectID string) *UserGrantRemovedEvent { +func NewUserGrantRemovedEvent(ctx context.Context, resourceOwner, userID, projectID, projectGrantID string) *UserGrantRemovedEvent { return &UserGrantRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner( ctx, UserGrantRemovedType, resourceOwner, ), - userID: userID, - projectID: projectID, + userID: userID, + projectID: projectID, + projectGrantID: projectGrantID, } } @@ -194,8 +196,9 @@ func UserGrantRemovedEventMapper(event *repository.Event) (eventstore.EventReade type UserGrantCascadeRemovedEvent struct { eventstore.BaseEvent `json:"-"` - userID string - projectID string + userID string `json:"-"` + projectID string `json:"-"` + projectGrantID string `json:"-"` } func (e *UserGrantCascadeRemovedEvent) Data() interface{} { @@ -203,18 +206,19 @@ func (e *UserGrantCascadeRemovedEvent) Data() interface{} { } func (e *UserGrantCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { - return []*eventstore.EventUniqueConstraint{NewRemoveUserGrantUniqueConstraint(e.ResourceOwner(), e.userID, e.projectID)} + return []*eventstore.EventUniqueConstraint{NewRemoveUserGrantUniqueConstraint(e.ResourceOwner(), e.userID, e.projectID, e.projectGrantID)} } -func NewUserGrantCascadeRemovedEvent(ctx context.Context, resourceOwner, userID, projectID string) *UserGrantCascadeRemovedEvent { +func NewUserGrantCascadeRemovedEvent(ctx context.Context, resourceOwner, userID, projectID, projectGrantID string) *UserGrantCascadeRemovedEvent { return &UserGrantCascadeRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner( ctx, UserGrantCascadeRemovedType, resourceOwner, ), - userID: userID, - projectID: projectID, + userID: userID, + projectID: projectID, + projectGrantID: projectGrantID, } }