diff --git a/internal/eventstore/v2/aggregate.go b/internal/eventstore/v2/aggregate.go index 69f2531de..ed3d833a4 100644 --- a/internal/eventstore/v2/aggregate.go +++ b/internal/eventstore/v2/aggregate.go @@ -1,34 +1,65 @@ package eventstore -func NewAggregate(id string) *Aggregate { +func NewAggregate( + id string, + typ AggregateType, + resourceOwner string, + version Version, + previousSequence uint64, +) *Aggregate { return &Aggregate{ - ID: id, - Events: []EventPusher{}, + id: id, + typ: typ, + resourceOwner: resourceOwner, + version: version, + previousSequence: previousSequence, + events: []EventPusher{}, } } +//Aggregate is the basic implementation of aggregater type Aggregate struct { - PreviousSequence uint64 `json:"-"` - ID string `json:"-"` - Events []EventPusher `json:"-"` + id string `json:"-"` + typ AggregateType `json:"-"` + events []EventPusher `json:"-"` + resourceOwner string `json:"-"` + version Version `json:"-"` + previousSequence uint64 `json:"-"` } -//AppendEvents adds all the events to the aggregate. -// The function doesn't compute the new state of the aggregate -func (a *Aggregate) AppendEvents(events ...EventPusher) *Aggregate { - a.Events = append(a.Events, events...) +//PushEvents adds all the events to the aggregate. +// The added events will be pushed to eventstore +func (a *Aggregate) PushEvents(events ...EventPusher) *Aggregate { + a.events = append(a.events, events...) return a } -//Reduce must be the last step in the reduce function of the extension -func (a *Aggregate) Reduce() error { - if len(a.Events) == 0 { - return nil - } - - a.PreviousSequence = a.Events[len(a.Events)-1].Sequence() - // all events processed and not needed anymore - a.Events = nil - a.Events = []Event{} - return nil +//ID implements aggregater +func (a *Aggregate) ID() string { + return a.id +} + +//Type implements aggregater +func (a *Aggregate) Type() AggregateType { + return a.typ +} + +//Events implements aggregater +func (a *Aggregate) Events() []EventPusher { + return a.events +} + +//ResourceOwner implements aggregater +func (a *Aggregate) ResourceOwner() string { + return a.resourceOwner +} + +//Version implements aggregater +func (a *Aggregate) Version() Version { + return a.version +} + +//PreviousSequence implements aggregater +func (a *Aggregate) PreviousSequence() uint64 { + return a.previousSequence } diff --git a/internal/eventstore/v2/eventstore_test.go b/internal/eventstore/v2/eventstore_test.go index 9e752f043..eec43fb8c 100644 --- a/internal/eventstore/v2/eventstore_test.go +++ b/internal/eventstore/v2/eventstore_test.go @@ -58,7 +58,6 @@ func newTestEvent(description string, data func() interface{}, checkPrevious boo shouldCheckPrevious: checkPrevious, BaseEvent: *NewBaseEventForPush( authz.NewMockContext("resourceOwner", "editorUser"), - "editorService", "test.event", ), } diff --git a/internal/eventstore/v2/example_test.go b/internal/eventstore/v2/example_test.go index 4d6be8982..9e7ddde6f 100644 --- a/internal/eventstore/v2/example_test.go +++ b/internal/eventstore/v2/example_test.go @@ -23,43 +23,20 @@ type UserAggregate struct { FirstName string } -func (a *UserAggregate) ID() string { - return a.Aggregate.ID -} -func (a *UserAggregate) Type() eventstore.AggregateType { - return "test.user" -} -func (a *UserAggregate) Events() []eventstore.EventPusher { - events := make([]eventstore.EventPusher, len(a.Aggregate.Events)) - for i, event := range a.Aggregate.Events { - events[i] = event - } - - return events -} -func (a *UserAggregate) ResourceOwner() string { - return "caos" -} -func (a *UserAggregate) Version() eventstore.Version { - return "v1" -} -func (a *UserAggregate) PreviousSequence() uint64 { - return a.Aggregate.PreviousSequence -} - func NewUserAggregate(id string) *UserAggregate { return &UserAggregate{ - Aggregate: *eventstore.NewAggregate(id), + Aggregate: *eventstore.NewAggregate( + id, + "test.user", + "caos", + "v1", + 0, + ), } } -func (rm *UserAggregate) AppendEvents(events ...eventstore.EventReader) *UserAggregate { - rm.Aggregate.AppendEvents(events...) - return rm -} - func (rm *UserAggregate) Reduce() error { - for _, event := range rm.Aggregate.Events { + for _, event := range rm.Aggregate.Events() { switch e := event.(type) { case *UserAddedEvent: rm.FirstName = e.FirstName @@ -67,7 +44,7 @@ func (rm *UserAggregate) Reduce() error { rm.FirstName = e.FirstName } } - return rm.Aggregate.Reduce() + return nil } // ------------------------------------------------------------ @@ -228,12 +205,13 @@ func (e *UserDeletedEvent) Data() interface{} { type UsersReadModel struct { eventstore.ReadModel + Users []*UserReadModel } func NewUsersReadModel() *UsersReadModel { return &UsersReadModel{ - ReadModel: *eventstore.NewReadModel(""), + ReadModel: *eventstore.NewReadModel(), Users: []*UserReadModel{}, } } @@ -284,7 +262,7 @@ func (rm *UsersReadModel) Reduce() error { func (rm *UsersReadModel) userByID(id string) (idx int, user *UserReadModel) { for idx, user = range rm.Users { - if user.ReadModel.ID == id { + if user.ID == id { return idx, user } } @@ -298,6 +276,8 @@ func (rm *UsersReadModel) userByID(id string) (idx int, user *UserReadModel) { type UserReadModel struct { eventstore.ReadModel + + ID string FirstName string pwCheckCount int lastPasswordCheck time.Time @@ -305,7 +285,8 @@ type UserReadModel struct { func NewUserReadModel(id string) *UserReadModel { return &UserReadModel{ - ReadModel: *eventstore.NewReadModel(id), + ReadModel: *eventstore.NewReadModel(), + ID: id, } } @@ -342,9 +323,9 @@ func TestUserReadModel(t *testing.T) { RegisterFilterEventMapper(UserDeletedMapper()) events, err := es.PushAggregates(context.Background(), - NewUserAggregate("1").AppendEvents(NewUserAddedEvent("hodor")), - NewUserAggregate("2").AppendEvents(NewUserAddedEvent("hodor"), NewUserPasswordCheckedEvent(), NewUserPasswordCheckedEvent(), NewUserFirstNameChangedEvent("ueli")), - NewUserAggregate("2").AppendEvents(NewUserDeletedEvent()), + NewUserAggregate("1").PushEvents(NewUserAddedEvent("hodor")), + NewUserAggregate("2").PushEvents(NewUserAddedEvent("hodor"), NewUserPasswordCheckedEvent(), NewUserPasswordCheckedEvent(), NewUserFirstNameChangedEvent("ueli")), + NewUserAggregate("2").PushEvents(NewUserDeletedEvent()), ) if err != nil { t.Errorf("unexpected error on push aggregates: %v", err) diff --git a/internal/eventstore/v2/read_model.go b/internal/eventstore/v2/read_model.go index d7fffbb6b..2f98063d1 100644 --- a/internal/eventstore/v2/read_model.go +++ b/internal/eventstore/v2/read_model.go @@ -2,21 +2,21 @@ package eventstore import "time" -func NewReadModel( /*id string*/ ) *ReadModel { +func NewReadModel() *ReadModel { return &ReadModel{ - // ID: id, Events: []EventReader{}, } } //ReadModel is the minimum representation of a View model. +// It implements a basic reducer // it might be saved in a database or in memory type ReadModel struct { - ProcessedSequence uint64 `json:"-"` - // ID string `json:"-"` - CreationDate time.Time `json:"-"` - ChangeDate time.Time `json:"-"` - Events []EventReader `json:"-"` + AggregateID string `json:"-"` + ProcessedSequence uint64 `json:"-"` + CreationDate time.Time `json:"-"` + ChangeDate time.Time `json:"-"` + Events []EventReader `json:"-"` } //AppendEvents adds all the events to the read model. @@ -26,12 +26,17 @@ func (rm *ReadModel) AppendEvents(events ...EventReader) *ReadModel { return rm } -//Reduce must be the last step in the reduce function of the extension +//Reduce is the basic implementaion of reducer +// If this function is extended the extending function should be the last step func (rm *ReadModel) Reduce() error { if len(rm.Events) == 0 { return nil } + if rm.AggregateID == "" { + rm.AggregateID = rm.Events[0].AggregateID() + } + if rm.CreationDate.IsZero() { rm.CreationDate = rm.Events[0].CreationDate() } diff --git a/internal/v2/repository/iam/member.go b/internal/v2/repository/iam/member.go new file mode 100644 index 000000000..0a1cabe0a --- /dev/null +++ b/internal/v2/repository/iam/member.go @@ -0,0 +1,114 @@ +package iam + +import ( + "context" + + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/member" + "github.com/caos/zitadel/internal/v2/repository/members" +) + +const ( + iamEventTypePrefix = eventstore.EventType("iam.") +) + +var ( + MemberAddedEventType = iamEventTypePrefix + member.AddedEventType + MemberChangedEventType = iamEventTypePrefix + member.ChangedEventType + MemberRemovedEventType = iamEventTypePrefix + member.RemovedEventType +) + +type MembersReadModel struct { + members.ReadModel +} + +func (rm *MembersReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { + for _, event := range events { + switch e := event.(type) { + case *MemberAddedEvent: + rm.ReadModel.AppendEvents(&e.AddedEvent) + case *MemberChangedEvent: + rm.ReadModel.AppendEvents(&e.ChangedEvent) + case *MemberRemovedEvent: + rm.ReadModel.AppendEvents(&e.RemovedEvent) + } + } + return nil +} + +type MemberReadModel member.ReadModel + +func (rm *MemberReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { + for _, event := range events { + switch e := event.(type) { + case *MemberAddedEvent: + rm.ReadModel.AppendEvents(&e.AddedEvent) + case *MemberChangedEvent: + rm.ReadModel.AppendEvents(&e.ChangedEvent) + } + } + return nil +} + +type MemberAddedEvent struct { + member.AddedEvent +} + +type MemberChangedEvent struct { + member.ChangedEvent +} +type MemberRemovedEvent struct { + member.RemovedEvent +} + +func NewMemberAddedEvent( + ctx context.Context, + userID string, + roles ...string, +) *MemberAddedEvent { + + return &MemberAddedEvent{ + AddedEvent: *member.NewMemberAddedEvent( + eventstore.NewBaseEventForPush( + ctx, + MemberAddedEventType, + ), + userID, + roles..., + ), + } +} + +func NewMemberChangedEvent( + ctx context.Context, + userID string, + roles ...string, +) *MemberChangedEvent { + + return &MemberChangedEvent{ + ChangedEvent: *member.NewMemberChangedEvent( + eventstore.NewBaseEventForPush( + ctx, + MemberChangedEventType, + ), + userID, + roles..., + ), + } +} + +func NewMemberRemovedEvent( + ctx context.Context, + userID string, +) *MemberRemovedEvent { + + return &MemberRemovedEvent{ + RemovedEvent: *member.NewMemberRemovedEvent( + eventstore.NewBaseEventForPush( + ctx, + MemberRemovedEventType, + ), + userID, + ), + } +} diff --git a/internal/v2/repository/iam/read_model.go b/internal/v2/repository/iam/read_model.go index c95b42cac..ef1f6a24e 100644 --- a/internal/v2/repository/iam/read_model.go +++ b/internal/v2/repository/iam/read_model.go @@ -3,6 +3,7 @@ package iam import ( "github.com/caos/zitadel/internal/eventstore/v2" "github.com/caos/zitadel/internal/v2/repository/member" + "github.com/caos/zitadel/internal/v2/repository/policy" ) type ReadModel struct { @@ -11,20 +12,38 @@ type ReadModel struct { SetUpStarted Step SetUpDone Step - Members member.MembersReadModel + Members MembersReadModel GlobalOrgID string ProjectID string + + DefaultLoginPolicy policy.LoginPolicyReadModel + DefaultLabelPolicy policy.LabelPolicyReadModel + DefaultOrgIAMPolicy policy.OrgIAMPolicyReadModel + DefaultPasswordComplexityPolicy policy.PasswordComplexityPolicyReadModel + DefaultPasswordAgePolicy policy.PasswordAgePolicyReadModel + DefaultPasswordLockoutPolicy policy.PasswordLockoutPolicyReadModel } func (rm *ReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { rm.ReadModel.AppendEvents(events...) for _, event := range events { switch event.(type) { - case *member.MemberAddedEvent, *member.MemberChangedEvent, *member.MemberRemovedEvent: - err = rm.Members.AppendEvents(events...) + case *member.AddedEvent, *member.ChangedEvent, *member.RemovedEvent: + rm.Members.AppendEvents(event) + case *policy.LabelPolicyAddedEvent, *policy.LabelPolicyChangedEvent: + rm.DefaultLabelPolicy.AppendEvents(event) + case *policy.LoginPolicyAddedEvent, *policy.LoginPolicyChangedEvent: + rm.DefaultLoginPolicy.AppendEvents(event) + case *policy.OrgIAMPolicyAddedEvent: + rm.DefaultOrgIAMPolicy.AppendEvents(event) + case *policy.PasswordComplexityPolicyAddedEvent, *policy.PasswordComplexityPolicyChangedEvent: + rm.DefaultPasswordComplexityPolicy.AppendEvents(event) + case *policy.PasswordAgePolicyAddedEvent, *policy.PasswordAgePolicyChangedEvent: + rm.DefaultPasswordAgePolicy.AppendEvents(event) + case *policy.PasswordLockoutPolicyAddedEvent, *policy.PasswordLockoutPolicyChangedEvent: + rm.DefaultPasswordLockoutPolicy.AppendEvents(event) } - } return err } @@ -44,9 +63,21 @@ func (rm *ReadModel) Reduce() (err error) { } } } - err = rm.Members.Reduce() - if err != nil { - return err + for _, reduce := range []func() error{ + rm.Members.Reduce, + rm.Members.Reduce, + rm.DefaultLoginPolicy.Reduce, + rm.DefaultLabelPolicy.Reduce, + rm.DefaultOrgIAMPolicy.Reduce, + rm.DefaultPasswordComplexityPolicy.Reduce, + rm.DefaultPasswordAgePolicy.Reduce, + rm.DefaultPasswordLockoutPolicy.Reduce, + rm.ReadModel.Reduce, + } { + if err = reduce(); err != nil { + return err + } } - return rm.ReadModel.Reduce() + + return nil } diff --git a/internal/v2/repository/member/event_added.go b/internal/v2/repository/member/event_added.go index 8feeadbc8..6e29c7743 100644 --- a/internal/v2/repository/member/event_added.go +++ b/internal/v2/repository/member/event_added.go @@ -1,39 +1,37 @@ package member import ( - "context" - "github.com/caos/zitadel/internal/eventstore/v2" ) -type MemberAddedEvent struct { +const ( + AddedEventType = "member.added" +) + +type AddedEvent struct { eventstore.BaseEvent `json:"-"` Roles []string `json:"roles"` UserID string `json:"userId"` } -func (e *MemberAddedEvent) CheckPrevious() bool { +func (e *AddedEvent) CheckPrevious() bool { return true } -func (e *MemberAddedEvent) Data() interface{} { +func (e *AddedEvent) Data() interface{} { return e } func NewMemberAddedEvent( - ctx context.Context, - eventType eventstore.EventType, + base *eventstore.BaseEvent, userID string, roles ...string, -) *MemberAddedEvent { +) *AddedEvent { - return &MemberAddedEvent{ - BaseEvent: *eventstore.NewBaseEventForPush( - ctx, - eventType, - ), - Roles: roles, - UserID: userID, + return &AddedEvent{ + BaseEvent: *base, + Roles: roles, + UserID: userID, } } diff --git a/internal/v2/repository/member/event_changed.go b/internal/v2/repository/member/event_changed.go index d081bdcd9..2c03e0fa0 100644 --- a/internal/v2/repository/member/event_changed.go +++ b/internal/v2/repository/member/event_changed.go @@ -1,39 +1,37 @@ package member import ( - "context" - "github.com/caos/zitadel/internal/eventstore/v2" ) -type MemberChangedEvent struct { +const ( + ChangedEventType = "member.changed" +) + +type ChangedEvent struct { eventstore.BaseEvent `json:"-"` Roles []string `json:"roles"` UserID string `json:"userId"` } -func (e *MemberChangedEvent) CheckPrevious() bool { +func (e *ChangedEvent) CheckPrevious() bool { return true } -func (e *MemberChangedEvent) Data() interface{} { +func (e *ChangedEvent) Data() interface{} { return e } func NewMemberChangedEvent( - ctx context.Context, - eventType eventstore.EventType, + base *eventstore.BaseEvent, userID string, roles ...string, -) *MemberChangedEvent { +) *ChangedEvent { - return &MemberChangedEvent{ - BaseEvent: *eventstore.NewBaseEventForPush( - ctx, - eventType, - ), - Roles: roles, - UserID: userID, + return &ChangedEvent{ + BaseEvent: *base, + Roles: roles, + UserID: userID, } } diff --git a/internal/v2/repository/member/event_removed.go b/internal/v2/repository/member/event_removed.go index 8627c466b..087ecc326 100644 --- a/internal/v2/repository/member/event_removed.go +++ b/internal/v2/repository/member/event_removed.go @@ -1,36 +1,34 @@ package member import ( - "context" - "github.com/caos/zitadel/internal/eventstore/v2" ) -type MemberRemovedEvent struct { +const ( + RemovedEventType = "member.removed" +) + +type RemovedEvent struct { eventstore.BaseEvent `json:"-"` UserID string `json:"userId"` } -func (e *MemberRemovedEvent) CheckPrevious() bool { +func (e *RemovedEvent) CheckPrevious() bool { return true } -func (e *MemberRemovedEvent) Data() interface{} { +func (e *RemovedEvent) Data() interface{} { return e } func NewMemberRemovedEvent( - ctx context.Context, - eventType eventstore.EventType, + base *eventstore.BaseEvent, userID string, -) *MemberRemovedEvent { +) *RemovedEvent { - return &MemberRemovedEvent{ - BaseEvent: *eventstore.NewBaseEventForPush( - ctx, - eventType, - ), - UserID: userID, + return &RemovedEvent{ + BaseEvent: *base, + UserID: userID, } } diff --git a/internal/v2/repository/member/read_model.go b/internal/v2/repository/member/read_model.go new file mode 100644 index 000000000..5dc315dd9 --- /dev/null +++ b/internal/v2/repository/member/read_model.go @@ -0,0 +1,30 @@ +package member + +import "github.com/caos/zitadel/internal/eventstore/v2" + +type ReadModel struct { + eventstore.ReadModel + + UserID string + Roles []string +} + +func NewMemberReadModel(userID string) *ReadModel { + return &ReadModel{ + ReadModel: *eventstore.NewReadModel(), + } +} + +func (rm *ReadModel) Reduce() error { + for _, event := range rm.Events { + switch e := event.(type) { + case *AddedEvent: + rm.UserID = e.UserID + rm.Roles = e.Roles + case *ChangedEvent: + rm.UserID = e.UserID + rm.Roles = e.Roles + } + } + return rm.ReadModel.Reduce() +} diff --git a/internal/v2/repository/member/read_models.go b/internal/v2/repository/member/read_models.go deleted file mode 100644 index 289d4a528..000000000 --- a/internal/v2/repository/member/read_models.go +++ /dev/null @@ -1,84 +0,0 @@ -package member - -import "github.com/caos/zitadel/internal/eventstore/v2" - -type MemberReadModel struct { - eventstore.ReadModel - - UserID string - Roles []string -} - -func NewMemberReadModel(userID string) *MemberReadModel { - return &MemberReadModel{ - ReadModel: *eventstore.NewReadModel(), - } -} - -func (rm *MemberReadModel) Reduce() error { - for _, event := range rm.Events { - switch e := event.(type) { - case *MemberAddedEvent: - rm.UserID = e.UserID - rm.Roles = e.Roles - case *MemberChangedEvent: - rm.UserID = e.UserID - rm.Roles = e.Roles - } - } - return rm.ReadModel.Reduce() -} - -type MembersReadModel struct { - eventstore.ReadModel - Members []*MemberReadModel -} - -func NewMembersReadModel() *MembersReadModel { - return &MembersReadModel{ - ReadModel: *eventstore.NewReadModel(), - Members: []*MemberReadModel{}, - } -} - -func (rm *MembersReadModel) MemberByUserID(id string) (idx int, member *MemberReadModel) { - for idx, member = range rm.Members { - if member.UserID == id { - return idx, member - } - } - return -1, nil -} - -func (rm *MembersReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { - for _, event := range events { - switch e := event.(type) { - case *MemberAddedEvent: - member := NewMemberReadModel(e.UserID) - rm.Members = append(rm.Members, member) - member.AppendEvents(e) - case *MemberChangedEvent: - _, member := rm.MemberByUserID(e.UserID) - member.AppendEvents(e) - case *MemberRemovedEvent: - idx, _ := rm.MemberByUserID(e.UserID) - if idx < 0 { - return nil - } - copy(rm.Members[idx:], rm.Members[idx+1:]) - rm.Members[len(rm.Members)-1] = nil - rm.Members = rm.Members[:len(rm.Members)-1] - } - } - return err -} - -func (rm *MembersReadModel) Reduce() (err error) { - for _, member := range rm.Members { - err = member.Reduce() - if err != nil { - return err - } - } - return rm.ReadModel.Reduce() -} diff --git a/internal/v2/repository/members/read_models.go b/internal/v2/repository/members/read_models.go new file mode 100644 index 000000000..7dfbddde5 --- /dev/null +++ b/internal/v2/repository/members/read_models.go @@ -0,0 +1,61 @@ +package members + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/member" +) + +type ReadModel struct { + eventstore.ReadModel + + Members []*member.ReadModel +} + +func NewMembersReadModel() *ReadModel { + return &ReadModel{ + ReadModel: *eventstore.NewReadModel(), + Members: []*member.ReadModel{}, + } +} + +func (rm *ReadModel) MemberByUserID(id string) (idx int, member *member.ReadModel) { + for idx, member = range rm.Members { + if member.UserID == id { + return idx, member + } + } + return -1, nil +} + +func (rm *ReadModel) AppendEvents(events ...eventstore.EventReader) (err error) { + for _, event := range events { + switch e := event.(type) { + case *member.MemberAddedEvent: + member := member.NewMemberReadModel(e.UserID) + rm.Members = append(rm.Members, member) + member.AppendEvents(e) + case *member.MemberChangedEvent: + _, member := rm.MemberByUserID(e.UserID) + member.AppendEvents(e) + case *member.MemberRemovedEvent: + idx, _ := rm.MemberByUserID(e.UserID) + if idx < 0 { + return nil + } + copy(rm.Members[idx:], rm.Members[idx+1:]) + rm.Members[len(rm.Members)-1] = nil + rm.Members = rm.Members[:len(rm.Members)-1] + } + } + return err +} + +func (rm *ReadModel) Reduce() (err error) { + for _, member := range rm.Members { + err = member.Reduce() + if err != nil { + return err + } + } + return rm.ReadModel.Reduce() +} diff --git a/internal/v2/repository/policy/label.go b/internal/v2/repository/policy/label.go index 3ab6ed5e6..ace861dfb 100644 --- a/internal/v2/repository/policy/label.go +++ b/internal/v2/repository/policy/label.go @@ -19,6 +19,13 @@ type LabelPolicyAggregate struct { SecondaryColor string } +type LabelPolicyReadModel struct { + eventstore.ReadModel + + PrimaryColor string + SecondaryColor string +} + type LabelPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -53,8 +60,8 @@ func NewLabelPolicyAddedEvent( type LabelPolicyChangedEvent struct { eventstore.BaseEvent `json:"-"` - current *LabelPolicyAggregate - changed *LabelPolicyAggregate + PrimaryColor string `json:"primaryColor,omitempty"` + SecondaryColor string `json:"secondaryColor,omitempty"` } func (e *LabelPolicyChangedEvent) CheckPrevious() bool { @@ -62,15 +69,7 @@ func (e *LabelPolicyChangedEvent) CheckPrevious() bool { } func (e *LabelPolicyChangedEvent) Data() interface{} { - changes := map[string]interface{}{} - if e.current.PrimaryColor != e.changed.PrimaryColor { - changes["primaryColor"] = e.changed.PrimaryColor - } - if e.current.SecondaryColor != e.changed.SecondaryColor { - changes["secondaryColor"] = e.changed.SecondaryColor - } - - return changes + return e } func NewLabelPolicyChangedEvent( @@ -79,14 +78,20 @@ func NewLabelPolicyChangedEvent( changed *LabelPolicyAggregate, ) *LabelPolicyChangedEvent { - return &LabelPolicyChangedEvent{ + e := &LabelPolicyChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, LabelPolicyChangedEventType, ), - current: current, - changed: changed, } + if current.PrimaryColor != changed.PrimaryColor { + e.PrimaryColor = changed.PrimaryColor + } + if current.SecondaryColor != changed.SecondaryColor { + e.SecondaryColor = changed.SecondaryColor + } + + return e } type LabelPolicyRemovedEvent struct { @@ -101,14 +106,11 @@ func (e *LabelPolicyRemovedEvent) Data() interface{} { return nil } -func NewLabelPolicyRemovedEvent( - ctx context.Context, -) *LabelPolicyRemovedEvent { - +func NewLabelPolicyRemovedEvent(ctx context.Context) *LabelPolicyRemovedEvent { return &LabelPolicyRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - LabelPolicyChangedEventType, + LabelPolicyRemovedEventType, ), } } diff --git a/internal/v2/repository/policy/login.go b/internal/v2/repository/policy/login.go index 69cfba49e..d0659ab58 100644 --- a/internal/v2/repository/policy/login.go +++ b/internal/v2/repository/policy/login.go @@ -20,6 +20,14 @@ type LoginPolicyAggregate struct { AllowExternalIDP bool } +type LoginPolicyReadModel struct { + eventstore.ReadModel + + AllowUserNamePassword bool + AllowRegister bool + AllowExternalIDP bool +} + type LoginPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -58,8 +66,9 @@ func NewLoginPolicyAddedEvent( type LoginPolicyChangedEvent struct { eventstore.BaseEvent `json:"-"` - current *LoginPolicyAggregate - changed *LoginPolicyAggregate + AllowUserNamePassword bool `json:"allowUsernamePassword,omitempty"` + AllowRegister bool `json:"allowRegister"` + AllowExternalIDP bool `json:"allowExternalIdp"` } func (e *LoginPolicyChangedEvent) CheckPrevious() bool { @@ -67,18 +76,7 @@ func (e *LoginPolicyChangedEvent) CheckPrevious() bool { } func (e *LoginPolicyChangedEvent) Data() interface{} { - changes := map[string]interface{}{} - if e.current.AllowExternalIDP != e.changed.AllowExternalIDP { - changes["allowUsernamePassword"] = e.changed.AllowExternalIDP - } - if e.current.AllowRegister != e.changed.AllowRegister { - changes["allowRegister"] = e.changed.AllowExternalIDP - } - if e.current.AllowExternalIDP != e.changed.AllowExternalIDP { - changes["allowExternalIdp"] = e.changed.AllowExternalIDP - } - - return changes + return e } func NewLoginPolicyChangedEvent( @@ -87,12 +85,24 @@ func NewLoginPolicyChangedEvent( changed *LoginPolicyAggregate, ) *LoginPolicyChangedEvent { - return &LoginPolicyChangedEvent{ + e := &LoginPolicyChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, LoginPolicyChangedEventType, ), } + + if current.AllowUserNamePassword != changed.AllowUserNamePassword { + e.AllowUserNamePassword = changed.AllowUserNamePassword + } + if current.AllowRegister != changed.AllowRegister { + e.AllowRegister = changed.AllowRegister + } + if current.AllowExternalIDP != changed.AllowExternalIDP { + e.AllowExternalIDP = changed.AllowExternalIDP + } + + return e } type LoginPolicyRemovedEvent struct { diff --git a/internal/v2/repository/policy/org_iam.go b/internal/v2/repository/policy/org_iam.go index f22b49473..9ad035e92 100644 --- a/internal/v2/repository/policy/org_iam.go +++ b/internal/v2/repository/policy/org_iam.go @@ -10,6 +10,18 @@ const ( OrgIAMPolicyAddedEventType = "policy.org.iam.added" ) +type OrgIAMPolicyAggregate struct { + eventstore.Aggregate + + UserLoginMustBeDomain bool +} + +type OrgIAMPolicyReadModel struct { + eventstore.ReadModel + + UserLoginMustBeDomain bool +} + type OrgIAMPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` diff --git a/internal/v2/repository/policy/password_age.go b/internal/v2/repository/policy/password_age.go index 765859e6c..889b9c327 100644 --- a/internal/v2/repository/policy/password_age.go +++ b/internal/v2/repository/policy/password_age.go @@ -19,6 +19,13 @@ type PasswordAgePolicyAggregate struct { MaxAgeDays int } +type PasswordAgePolicyReadModel struct { + eventstore.ReadModel + + ExpireWarnDays int + MaxAgeDays int +} + type PasswordAgePolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -53,8 +60,8 @@ func NewPasswordAgePolicyAddedEvent( type PasswordAgePolicyChangedEvent struct { eventstore.BaseEvent `json:"-"` - current *PasswordAgePolicyAggregate - changed *PasswordAgePolicyAggregate + ExpireWarnDays int `json:"expireWarnDays,omitempty"` + MaxAgeDays int `json:"maxAgeDays,omitempty"` } func (e *PasswordAgePolicyChangedEvent) CheckPrevious() bool { @@ -62,16 +69,7 @@ func (e *PasswordAgePolicyChangedEvent) CheckPrevious() bool { } func (e *PasswordAgePolicyChangedEvent) Data() interface{} { - changes := map[string]interface{}{} - - if e.current.ExpireWarnDays != e.changed.ExpireWarnDays { - changes["expireWarnDays"] = e.changed.ExpireWarnDays - } - if e.current.MaxAgeDays != e.changed.MaxAgeDays { - changes["maxAgeDays"] = e.changed.ExpireWarnDays - } - - return changes + return e } func NewPasswordAgePolicyChangedEvent( @@ -80,14 +78,21 @@ func NewPasswordAgePolicyChangedEvent( changed *PasswordAgePolicyAggregate, ) *PasswordAgePolicyChangedEvent { - return &PasswordAgePolicyChangedEvent{ + e := &PasswordAgePolicyChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, PasswordAgePolicyChangedEventType, ), - current: current, - changed: changed, } + + if current.ExpireWarnDays != changed.ExpireWarnDays { + e.ExpireWarnDays = changed.ExpireWarnDays + } + if current.MaxAgeDays != changed.MaxAgeDays { + e.MaxAgeDays = changed.ExpireWarnDays + } + + return e } type PasswordAgePolicyRemovedEvent struct { @@ -111,7 +116,7 @@ func NewPasswordAgePolicyRemovedEvent( return &PasswordAgePolicyChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - PasswordAgePolicyChangedEventType, + PasswordAgePolicyRemovedEventType, ), } } diff --git a/internal/v2/repository/policy/password_complexity.go b/internal/v2/repository/policy/password_complexity.go index 7635d33d9..f9b4d4555 100644 --- a/internal/v2/repository/policy/password_complexity.go +++ b/internal/v2/repository/policy/password_complexity.go @@ -13,6 +13,18 @@ const ( ) type PasswordComplexityPolicyAggregate struct { + eventstore.Aggregate + + MinLength int + HasLowercase bool + HasUpperCase bool + HasNumber bool + HasSymbol bool +} + +type PasswordComplexityPolicyReadModel struct { + eventstore.ReadModel + MinLength int HasLowercase bool HasUpperCase bool @@ -63,8 +75,11 @@ func NewPasswordComplexityPolicyAddedEvent( type PasswordComplexityPolicyChangedEvent struct { eventstore.BaseEvent `json:"-"` - current *PasswordComplexityPolicyAggregate - changed *PasswordComplexityPolicyAggregate + MinLength int `json:"minLength"` + HasLowercase bool `json:"hasLowercase"` + HasUpperCase bool `json:"hasUppercase"` + HasNumber bool `json:"hasNumber"` + HasSymbol bool `json:"hasSymbol"` } func (e *PasswordComplexityPolicyChangedEvent) CheckPrevious() bool { @@ -72,25 +87,7 @@ func (e *PasswordComplexityPolicyChangedEvent) CheckPrevious() bool { } func (e *PasswordComplexityPolicyChangedEvent) Data() interface{} { - changes := map[string]interface{}{} - - if e.current.MinLength != e.changed.MinLength { - changes["minLength"] = e.changed.MinLength - } - if e.current.HasLowercase != e.changed.HasLowercase { - changes["hasLowercase"] = e.changed.HasLowercase - } - if e.current.HasUpperCase != e.changed.HasUpperCase { - changes["hasUppercase"] = e.changed.HasUpperCase - } - if e.current.HasNumber != e.changed.HasNumber { - changes["hasNumber"] = e.changed.HasNumber - } - if e.current.HasSymbol != e.changed.HasSymbol { - changes["hasSymbol"] = e.changed.HasSymbol - } - - return changes + return e } func NewPasswordComplexityPolicyChangedEvent( @@ -99,14 +96,30 @@ func NewPasswordComplexityPolicyChangedEvent( changed *PasswordComplexityPolicyAggregate, ) *PasswordComplexityPolicyChangedEvent { - return &PasswordComplexityPolicyChangedEvent{ + e := &PasswordComplexityPolicyChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - PasswordComplexityPolicyAddedEventType, + PasswordComplexityPolicyChangedEventType, ), - current: current, - changed: changed, } + + if current.MinLength != changed.MinLength { + e.MinLength = changed.MinLength + } + if current.HasLowercase != changed.HasLowercase { + e.HasLowercase = changed.HasLowercase + } + if current.HasUpperCase != changed.HasUpperCase { + e.HasUpperCase = changed.HasUpperCase + } + if current.HasNumber != changed.HasNumber { + e.HasNumber = changed.HasNumber + } + if current.HasSymbol != changed.HasSymbol { + e.HasSymbol = changed.HasSymbol + } + + return e } type PasswordComplexityPolicyRemovedEvent struct { @@ -128,7 +141,7 @@ func NewPasswordComplexityPolicyRemovedEvent( return &PasswordComplexityPolicyRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - PasswordComplexityPolicyChangedEventType, + PasswordComplexityPolicyRemovedEventType, ), } } diff --git a/internal/v2/repository/policy/password_lockout.go b/internal/v2/repository/policy/password_lockout.go index 1f4c755fb..94f601f1d 100644 --- a/internal/v2/repository/policy/password_lockout.go +++ b/internal/v2/repository/policy/password_lockout.go @@ -7,16 +7,25 @@ import ( ) const ( - PasswordLockoutPolicyAddedEventType = "policy.password.lockout.added" + PasswordLockoutPolicyAddedEventType = "policy.password.lockout.added" + PasswordLockoutPolicyChangedEventType = "policy.password.lockout.changed" + PasswordLockoutPolicyRemovedEventType = "policy.password.lockout.removed" ) -type PasswordLockoutAggregate struct { +type PasswordLockoutPolicyAggregate struct { eventstore.Aggregate MaxAttempts int ShowLockOutFailures bool } +type PasswordLockoutPolicyReadModel struct { + eventstore.ReadModel + + MaxAttempts int + ShowLockOutFailures bool +} + type PasswordLockoutPolicyAddedEvent struct { eventstore.BaseEvent `json:"-"` @@ -41,7 +50,7 @@ func NewPasswordLockoutPolicyAddedEvent( return &PasswordLockoutPolicyAddedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - LabelPolicyAddedEventType, + PasswordLockoutPolicyAddedEventType, ), MaxAttempts: maxAttempts, ShowLockOutFailures: showLockOutFailures, @@ -51,8 +60,8 @@ func NewPasswordLockoutPolicyAddedEvent( type PasswordLockoutPolicyChangedEvent struct { eventstore.BaseEvent `json:"-"` - current *PasswordLockoutAggregate - changed *PasswordLockoutAggregate + MaxAttempts int `json:"maxAttempts,omitempty"` + ShowLockOutFailures bool `json:"showLockOutFailures,omitempty"` } func (e *PasswordLockoutPolicyChangedEvent) CheckPrevious() bool { @@ -60,32 +69,30 @@ func (e *PasswordLockoutPolicyChangedEvent) CheckPrevious() bool { } func (e *PasswordLockoutPolicyChangedEvent) Data() interface{} { - changes := map[string]interface{}{} - - if e.current.MaxAttempts != e.changed.MaxAttempts { - changes["maxAttempts"] = e.changed.MaxAttempts - } - if e.current.ShowLockOutFailures != e.changed.ShowLockOutFailures { - changes["showLockOutFailures"] = e.changed.ShowLockOutFailures - } - - return changes + return e } func NewPasswordLockoutPolicyChangedEvent( ctx context.Context, current, - changed *PasswordLockoutAggregate, + changed *PasswordLockoutPolicyAggregate, ) *PasswordLockoutPolicyChangedEvent { - return &PasswordLockoutPolicyChangedEvent{ + e := &PasswordLockoutPolicyChangedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - LabelPolicyAddedEventType, + PasswordLockoutPolicyChangedEventType, ), - current: current, - changed: changed, } + + if current.MaxAttempts != changed.MaxAttempts { + e.MaxAttempts = changed.MaxAttempts + } + if current.ShowLockOutFailures != changed.ShowLockOutFailures { + e.ShowLockOutFailures = changed.ShowLockOutFailures + } + + return e } type PasswordLockoutPolicyRemovedEvent struct { @@ -107,7 +114,7 @@ func NewPasswordLockoutPolicyRemovedEvent( return &PasswordLockoutPolicyRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( ctx, - LabelPolicyAddedEventType, + PasswordLockoutPolicyRemovedEventType, ), } } diff --git a/internal/v2/view/iam.go b/internal/v2/view/iam.go new file mode 100644 index 000000000..3e7d8560e --- /dev/null +++ b/internal/v2/view/iam.go @@ -0,0 +1,44 @@ +package view + +import ( + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/repository/iam" +) + +type IAM struct { + eventstore.ReadModel + + SetUpStarted iam.Step + SetUpDone iam.Step + + GlobalOrgID string + ProjectID string + + // TODO: how to implement queries? +} + +func (rm *IAM) AppendEvents(events ...eventstore.EventReader) (err error) { + rm.ReadModel.AppendEvents(events...) + return err +} + +//Reduce implements eventstore.ReadModel +// +func (rm *IAM) Reduce() (err error) { + for _, event := range rm.Events { + switch e := event.(type) { + case *iam.ProjectSetEvent: + rm.ProjectID = e.ProjectID + case *iam.GlobalOrgSetEvent: + rm.GlobalOrgID = e.OrgID + case *iam.SetupStepEvent: + if e.Done { + rm.SetUpDone = e.Step + } else { + rm.SetUpStarted = e.Step + } + } + } + return rm.ReadModel.Reduce() + //execute all queries +}