diff --git a/internal/command/member_model.go b/internal/command/member_model.go index b3bb25bc8b..cecddb3b0a 100644 --- a/internal/command/member_model.go +++ b/internal/command/member_model.go @@ -4,6 +4,7 @@ import ( "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/repository/member" + "github.com/zitadel/zitadel/internal/repository/org" ) type MemberWriteModel struct { @@ -30,7 +31,7 @@ func (wm *MemberWriteModel) Reduce() error { wm.State = domain.MemberStateActive case *member.MemberChangedEvent: wm.Roles = e.Roles - case *member.MemberRemovedEvent: + case *member.MemberRemovedEvent, *org.OrgRemovedEvent: wm.Roles = nil wm.State = domain.MemberStateRemoved } diff --git a/internal/command/org.go b/internal/command/org.go index b6c5d02d7e..173779fc90 100644 --- a/internal/command/org.go +++ b/internal/command/org.go @@ -515,6 +515,10 @@ func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation { if err != nil { return nil, err } + members, err := OrgMembers(ctx, filter, a.ID) + if err != nil { + return nil, err + } domains, err := OrgDomains(ctx, filter, a.ID) if err != nil { return nil, err @@ -527,7 +531,7 @@ func (c *Commands) prepareRemoveOrg(a *org.Aggregate) preparation.Validation { if err != nil { return nil, err } - return []eventstore.Command{org.NewOrgRemovedEvent(ctx, &a.Aggregate, writeModel.Name, usernames, domainPolicy.UserLoginMustBeDomain, domains, links, entityIds)}, nil + return []eventstore.Command{org.NewOrgRemovedEvent(ctx, &a.Aggregate, writeModel.Name, usernames, members, domainPolicy.UserLoginMustBeDomain, domains, links, entityIds)}, nil }, nil } } @@ -661,6 +665,46 @@ type userIDName struct { id string } +func OrgMembers(ctx context.Context, filter preparation.FilterToQueryReducer, orgID string) ([]string, error) { + events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). + ResourceOwner(orgID). + OrderAsc(). + AddQuery(). + AggregateTypes(org.AggregateType). + EventTypes( + org.MemberAddedEventType, + org.MemberRemovedEventType, + org.MemberCascadeRemovedEventType, + ).Builder()) + if err != nil { + return nil, err + } + ids := make([]string, 0) + for _, event := range events { + switch eventTyped := event.(type) { + case *org.MemberAddedEvent: + ids = append(ids, eventTyped.UserID) + case *org.MemberRemovedEvent: + for i := range ids { + if ids[i] == eventTyped.UserID { + ids[i] = ids[len(ids)-1] + ids = ids[:len(ids)-1] + break + } + } + case *org.MemberCascadeRemovedEvent: + for i := range ids { + if ids[i] == eventTyped.UserID { + ids[i] = ids[len(ids)-1] + ids = ids[:len(ids)-1] + break + } + } + } + } + return ids, nil +} + func OrgUsers(ctx context.Context, filter preparation.FilterToQueryReducer, orgID string) ([]string, error) { events, err := filter(ctx, eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). InstanceID(authz.GetInstance(ctx).InstanceID()). @@ -712,8 +756,10 @@ func OrgUsers(ctx context.Context, filter preparation.FilterToQueryReducer, orgI } } names := make([]string, len(users)) + ids := make([]string, len(users)) for i := range users { names[i] = users[i].name + ids[i] = users[i].id } return names, nil } diff --git a/internal/command/org_domain_model.go b/internal/command/org_domain_model.go index b387e6f4b7..0f6baf025c 100644 --- a/internal/command/org_domain_model.go +++ b/internal/command/org_domain_model.go @@ -59,6 +59,8 @@ func (wm *OrgDomainWriteModel) AppendEvents(events ...eventstore.Event) { continue } wm.WriteModel.AppendEvents(e) + case *org.OrgRemovedEvent: + wm.WriteModel.AppendEvents(e) } } } @@ -76,7 +78,7 @@ func (wm *OrgDomainWriteModel) Reduce() error { wm.Verified = true case *org.DomainPrimarySetEvent: wm.Primary = e.Domain == wm.Domain - case *org.DomainRemovedEvent: + case *org.DomainRemovedEvent, *org.OrgRemovedEvent: wm.State = domain.OrgDomainStateRemoved wm.Verified = false wm.Primary = false @@ -99,7 +101,8 @@ func (wm *OrgDomainWriteModel) Query() *eventstore.SearchQueryBuilder { org.OrgDomainVerificationAddedEventType, org.OrgDomainVerifiedEventType, org.OrgDomainPrimarySetEventType, - org.OrgDomainRemovedEventType). + org.OrgDomainRemovedEventType, + org.OrgRemovedEventType). Builder() } diff --git a/internal/command/org_member_model.go b/internal/command/org_member_model.go index 92218f6535..6c62dbbe21 100644 --- a/internal/command/org_member_model.go +++ b/internal/command/org_member_model.go @@ -44,6 +44,8 @@ func (wm *OrgMemberWriteModel) AppendEvents(events ...eventstore.Event) { continue } wm.MemberWriteModel.AppendEvents(&e.MemberCascadeRemovedEvent) + case *org.OrgRemovedEvent: + wm.MemberWriteModel.AppendEvents(e) } } } @@ -62,6 +64,7 @@ func (wm *OrgMemberWriteModel) Query() *eventstore.SearchQueryBuilder { org.MemberAddedEventType, org.MemberChangedEventType, org.MemberRemovedEventType, - org.MemberCascadeRemovedEventType). + org.MemberCascadeRemovedEventType, + org.OrgRemovedEventType). Builder() } diff --git a/internal/repository/org/org.go b/internal/repository/org/org.go index cf8a3ce114..7502622834 100644 --- a/internal/repository/org/org.go +++ b/internal/repository/org/org.go @@ -5,6 +5,7 @@ import ( "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/repository/member" "github.com/zitadel/zitadel/internal/repository/project" "github.com/zitadel/zitadel/internal/repository/user" "github.com/zitadel/zitadel/internal/zerrors" @@ -278,6 +279,7 @@ type OrgRemovedEvent struct { eventstore.BaseEvent `json:"-"` name string usernames []string + members []string loginMustBeDomain bool domains []string externalIDPs []*domain.UserIDPLink @@ -295,6 +297,9 @@ func (e *OrgRemovedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { for _, name := range e.usernames { constraints = append(constraints, user.NewRemoveUsernameUniqueConstraint(name, e.Aggregate().ID, e.loginMustBeDomain)) } + for _, id := range e.members { + constraints = append(constraints, member.NewRemoveMemberUniqueConstraint(e.Aggregate().ID, id)) + } for _, domain := range e.domains { constraints = append(constraints, NewRemoveOrgDomainUniqueConstraint(domain)) } @@ -314,7 +319,7 @@ func (e *OrgRemovedEvent) Fields() []*eventstore.FieldOperation { } } -func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string, usernames []string, loginMustBeDomain bool, domains []string, externalIDPs []*domain.UserIDPLink, samlEntityIDs []string) *OrgRemovedEvent { +func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, name string, usernames []string, members []string, loginMustBeDomain bool, domains []string, externalIDPs []*domain.UserIDPLink, samlEntityIDs []string) *OrgRemovedEvent { return &OrgRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, @@ -323,6 +328,7 @@ func NewOrgRemovedEvent(ctx context.Context, aggregate *eventstore.Aggregate, na ), name: name, usernames: usernames, + members: members, domains: domains, externalIDPs: externalIDPs, samlEntityIDs: samlEntityIDs,