fix: Remove user with cascading memberships (#1811)

* fix: remove usermemberships on user remove

* fix: text user remove with memberships

* fix: translations

* Update internal/iam/repository/eventsourcing/model/types.go

Co-authored-by: Livio Amstutz <livio.a@gmail.com>

* fix: uncomment tests

* fix: remove memberships if user removed

Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
Fabi 2021-06-07 07:20:47 +02:00 committed by GitHub
parent 9ffc9d9330
commit 1143e3773e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 693 additions and 84 deletions

View File

@ -110,7 +110,8 @@ func (m *IAMMember) processIAMMember(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case model.IAMMemberRemoved:
case model.IAMMemberRemoved,
model.IAMMemberCascadeRemoved:
err := member.SetData(event)
if err != nil {
return err

View File

@ -166,7 +166,11 @@ func (s *Server) RemoveUser(ctx context.Context, req *mgmt_pb.RemoveUserRequest)
if err != nil {
return nil, err
}
objectDetails, err := s.command.RemoveUser(ctx, req.Id, authz.GetCtxData(ctx).OrgID, userGrantsToIDs(grants)...)
membersShips, err := s.user.UserMembershipsByUserID(ctx, req.Id)
if err != nil {
return nil, err
}
objectDetails, err := s.command.RemoveUser(ctx, req.Id, authz.GetCtxData(ctx).OrgID, UserMembershipViewsToDomain(membersShips), userGrantsToIDs(grants)...)
if err != nil {
return nil, err
}

View File

@ -241,3 +241,38 @@ func ListUserMembershipsRequestToModel(req *mgmt_pb.ListUserMembershipsRequest)
Queries: queries,
}, nil
}
func UserMembershipViewsToDomain(memberships []*user_model.UserMembershipView) []*domain.UserMembership {
result := make([]*domain.UserMembership, len(memberships))
for i, membership := range memberships {
result[i] = &domain.UserMembership{
UserID: membership.UserID,
MemberType: MemberTypeToDomain(membership.MemberType),
AggregateID: membership.AggregateID,
ObjectID: membership.ObjectID,
Roles: membership.Roles,
DisplayName: membership.DisplayName,
CreationDate: membership.CreationDate,
ChangeDate: membership.ChangeDate,
ResourceOwner: membership.ResourceOwner,
ResourceOwnerName: membership.ResourceOwnerName,
Sequence: membership.Sequence,
}
}
return result
}
func MemberTypeToDomain(mType user_model.MemberType) domain.MemberType {
switch mType {
case user_model.MemberTypeIam:
return domain.MemberTypeIam
case user_model.MemberTypeOrganisation:
return domain.MemberTypeOrganisation
case user_model.MemberTypeProject:
return domain.MemberTypeProject
case user_model.MemberTypeProjectGrant:
return domain.MemberTypeProjectGrant
default:
return domain.MemberTypeUnspecified
}
}

View File

@ -185,11 +185,13 @@ func (u *UserGrant) processProject(event *es_models.Event) (err error) {
u.fillProjectData(grant, project)
}
return u.view.PutUserGrants(grants, event)
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved:
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged,
proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberCascadeRemoved:
member := new(proj_es_model.ProjectMember)
member.SetData(event)
return u.processMember(event, "PROJECT", event.AggregateID, member.UserID, member.Roles)
case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged, proj_es_model.ProjectGrantMemberRemoved:
case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged,
proj_es_model.ProjectGrantMemberRemoved, proj_es_model.ProjectGrantMemberCascadeRemoved:
member := new(proj_es_model.ProjectGrantMember)
member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
@ -200,7 +202,8 @@ func (u *UserGrant) processProject(event *es_models.Event) (err error) {
func (u *UserGrant) processOrg(event *es_models.Event) (err error) {
switch event.Type {
case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged, org_es_model.OrgMemberRemoved:
case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged,
org_es_model.OrgMemberRemoved, org_es_model.OrgMemberCascadeRemoved:
member := new(org_es_model.OrgMember)
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
@ -260,7 +263,8 @@ func (u *UserGrant) processIAMMember(event *es_models.Event, rolePrefix string,
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event)
case iam_es_model.IAMMemberRemoved:
case iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
@ -306,8 +310,11 @@ func (u *UserGrant) processMember(event *es_models.Event, rolePrefix, roleSuffix
grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event)
case org_es_model.OrgMemberRemoved,
org_es_model.OrgMemberCascadeRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved:
proj_es_model.ProjectMemberCascadeRemoved,
proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID)
if err != nil && !errors.IsNotFound(err) {

View File

@ -108,7 +108,8 @@ func (m *UserMembership) processIAM(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
case iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event)
default:
return m.view.ProcessedUserMembershipSequence(event)
@ -139,7 +140,8 @@ func (m *UserMembership) processOrg(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
case org_es_model.OrgMemberRemoved,
org_es_model.OrgMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event)
case org_es_model.OrgChanged:
return m.updateOrgName(event)
@ -202,7 +204,8 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
case proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
@ -210,7 +213,8 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
case proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)

View File

@ -102,11 +102,14 @@ func (u *UserGrant) Reduce(event *es_models.Event) (err error) {
func (u *UserGrant) processProject(event *es_models.Event) (err error) {
switch event.Type {
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved:
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged,
proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberCascadeRemoved:
member := new(proj_es_model.ProjectMember)
member.SetData(event)
return u.processMember(event, "PROJECT", event.AggregateID, member.UserID, member.Roles)
case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged, proj_es_model.ProjectGrantMemberRemoved:
case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged,
proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
member := new(proj_es_model.ProjectGrantMember)
member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
@ -117,7 +120,8 @@ func (u *UserGrant) processProject(event *es_models.Event) (err error) {
func (u *UserGrant) processOrg(event *es_models.Event) (err error) {
switch event.Type {
case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged, org_es_model.OrgMemberRemoved:
case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged,
org_es_model.OrgMemberRemoved, org_es_model.OrgMemberCascadeRemoved:
member := new(org_es_model.OrgMember)
member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles)
@ -161,7 +165,8 @@ func (u *UserGrant) processIAMMember(event *es_models.Event, rolePrefix string,
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event)
case iam_es_model.IAMMemberRemoved:
case iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil {
@ -207,8 +212,11 @@ func (u *UserGrant) processMember(event *es_models.Event, rolePrefix, roleSuffix
grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event)
case org_es_model.OrgMemberRemoved,
org_es_model.OrgMemberCascadeRemoved,
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved:
proj_es_model.ProjectMemberCascadeRemoved,
proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID)
if err != nil && !errors.IsNotFound(err) {

View File

@ -108,7 +108,8 @@ func (m *UserMembership) processIAM(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
case iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event)
default:
return m.view.ProcessedUserMembershipSequence(event)
@ -139,7 +140,8 @@ func (m *UserMembership) processOrg(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
case org_es_model.OrgMemberRemoved,
org_es_model.OrgMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event)
case org_es_model.OrgChanged:
return m.updateOrgName(event)
@ -202,7 +204,7 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
case proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
@ -210,7 +212,8 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
case proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)

View File

@ -2,9 +2,10 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore"
"reflect"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
@ -99,7 +100,8 @@ func (c *Commands) RemoveIAMMember(ctx context.Context, userID string) (*domain.
}
iamAgg := IAMAggregateFromWriteModel(&memberWriteModel.MemberWriteModel.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, iam_repo.NewMemberRemovedEvent(ctx, iamAgg, userID))
removeEvent := c.removeIAMMember(ctx, iamAgg, userID, false)
pushedEvents, err := c.eventstore.PushEvents(ctx, removeEvent)
if err != nil {
return nil, err
}
@ -111,6 +113,17 @@ func (c *Commands) RemoveIAMMember(ctx context.Context, userID string) (*domain.
return writeModelToObjectDetails(&memberWriteModel.MemberWriteModel.WriteModel), nil
}
func (c *Commands) removeIAMMember(ctx context.Context, iamAgg *eventstore.Aggregate, userID string, cascade bool) eventstore.EventPusher {
if cascade {
return iam_repo.NewMemberCascadeRemovedEvent(
ctx,
iamAgg,
userID)
} else {
return iam_repo.NewMemberRemovedEvent(ctx, iamAgg, userID)
}
}
func (c *Commands) iamMemberWriteModelByID(ctx context.Context, userID string) (member *IAMMemberWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()

View File

@ -40,6 +40,11 @@ func (wm *IAMMemberWriteModel) AppendEvents(events ...eventstore.EventReader) {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberRemovedEvent)
case *iam.MemberCascadeRemovedEvent:
if e.UserID != wm.MemberWriteModel.UserID {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}
@ -55,5 +60,6 @@ func (wm *IAMMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
iam.MemberAddedEventType,
iam.MemberChangedEventType,
iam.MemberRemovedEventType)
iam.MemberRemovedEventType,
iam.MemberCascadeRemovedEventType)
}

View File

@ -2,9 +2,10 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore"
"reflect"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
@ -92,7 +93,8 @@ func (c *Commands) RemoveOrgMember(ctx context.Context, orgID, userID string) (*
}
orgAgg := OrgAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, org.NewMemberRemovedEvent(ctx, orgAgg, userID))
removeEvent := c.removeOrgMember(ctx, orgAgg, userID, false)
pushedEvents, err := c.eventstore.PushEvents(ctx, removeEvent)
if err != nil {
return nil, err
}
@ -103,6 +105,17 @@ func (c *Commands) RemoveOrgMember(ctx context.Context, orgID, userID string) (*
return writeModelToObjectDetails(&m.WriteModel), nil
}
func (c *Commands) removeOrgMember(ctx context.Context, orgAgg *eventstore.Aggregate, userID string, cascade bool) eventstore.EventPusher {
if cascade {
return org.NewMemberCascadeRemovedEvent(
ctx,
orgAgg,
userID)
} else {
return org.NewMemberRemovedEvent(ctx, orgAgg, userID)
}
}
func (c *Commands) orgMemberWriteModelByID(ctx context.Context, orgID, userID string) (member *OrgMemberWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()

View File

@ -39,6 +39,11 @@ func (wm *OrgMemberWriteModel) AppendEvents(events ...eventstore.EventReader) {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberRemovedEvent)
case *org.MemberCascadeRemovedEvent:
if e.UserID != wm.MemberWriteModel.UserID {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}
@ -54,5 +59,6 @@ func (wm *OrgMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
EventTypes(
org.MemberAddedEventType,
org.MemberChangedEventType,
org.MemberRemovedEventType)
org.MemberRemovedEventType,
org.MemberCascadeRemovedEventType)
}

View File

@ -7,6 +7,7 @@ import (
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/project"
"github.com/caos/zitadel/internal/telemetry/tracing"
)
@ -87,7 +88,8 @@ func (c *Commands) RemoveProjectGrantMember(ctx context.Context, projectID, user
}
projectAgg := ProjectAggregateFromWriteModel(&m.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, project.NewProjectGrantMemberRemovedEvent(ctx, projectAgg, userID, grantID))
removeEvent := c.removeProjectGrantMember(ctx, projectAgg, userID, grantID, false)
pushedEvents, err := c.eventstore.PushEvents(ctx, removeEvent)
if err != nil {
return nil, err
}
@ -98,6 +100,18 @@ func (c *Commands) RemoveProjectGrantMember(ctx context.Context, projectID, user
return writeModelToObjectDetails(&m.WriteModel), nil
}
func (c *Commands) removeProjectGrantMember(ctx context.Context, projectAgg *eventstore.Aggregate, userID, grantID string, cascade bool) eventstore.EventPusher {
if cascade {
return project.NewProjectGrantMemberCascadeRemovedEvent(
ctx,
projectAgg,
userID,
grantID)
} else {
return project.NewProjectGrantMemberRemovedEvent(ctx, projectAgg, userID, grantID)
}
}
func (c *Commands) projectGrantMemberWriteModelByID(ctx context.Context, projectID, userID, grantID string) (member *ProjectGrantMemberWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()

View File

@ -44,6 +44,11 @@ func (wm *ProjectGrantMemberWriteModel) AppendEvents(events ...eventstore.EventR
continue
}
wm.WriteModel.AppendEvents(e)
case *project.GrantMemberCascadeRemovedEvent:
if e.UserID != wm.UserID || e.GrantID != wm.GrantID {
continue
}
wm.WriteModel.AppendEvents(e)
case *project.GrantRemovedEvent:
if e.GrantID != wm.GrantID {
continue
@ -65,6 +70,8 @@ func (wm *ProjectGrantMemberWriteModel) Reduce() error {
wm.Roles = e.Roles
case *project.GrantMemberRemovedEvent:
wm.State = domain.MemberStateRemoved
case *project.GrantMemberCascadeRemovedEvent:
wm.State = domain.MemberStateRemoved
case *project.GrantRemovedEvent, *project.ProjectRemovedEvent:
wm.State = domain.MemberStateRemoved
}
@ -79,6 +86,7 @@ func (wm *ProjectGrantMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
project.GrantMemberAddedType,
project.GrantMemberChangedType,
project.GrantMemberRemovedType,
project.GrantMemberCascadeRemovedType,
project.GrantRemovedType,
project.ProjectRemovedType)
}

View File

@ -2,9 +2,10 @@ package command
import (
"context"
"github.com/caos/zitadel/internal/eventstore"
"reflect"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
caos_errs "github.com/caos/zitadel/internal/errors"
@ -99,7 +100,8 @@ func (c *Commands) RemoveProjectMember(ctx context.Context, projectID, userID, r
}
projectAgg := ProjectAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
pushedEvents, err := c.eventstore.PushEvents(ctx, project.NewProjectMemberRemovedEvent(ctx, projectAgg, userID))
removeEvent := c.removeProjectMember(ctx, projectAgg, userID, false)
pushedEvents, err := c.eventstore.PushEvents(ctx, removeEvent)
if err != nil {
return nil, err
}
@ -110,6 +112,17 @@ func (c *Commands) RemoveProjectMember(ctx context.Context, projectID, userID, r
return writeModelToObjectDetails(&m.WriteModel), nil
}
func (c *Commands) removeProjectMember(ctx context.Context, projectAgg *eventstore.Aggregate, userID string, cascade bool) eventstore.EventPusher {
if cascade {
return project.NewProjectMemberCascadeRemovedEvent(
ctx,
projectAgg,
userID)
} else {
return project.NewProjectMemberRemovedEvent(ctx, projectAgg, userID)
}
}
func (c *Commands) projectMemberWriteModelByID(ctx context.Context, projectID, userID, resourceOwner string) (member *ProjectMemberWriteModel, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()

View File

@ -39,6 +39,11 @@ func (wm *ProjectMemberWriteModel) AppendEvents(events ...eventstore.EventReader
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberRemovedEvent)
case *project.MemberCascadeRemovedEvent:
if e.UserID != wm.MemberWriteModel.UserID {
continue
}
wm.MemberWriteModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}
@ -53,5 +58,6 @@ func (wm *ProjectMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
ResourceOwner(wm.ResourceOwner).
EventTypes(project.MemberAddedType,
project.MemberChangedType,
project.MemberRemovedType)
project.MemberRemovedType,
project.MemberCascadeRemovedType)
}

View File

@ -101,6 +101,8 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
rm.addUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.NewAddProjectGrantMemberUniqueConstraint(e.Aggregate().ID, e.UserID, e.GrantID))
case *project.GrantMemberRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType)
case *project.GrantMemberCascadeRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.GrantID+e.UserID, project.UniqueProjectGrantMemberType)
case *project.RoleAddedEvent:
rm.addUniqueConstraint(e.Aggregate().ID, e.Key, project.NewAddProjectRoleUniqueConstraint(e.Key, e.Aggregate().ID))
case *project.RoleRemovedEvent:
@ -159,14 +161,20 @@ func (rm *UniqueConstraintReadModel) Reduce() error {
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
case *iam.MemberRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *iam.MemberCascadeRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *org.MemberAddedEvent:
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
case *org.MemberRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *org.MemberCascadeRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *project.MemberAddedEvent:
rm.addUniqueConstraint(e.Aggregate().ID, e.UserID, member.NewAddMemberUniqueConstraint(e.Aggregate().ID, e.UserID))
case *project.MemberRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
case *project.MemberCascadeRemovedEvent:
rm.removeUniqueConstraint(e.Aggregate().ID, e.UserID, member.UniqueMember)
}
}
return nil
@ -204,6 +212,7 @@ func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder {
project.GrantRemovedType,
project.GrantMemberAddedType,
project.GrantMemberRemovedType,
project.GrantMemberCascadeRemovedType,
project.RoleAddedType,
project.RoleRemovedType,
user.UserV1AddedType,
@ -222,10 +231,13 @@ func (rm *UniqueConstraintReadModel) Query() *eventstore.SearchQueryBuilder {
usergrant.UserGrantCascadeRemovedType,
iam.MemberAddedEventType,
iam.MemberRemovedEventType,
iam.MemberCascadeRemovedEventType,
org.MemberAddedEventType,
org.MemberRemovedEventType,
org.MemberCascadeRemovedEventType,
project.MemberAddedType,
project.MemberRemovedType,
project.MemberCascadeRemovedType,
)
}

View File

@ -169,7 +169,7 @@ func (c *Commands) UnlockUser(ctx context.Context, userID, resourceOwner string)
return writeModelToObjectDetails(&existingUser.WriteModel), nil
}
func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string, cascadingGrantIDs ...string) (*domain.ObjectDetails, error) {
func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string, cascadingUserMemberships []*domain.UserMembership, cascadingGrantIDs ...string) (*domain.ObjectDetails, error) {
if userID == "" {
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-2M0ds", "Errors.User.UserIDMissing")
}
@ -199,6 +199,14 @@ func (c *Commands) RemoveUser(ctx context.Context, userID, resourceOwner string,
events = append(events, removeEvent)
}
if len(cascadingUserMemberships) > 0 {
membershipEvents, err := c.removeUserMemberships(ctx, cascadingUserMemberships, true)
if err != nil {
return nil, err
}
events = append(events, membershipEvents...)
}
pushedEvents, err := c.eventstore.PushEvents(ctx, events...)
if err != nil {
return nil, err

View File

@ -0,0 +1,36 @@
package command
import (
"context"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/project"
)
func (c *Commands) removeUserMemberships(ctx context.Context, memberships []*domain.UserMembership, cascade bool) (_ []eventstore.EventPusher, err error) {
events := make([]eventstore.EventPusher, 0)
for _, membership := range memberships {
switch membership.MemberType {
case domain.MemberTypeIam:
iamAgg := iam.NewAggregate()
removeEvent := c.removeIAMMember(ctx, &iamAgg.Aggregate, membership.UserID, true)
events = append(events, removeEvent)
case domain.MemberTypeOrganisation:
iamAgg := org.NewAggregate(membership.AggregateID, membership.ResourceOwner)
removeEvent := c.removeOrgMember(ctx, &iamAgg.Aggregate, membership.UserID, true)
events = append(events, removeEvent)
case domain.MemberTypeProject:
projectAgg := project.NewAggregate(membership.AggregateID, membership.ResourceOwner)
removeEvent := c.removeProjectMember(ctx, &projectAgg.Aggregate, membership.UserID, true)
events = append(events, removeEvent)
case domain.MemberTypeProjectGrant:
projectAgg := project.NewAggregate(membership.AggregateID, membership.ResourceOwner)
removeEvent := c.removeProjectGrantMember(ctx, &projectAgg.Aggregate, membership.UserID, membership.ObjectID, true)
events = append(events, removeEvent)
}
}
return events, nil
}

View File

@ -14,6 +14,9 @@ import (
"github.com/caos/zitadel/internal/eventstore/repository"
"github.com/caos/zitadel/internal/id"
"github.com/caos/zitadel/internal/repository/iam"
"github.com/caos/zitadel/internal/repository/member"
"github.com/caos/zitadel/internal/repository/org"
"github.com/caos/zitadel/internal/repository/project"
"github.com/caos/zitadel/internal/repository/user"
)
@ -914,9 +917,11 @@ func TestCommandSide_RemoveUser(t *testing.T) {
}
type (
args struct {
ctx context.Context
orgID string
userID string
ctx context.Context
orgID string
userID string
cascadeUserMemberships []*domain.UserMembership
cascadeUserGrants []string
}
)
type res struct {
@ -1051,13 +1056,124 @@ func TestCommandSide_RemoveUser(t *testing.T) {
},
},
},
{
name: "remove user with user memberships, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
user.NewHumanAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"username",
"firstname",
"lastname",
"nickname",
"displayname",
language.German,
domain.GenderUnspecified,
"email@test.ch",
true,
),
),
),
expectFilter(),
expectFilter(
eventFromEventPusher(
iam.NewOrgIAMPolicyAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
true,
),
),
),
expectPush(
[]*repository.Event{
eventFromEventPusher(
user.NewUserRemovedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"username",
true,
),
),
eventFromEventPusher(
iam.NewMemberCascadeRemovedEvent(context.Background(),
&iam.NewAggregate().Aggregate,
"user1",
),
),
eventFromEventPusher(
org.NewMemberCascadeRemovedEvent(context.Background(),
&org.NewAggregate("org1", "org1").Aggregate,
"user1",
),
),
eventFromEventPusher(
project.NewProjectMemberCascadeRemovedEvent(context.Background(),
&project.NewAggregate("project1", "org1").Aggregate,
"user1",
),
),
eventFromEventPusher(
project.NewProjectGrantMemberCascadeRemovedEvent(context.Background(),
&project.NewAggregate("project1", "org1").Aggregate,
"user1",
"grant1",
),
),
},
uniqueConstraintsFromEventConstraint(user.NewRemoveUsernameUniqueConstraint("username", "org1", true)),
uniqueConstraintsFromEventConstraint(member.NewRemoveMemberUniqueConstraint(domain.IAMID, "user1")),
uniqueConstraintsFromEventConstraint(member.NewRemoveMemberUniqueConstraint("org1", "user1")),
uniqueConstraintsFromEventConstraint(member.NewRemoveMemberUniqueConstraint("project1", "user1")),
uniqueConstraintsFromEventConstraint(project.NewRemoveProjectGrantMemberUniqueConstraint("project1", "user1", "grant1")),
),
),
},
args: args{
ctx: context.Background(),
orgID: "org1",
userID: "user1",
cascadeUserMemberships: []*domain.UserMembership{
{
MemberType: domain.MemberTypeIam,
UserID: "user1",
AggregateID: "IAM",
ResourceOwner: "org1",
},
{
MemberType: domain.MemberTypeOrganisation,
UserID: "user1",
ResourceOwner: "org1",
AggregateID: "org1",
},
{
MemberType: domain.MemberTypeProject,
UserID: "user1",
ResourceOwner: "org1",
AggregateID: "project1",
},
{
MemberType: domain.MemberTypeProjectGrant,
UserID: "user1",
ResourceOwner: "org1",
AggregateID: "project1",
ObjectID: "grant1",
},
},
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
}
got, err := r.RemoveUser(tt.args.ctx, tt.args.userID, tt.args.orgID)
got, err := r.RemoveUser(tt.args.ctx, tt.args.userID, tt.args.orgID, tt.args.cascadeUserMemberships, tt.args.cascadeUserGrants...)
if tt.res.err == nil {
assert.NoError(t, err)
}

View File

@ -0,0 +1,29 @@
package domain
import "time"
type UserMembership struct {
UserID string
MemberType MemberType
AggregateID string
//ObjectID differs from aggregate id if obejct is sub of an aggregate
ObjectID string
Roles []string
DisplayName string
CreationDate time.Time
ChangeDate time.Time
ResourceOwner string
ResourceOwnerName string
Sequence uint64
}
type MemberType int32
const (
MemberTypeUnspecified MemberType = iota
MemberTypeOrganisation
MemberTypeProject
MemberTypeProjectGrant
MemberTypeIam
)

View File

@ -159,6 +159,8 @@ func (i *IAM) AppendEvent(event *es_models.Event) (err error) {
err = i.appendChangeMemberEvent(event)
case IAMMemberRemoved:
err = i.appendRemoveMemberEvent(event)
case IAMMemberCascadeRemoved:
err = i.appendRemoveMemberEvent(event)
case IDPConfigAdded:
return i.appendAddIDPConfigEvent(event)
case IDPConfigChanged:

View File

@ -5,13 +5,14 @@ import "github.com/caos/zitadel/internal/eventstore/v1/models"
const (
IAMAggregate models.AggregateType = "iam"
IAMSetupStarted models.EventType = "iam.setup.started"
IAMSetupDone models.EventType = "iam.setup.done"
GlobalOrgSet models.EventType = "iam.global.org.set"
IAMProjectSet models.EventType = "iam.project.iam.set"
IAMMemberAdded models.EventType = "iam.member.added"
IAMMemberChanged models.EventType = "iam.member.changed"
IAMMemberRemoved models.EventType = "iam.member.removed"
IAMSetupStarted models.EventType = "iam.setup.started"
IAMSetupDone models.EventType = "iam.setup.done"
GlobalOrgSet models.EventType = "iam.global.org.set"
IAMProjectSet models.EventType = "iam.project.iam.set"
IAMMemberAdded models.EventType = "iam.member.added"
IAMMemberChanged models.EventType = "iam.member.changed"
IAMMemberRemoved models.EventType = "iam.member.removed"
IAMMemberCascadeRemoved models.EventType = "iam.member.cascade.removed"
IDPConfigAdded models.EventType = "iam.idp.config.added"
IDPConfigChanged models.EventType = "iam.idp.config.changed"

View File

@ -298,6 +298,14 @@ func (repo *UserRepo) SearchUserMemberships(ctx context.Context, request *usr_mo
return result, nil
}
func (repo *UserRepo) UserMembershipsByUserID(ctx context.Context, userID string) ([]*usr_model.UserMembershipView, error) {
memberships, err := repo.View.UserMembershipsByUserID(userID)
if err != nil {
return nil, err
}
return model.UserMembershipsToModel(memberships), nil
}
func (r *UserRepo) getUserChanges(ctx context.Context, userID string, lastSequence uint64, limit uint64, sortAscending bool, retention time.Duration) (*usr_model.UserChanges, error) {
query := usr_view.ChangesQuery(userID, lastSequence, limit, sortAscending, retention)

View File

@ -109,7 +109,8 @@ func (m *OrgMember) processOrgMember(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case model.OrgMemberRemoved:
case model.OrgMemberRemoved,
model.OrgMemberCascadeRemoved:
err = member.SetData(event)
if err != nil {
return err

View File

@ -111,7 +111,8 @@ func (p *ProjectGrantMember) processProjectGrantMember(event *es_models.Event) (
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
case proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
err = member.SetData(event)
if err != nil {
return err
@ -154,9 +155,12 @@ func (p *ProjectGrantMember) processUser(event *es_models.Event) (err error) {
p.fillUserData(member, user)
}
return p.view.PutProjectGrantMembers(members, event)
case usr_es_model.UserRemoved:
p.view.DeleteProjectGrantMembersByUserID(event.AggregateID)
default:
return p.view.ProcessedProjectGrantMemberSequence(event)
}
return nil
}
func (p *ProjectGrantMember) fillData(member *view_model.ProjectGrantMemberView) (err error) {

View File

@ -111,7 +111,7 @@ func (p *ProjectMember) processProjectMember(event *es_models.Event) (err error)
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
case proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberCascadeRemoved:
err = member.SetData(event)
if err != nil {
return err
@ -150,6 +150,8 @@ func (p *ProjectMember) processUser(event *es_models.Event) (err error) {
p.fillUserData(member, user)
}
return p.view.PutProjectMembers(members, event)
case usr_es_model.UserRemoved:
p.view.DeleteProjectMembersByUserID(event.AggregateID)
default:
return p.view.ProcessedProjectMemberSequence(event)
}

View File

@ -107,7 +107,8 @@ func (m *UserMembership) processIAM(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved:
case iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event)
default:
return m.view.ProcessedUserMembershipSequence(event)
@ -137,7 +138,7 @@ func (m *UserMembership) processOrg(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved:
case org_es_model.OrgMemberRemoved, org_es_model.OrgMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event)
case org_es_model.OrgChanged:
return m.updateOrgDisplayName(event)
@ -190,7 +191,7 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved:
case proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event)
case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
@ -198,7 +199,8 @@ func (m *UserMembership) processProject(event *es_models.Event) (err error) {
return err
}
err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved:
case proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event)
case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event)

View File

@ -57,6 +57,10 @@ func (v *View) DeleteProjectGrantMembersByProjectID(projectID string) error {
return view.DeleteProjectGrantMembersByProjectID(v.Db, projectGrantMemberTable, projectID)
}
func (v *View) DeleteProjectGrantMembersByUserID(userID string) error {
return view.DeleteProjectGrantMembersByUserID(v.Db, projectGrantMemberTable, userID)
}
func (v *View) GetLatestProjectGrantMemberSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(projectGrantMemberTable)
}

View File

@ -57,6 +57,10 @@ func (v *View) DeleteProjectMembersByProjectID(projectID string) error {
return view.DeleteProjectMembersByProjectID(v.Db, projectMemberTable, projectID)
}
func (v *View) DeleteProjectMembersByUserID(userID string) error {
return view.DeleteProjectMembersByUserID(v.Db, projectMemberTable, userID)
}
func (v *View) GetLatestProjectMemberSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(projectMemberTable)
}

View File

@ -21,6 +21,10 @@ func (v *View) UserMembershipsByAggregateID(aggregateID string) ([]*model.UserMe
return view.UserMembershipsByAggregateID(v.Db, userMembershipTable, aggregateID)
}
func (v *View) UserMembershipsByUserID(userID string) ([]*model.UserMembershipView, error) {
return view.UserMembershipsByUserID(v.Db, userMembershipTable, userID)
}
func (v *View) SearchUserMemberships(request *usr_model.UserMembershipSearchRequest) ([]*model.UserMembershipView, uint64, error) {
return view.SearchUserMemberships(v.Db, userMembershipTable, request)
}

View File

@ -38,4 +38,5 @@ type UserRepository interface {
AddressByID(ctx context.Context, userID string) (*model.Address, error)
SearchUserMemberships(ctx context.Context, request *model.UserMembershipSearchRequest) (*model.UserMembershipSearchResponse, error)
UserMembershipsByUserID(ctx context.Context, userID string) ([]*model.UserMembershipView, error)
}

View File

@ -157,7 +157,8 @@ func (o *Org) AppendEvent(event *es_models.Event) (err error) {
member.CreationDate = existingMember.CreationDate
o.setMember(member)
case OrgMemberRemoved:
case OrgMemberRemoved,
OrgMemberCascadeRemoved:
member, err := OrgMemberFromEvent(nil, event)
if err != nil {
return err

View File

@ -25,9 +25,10 @@ const (
OrgDomainReserved models.EventType = "org.domain.reserved"
OrgDomainReleased models.EventType = "org.domain.released"
OrgMemberAdded models.EventType = "org.member.added"
OrgMemberChanged models.EventType = "org.member.changed"
OrgMemberRemoved models.EventType = "org.member.removed"
OrgMemberAdded models.EventType = "org.member.added"
OrgMemberChanged models.EventType = "org.member.changed"
OrgMemberRemoved models.EventType = "org.member.removed"
OrgMemberCascadeRemoved models.EventType = "org.member.cascade.removed"
OrgIAMPolicyAdded models.EventType = "org.iam.policy.added"
OrgIAMPolicyChanged models.EventType = "org.iam.policy.changed"

View File

@ -119,6 +119,8 @@ func (p *Project) AppendEvent(event *es_models.Event) error {
return p.appendChangeMemberEvent(event)
case ProjectMemberRemoved:
return p.appendRemoveMemberEvent(event)
case ProjectMemberCascadeRemoved:
return p.appendRemoveMemberEvent(event)
case ProjectRoleAdded:
return p.appendAddRoleEvent(event)
case ProjectRoleChanged:
@ -163,6 +165,8 @@ func (p *Project) AppendEvent(event *es_models.Event) error {
return p.appendChangeGrantMemberEvent(event)
case ProjectGrantMemberRemoved:
return p.appendRemoveGrantMemberEvent(event)
case ProjectGrantMemberCascadeRemoved:
return p.appendRemoveGrantMemberEvent(event)
}
return nil
}

View File

@ -11,9 +11,10 @@ const (
ProjectReactivated models.EventType = "project.reactivated"
ProjectRemoved models.EventType = "project.removed"
ProjectMemberAdded models.EventType = "project.member.added"
ProjectMemberChanged models.EventType = "project.member.changed"
ProjectMemberRemoved models.EventType = "project.member.removed"
ProjectMemberAdded models.EventType = "project.member.added"
ProjectMemberChanged models.EventType = "project.member.changed"
ProjectMemberRemoved models.EventType = "project.member.removed"
ProjectMemberCascadeRemoved models.EventType = "project.member.cascade.removed"
ProjectRoleAdded models.EventType = "project.role.added"
ProjectRoleChanged models.EventType = "project.role.changed"
@ -26,9 +27,10 @@ const (
ProjectGrantReactivated models.EventType = "project.grant.reactivated"
ProjectGrantCascadeChanged models.EventType = "project.grant.cascade.changed"
ProjectGrantMemberAdded models.EventType = "project.grant.member.added"
ProjectGrantMemberChanged models.EventType = "project.grant.member.changed"
ProjectGrantMemberRemoved models.EventType = "project.grant.member.removed"
ProjectGrantMemberAdded models.EventType = "project.grant.member.added"
ProjectGrantMemberChanged models.EventType = "project.grant.member.changed"
ProjectGrantMemberRemoved models.EventType = "project.grant.member.removed"
ProjectGrantMemberCascadeRemoved models.EventType = "project.grant.member.cascade.removed"
ApplicationAdded models.EventType = "project.application.added"
ApplicationChanged models.EventType = "project.application.changed"

View File

@ -85,3 +85,8 @@ func DeleteProjectGrantMembersByProjectID(db *gorm.DB, table, projectID string)
delete := repository.PrepareDeleteByKey(table, model.ProjectGrantMemberSearchKey(proj_model.ProjectGrantMemberSearchKeyProjectID), projectID)
return delete(db)
}
func DeleteProjectGrantMembersByUserID(db *gorm.DB, table, userID string) error {
delete := repository.PrepareDeleteByKey(table, model.ProjectGrantMemberSearchKey(proj_model.ProjectGrantMemberSearchKeyUserID), userID)
return delete(db)
}

View File

@ -84,3 +84,8 @@ func DeleteProjectMembersByProjectID(db *gorm.DB, table, projectID string) error
delete := repository.PrepareDeleteByKey(table, model.ProjectMemberSearchKey(proj_model.ProjectMemberSearchKeyProjectID), projectID)
return delete(db)
}
func DeleteProjectMembersByUserID(db *gorm.DB, table, userID string) error {
delete := repository.PrepareDeleteByKey(table, model.ProjectMemberSearchKey(proj_model.ProjectMemberSearchKeyUserID), userID)
return delete(db)
}

View File

@ -27,7 +27,8 @@ func (rm *IAMMemberReadModel) AppendEvents(events ...eventstore.EventReader) {
rm.MemberReadModel.AppendEvents(&e.MemberAddedEvent)
case *iam.MemberChangedEvent:
rm.MemberReadModel.AppendEvents(&e.MemberChangedEvent)
case *member.MemberAddedEvent, *member.MemberChangedEvent, *iam.MemberRemovedEvent:
case *member.MemberAddedEvent, *member.MemberChangedEvent,
*iam.MemberRemovedEvent, *iam.MemberCascadeRemovedEvent:
rm.MemberReadModel.AppendEvents(e)
}
}

View File

@ -18,6 +18,8 @@ func (rm *IAMMembersReadModel) AppendEvents(events ...eventstore.EventReader) {
rm.MembersReadModel.AppendEvents(&e.MemberChangedEvent)
case *iam.MemberRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberRemovedEvent)
case *iam.MemberCascadeRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}

View File

@ -18,6 +18,8 @@ func (rm *OrgMembersReadModel) AppendEvents(events ...eventstore.EventReader) {
rm.MembersReadModel.AppendEvents(&e.MemberChangedEvent)
case *org.MemberRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberRemovedEvent)
case *org.MemberCascadeRemovedEvent:
rm.MembersReadModel.AppendEvents(&e.MemberCascadeRemovedEvent)
}
}
}

View File

@ -37,6 +37,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(MemberAddedEventType, MemberAddedEventMapper).
RegisterFilterEventMapper(MemberChangedEventType, MemberChangedEventMapper).
RegisterFilterEventMapper(MemberRemovedEventType, MemberRemovedEventMapper).
RegisterFilterEventMapper(MemberCascadeRemovedEventType, MemberCascadeRemovedEventMapper).
RegisterFilterEventMapper(IDPConfigAddedEventType, IDPConfigAddedEventMapper).
RegisterFilterEventMapper(IDPConfigChangedEventType, IDPConfigChangedEventMapper).
RegisterFilterEventMapper(IDPConfigRemovedEventType, IDPConfigRemovedEventMapper).

View File

@ -9,9 +9,10 @@ import (
)
var (
MemberAddedEventType = iamEventTypePrefix + member.AddedEventType
MemberChangedEventType = iamEventTypePrefix + member.ChangedEventType
MemberRemovedEventType = iamEventTypePrefix + member.RemovedEventType
MemberAddedEventType = iamEventTypePrefix + member.AddedEventType
MemberChangedEventType = iamEventTypePrefix + member.ChangedEventType
MemberRemovedEventType = iamEventTypePrefix + member.RemovedEventType
MemberCascadeRemovedEventType = iamEventTypePrefix + member.CascadeRemovedEventType
)
type MemberAddedEvent struct {
@ -88,7 +89,6 @@ func NewMemberRemovedEvent(
aggregate *eventstore.Aggregate,
userID string,
) *MemberRemovedEvent {
return &MemberRemovedEvent{
MemberRemovedEvent: *member.NewRemovedEvent(
eventstore.NewBaseEventForPush(
@ -109,3 +109,33 @@ func MemberRemovedEventMapper(event *repository.Event) (eventstore.EventReader,
return &MemberRemovedEvent{MemberRemovedEvent: *e.(*member.MemberRemovedEvent)}, nil
}
type MemberCascadeRemovedEvent struct {
member.MemberCascadeRemovedEvent
}
func NewMemberCascadeRemovedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
userID string,
) *MemberCascadeRemovedEvent {
return &MemberCascadeRemovedEvent{
MemberCascadeRemovedEvent: *member.NewCascadeRemovedEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
MemberCascadeRemovedEventType,
),
userID,
),
}
}
func MemberCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e, err := member.CascadeRemovedEventMapper(event)
if err != nil {
return nil, err
}
return &MemberCascadeRemovedEvent{MemberCascadeRemovedEvent: *e.(*member.MemberCascadeRemovedEvent)}, nil
}

View File

@ -9,10 +9,11 @@ import (
)
const (
UniqueMember = "member"
AddedEventType = "member.added"
ChangedEventType = "member.changed"
RemovedEventType = "member.removed"
UniqueMember = "member"
AddedEventType = "member.added"
ChangedEventType = "member.changed"
RemovedEventType = "member.removed"
CascadeRemovedEventType = "member.cascade.removed"
)
func NewAddMemberUniqueConstraint(aggregateID, userID string) *eventstore.EventUniqueConstraint {
@ -142,7 +143,45 @@ func RemovedEventMapper(event *repository.Event) (eventstore.EventReader, error)
err := json.Unmarshal(event.Data, e)
if err != nil {
return nil, errors.ThrowInternal(err, "POLIC-Ep4ip", "unable to unmarshal label policy")
return nil, errors.ThrowInternal(err, "MEMBER-Ep4ip", "unable to unmarshal label policy")
}
return e, nil
}
type MemberCascadeRemovedEvent struct {
eventstore.BaseEvent `json:"-"`
UserID string `json:"userId"`
}
func (e *MemberCascadeRemovedEvent) Data() interface{} {
return e
}
func (e *MemberCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewRemoveMemberUniqueConstraint(e.Aggregate().ID, e.UserID)}
}
func NewCascadeRemovedEvent(
base *eventstore.BaseEvent,
userID string,
) *MemberCascadeRemovedEvent {
return &MemberCascadeRemovedEvent{
BaseEvent: *base,
UserID: userID,
}
}
func CascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &MemberCascadeRemovedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, e)
if err != nil {
return nil, errors.ThrowInternal(err, "MEMBER-3j9sf", "unable to unmarshal label policy")
}
return e, nil

View File

@ -18,6 +18,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(MemberAddedEventType, MemberAddedEventMapper).
RegisterFilterEventMapper(MemberChangedEventType, MemberChangedEventMapper).
RegisterFilterEventMapper(MemberRemovedEventType, MemberRemovedEventMapper).
RegisterFilterEventMapper(MemberCascadeRemovedEventType, MemberCascadeRemovedEventMapper).
RegisterFilterEventMapper(LabelPolicyAddedEventType, LabelPolicyAddedEventMapper).
RegisterFilterEventMapper(LabelPolicyChangedEventType, LabelPolicyChangedEventMapper).
RegisterFilterEventMapper(LabelPolicyActivatedEventType, LabelPolicyActivatedEventMapper).

View File

@ -9,9 +9,10 @@ import (
)
var (
MemberAddedEventType = orgEventTypePrefix + member.AddedEventType
MemberChangedEventType = orgEventTypePrefix + member.ChangedEventType
MemberRemovedEventType = orgEventTypePrefix + member.RemovedEventType
MemberAddedEventType = orgEventTypePrefix + member.AddedEventType
MemberChangedEventType = orgEventTypePrefix + member.ChangedEventType
MemberRemovedEventType = orgEventTypePrefix + member.RemovedEventType
MemberCascadeRemovedEventType = orgEventTypePrefix + member.CascadeRemovedEventType
)
type MemberAddedEvent struct {
@ -88,7 +89,6 @@ func NewMemberRemovedEvent(
aggregate *eventstore.Aggregate,
userID string,
) *MemberRemovedEvent {
return &MemberRemovedEvent{
MemberRemovedEvent: *member.NewRemovedEvent(
eventstore.NewBaseEventForPush(
@ -109,3 +109,33 @@ func MemberRemovedEventMapper(event *repository.Event) (eventstore.EventReader,
return &MemberRemovedEvent{MemberRemovedEvent: *e.(*member.MemberRemovedEvent)}, nil
}
type MemberCascadeRemovedEvent struct {
member.MemberCascadeRemovedEvent
}
func NewMemberCascadeRemovedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
userID string,
) *MemberCascadeRemovedEvent {
return &MemberCascadeRemovedEvent{
MemberCascadeRemovedEvent: *member.NewCascadeRemovedEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
MemberCascadeRemovedEventType,
),
userID,
),
}
}
func MemberCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e, err := member.CascadeRemovedEventMapper(event)
if err != nil {
return nil, err
}
return &MemberCascadeRemovedEvent{MemberCascadeRemovedEvent: *e.(*member.MemberCascadeRemovedEvent)}, nil
}

View File

@ -13,6 +13,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(MemberAddedType, MemberAddedEventMapper).
RegisterFilterEventMapper(MemberChangedType, MemberChangedEventMapper).
RegisterFilterEventMapper(MemberRemovedType, MemberRemovedEventMapper).
RegisterFilterEventMapper(MemberCascadeRemovedType, MemberCascadeRemovedEventMapper).
RegisterFilterEventMapper(RoleAddedType, RoleAddedEventMapper).
RegisterFilterEventMapper(RoleChangedType, RoleChangedEventMapper).
RegisterFilterEventMapper(RoleRemovedType, RoleRemovedEventMapper).
@ -25,6 +26,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
RegisterFilterEventMapper(GrantMemberAddedType, GrantMemberAddedEventMapper).
RegisterFilterEventMapper(GrantMemberChangedType, GrantMemberChangedEventMapper).
RegisterFilterEventMapper(GrantMemberRemovedType, GrantMemberRemovedEventMapper).
RegisterFilterEventMapper(GrantMemberCascadeRemovedType, GrantMemberCascadeRemovedEventMapper).
RegisterFilterEventMapper(ApplicationAddedType, ApplicationAddedEventMapper).
RegisterFilterEventMapper(ApplicationChangedType, ApplicationChangedEventMapper).
RegisterFilterEventMapper(ApplicationRemovedType, ApplicationRemovedEventMapper).

View File

@ -12,10 +12,11 @@ import (
)
var (
UniqueProjectGrantMemberType = "project_grant_member"
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
GrantMemberCascadeRemovedType = grantEventTypePrefix + member.CascadeRemovedEventType
)
func NewAddProjectGrantMemberUniqueConstraint(projectID, userID, grantID string) *eventstore.EventUniqueConstraint {
@ -172,3 +173,48 @@ func GrantMemberRemovedEventMapper(event *repository.Event) (eventstore.EventRea
return e, nil
}
type GrantMemberCascadeRemovedEvent struct {
eventstore.BaseEvent `json:"-"`
UserID string `json:"userId"`
GrantID string `json:"grantId"`
}
func (e *GrantMemberCascadeRemovedEvent) Data() interface{} {
return e
}
func (e *GrantMemberCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
return []*eventstore.EventUniqueConstraint{NewRemoveProjectGrantMemberUniqueConstraint(e.Aggregate().ID, e.UserID, e.GrantID)}
}
func NewProjectGrantMemberCascadeRemovedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
userID,
grantID string,
) *GrantMemberCascadeRemovedEvent {
return &GrantMemberCascadeRemovedEvent{
BaseEvent: *eventstore.NewBaseEventForPush(
ctx,
aggregate,
GrantMemberCascadeRemovedType,
),
UserID: userID,
GrantID: grantID,
}
}
func GrantMemberCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e := &GrantMemberCascadeRemovedEvent{
BaseEvent: *eventstore.BaseEventFromRepo(event),
}
err := json.Unmarshal(event.Data, e)
if err != nil {
return nil, errors.ThrowInternal(err, "PROJECT-3kfs3", "unable to unmarshal label policy")
}
return e, nil
}

View File

@ -9,9 +9,10 @@ import (
)
var (
MemberAddedType = projectEventTypePrefix + member.AddedEventType
MemberChangedType = projectEventTypePrefix + member.ChangedEventType
MemberRemovedType = projectEventTypePrefix + member.RemovedEventType
MemberAddedType = projectEventTypePrefix + member.AddedEventType
MemberChangedType = projectEventTypePrefix + member.ChangedEventType
MemberRemovedType = projectEventTypePrefix + member.RemovedEventType
MemberCascadeRemovedType = projectEventTypePrefix + member.CascadeRemovedEventType
)
type MemberAddedEvent struct {
@ -109,3 +110,34 @@ func MemberRemovedEventMapper(event *repository.Event) (eventstore.EventReader,
return &MemberRemovedEvent{MemberRemovedEvent: *e.(*member.MemberRemovedEvent)}, nil
}
type MemberCascadeRemovedEvent struct {
member.MemberCascadeRemovedEvent
}
func NewProjectMemberCascadeRemovedEvent(
ctx context.Context,
aggregate *eventstore.Aggregate,
userID string,
) *MemberCascadeRemovedEvent {
return &MemberCascadeRemovedEvent{
MemberCascadeRemovedEvent: *member.NewCascadeRemovedEvent(
eventstore.NewBaseEventForPush(
ctx,
aggregate,
MemberCascadeRemovedType,
),
userID,
),
}
}
func MemberCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
e, err := member.CascadeRemovedEventMapper(event)
if err != nil {
return nil, err
}
return &MemberCascadeRemovedEvent{MemberCascadeRemovedEvent: *e.(*member.MemberCascadeRemovedEvent)}, nil
}

View File

@ -547,6 +547,8 @@ EventTypes:
added: Organisationsmitglied hinzugefügt
changed: Organisationsmitglied geändert
removed: Organisationsmitglied entfernt
cascade:
removed: Organisationsmitglied kaskadiert entfernt
iam:
policy:
added: System Richtlinie der Organisation hinzugefügt
@ -626,6 +628,8 @@ EventTypes:
added: Projektmitglied hinzugefügt
changed: Projektmitglied geändert
removed: Projektmitglied entfernt
cascade:
removed: Projektmitglied kaskadiert entfernt
role:
added: Projektrolle hinzugefügt
changed: Projektrolle geändert
@ -642,6 +646,8 @@ EventTypes:
added: Verwaltungszugriffsmitglied hinzugefügt
changed: Verwaltungszugriffsmitglied geändert
removed: Verwaltungszugriffsmitglied entfernt
cascade:
removed: Verwaltungszugriffsmitglied kaskadiert entfernt
application:
added: Applikation hinzugefügt
changed: Applikation geändert
@ -692,6 +698,8 @@ EventTypes:
added: ZITADEL Mitglied hinzugefügt
changed: ZITADEL Mitglied geändert
removed: ZITADEL Mitglied entfernt
cascade:
removed: ZITADEL Mitglied kaskadiert entfernt
idp:
config:
added: IDP Konfiguration hinzugefügt

View File

@ -547,6 +547,8 @@ EventTypes:
added: Organization member added
changed: Organization member changed
removed: Organization member removed
cascade:
removeD: Organization member cascade removed
iam:
policy:
added: System policy added
@ -626,6 +628,8 @@ EventTypes:
added: Project member added
changed: Project member changed
removed: Project member removed
cascade:
removeD: Project member cascade removed
role:
added: Project role added
changed: Project role changed
@ -642,6 +646,8 @@ EventTypes:
added: Management access member added
changed: Management access member changed
removed: Management access member removed
cascade:
removeD: Management access cascade removed
application:
added: Application added
changed: Application changed
@ -692,6 +698,8 @@ EventTypes:
added: ZITADEL member added
changed: ZITADEL member changed
removed: ZITADEL member removed
cascade:
removeD: ZITADEL member cascade removed
idp:
config:
added: IDP configuration added

View File

@ -71,25 +71,29 @@ func (u *UserMembershipView) AppendEvent(event *models.Event) (err error) {
u.setRootData(event, model.MemberTypeIam)
err = u.setIamMemberData(event)
case iam_es_model.IAMMemberChanged,
iam_es_model.IAMMemberRemoved:
iam_es_model.IAMMemberRemoved,
iam_es_model.IAMMemberCascadeRemoved:
err = u.setIamMemberData(event)
case org_es_model.OrgMemberAdded:
u.setRootData(event, model.MemberTypeOrganisation)
err = u.setOrgMemberData(event)
case org_es_model.OrgMemberChanged,
org_es_model.OrgMemberRemoved:
org_es_model.OrgMemberRemoved,
org_es_model.OrgMemberCascadeRemoved:
err = u.setOrgMemberData(event)
case proj_es_model.ProjectMemberAdded:
u.setRootData(event, model.MemberTypeProject)
err = u.setProjectMemberData(event)
case proj_es_model.ProjectMemberChanged,
proj_es_model.ProjectMemberRemoved:
proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectMemberCascadeRemoved:
err = u.setProjectMemberData(event)
case proj_es_model.ProjectGrantMemberAdded:
u.setRootData(event, model.MemberTypeProjectGrant)
err = u.setProjectGrantMemberData(event)
case proj_es_model.ProjectGrantMemberChanged,
proj_es_model.ProjectGrantMemberRemoved:
proj_es_model.ProjectGrantMemberRemoved,
proj_es_model.ProjectGrantMemberCascadeRemoved:
err = u.setProjectGrantMemberData(event)
}
return err

View File

@ -35,6 +35,16 @@ func UserMembershipsByAggregateID(db *gorm.DB, table, aggregateID string) ([]*mo
return memberships, err
}
func UserMembershipsByUserID(db *gorm.DB, table, userID string) ([]*model.UserMembershipView, error) {
memberships := make([]*model.UserMembershipView, 0)
aggregateIDQuery := &usr_model.UserMembershipSearchQuery{Key: usr_model.UserMembershipSearchKeyUserID, Value: userID, Method: domain.SearchMethodEquals}
query := repository.PrepareSearchQuery(table, model.UserMembershipSearchRequest{
Queries: []*usr_model.UserMembershipSearchQuery{aggregateIDQuery},
})
_, err := query(db, &memberships)
return memberships, err
}
func UserMembershipsByResourceOwner(db *gorm.DB, table, resourceOwner string) ([]*model.UserMembershipView, error) {
memberships := make([]*model.UserMembershipView, 0)
aggregateIDQuery := &usr_model.UserMembershipSearchQuery{Key: usr_model.UserMembershipSearchKeyResourceOwner, Value: resourceOwner, Method: domain.SearchMethodEquals}